14 |
14 |
# You should have received a copy of the GNU Affero General Public License
|
15 |
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16 |
16 |
|
17 |
17 |
from urllib.parse import urljoin
|
18 |
18 |
|
19 |
19 |
import zeep
|
20 |
20 |
from django.core.cache import cache
|
21 |
21 |
from django.db import models
|
22 |
|
from django.utils.translation import ugettext_lazy as _
|
23 |
22 |
from zeep.helpers import serialize_object
|
24 |
23 |
from zeep.wsse.username import UsernameToken
|
25 |
24 |
|
26 |
25 |
from passerelle.base.models import BaseResource, HTTPResource
|
27 |
26 |
from passerelle.utils.api import endpoint
|
28 |
27 |
from passerelle.utils.jsonresponse import APIError
|
29 |
28 |
|
30 |
29 |
from . import schemas
|
31 |
30 |
|
32 |
31 |
|
33 |
32 |
class ToulouseMaelis(BaseResource, HTTPResource):
|
34 |
33 |
base_wsdl_url = models.CharField(
|
35 |
34 |
max_length=128,
|
36 |
35 |
blank=False,
|
37 |
|
verbose_name=_('Base WSDL URL'),
|
38 |
|
help_text=_('Toulouse Maelis base WSDL URL'),
|
|
36 |
verbose_name='URL de base des WSDL',
|
39 |
37 |
default='https://demo-toulouse.sigec.fr/maelisws-toulouse/services/',
|
40 |
38 |
)
|
41 |
39 |
zeep_wsse_username = models.CharField(
|
42 |
|
max_length=64, blank=True, default='', verbose_name=_('WSSE Username')
|
|
40 |
max_length=64, blank=True, default='', verbose_name='Identifiant utilisateur WSSE'
|
43 |
41 |
)
|
44 |
42 |
zeep_wsse_password = models.CharField(
|
45 |
|
max_length=64, blank=True, default='', verbose_name=_('WSSE Password')
|
|
43 |
max_length=64, blank=True, default='', verbose_name='Mot de passe WSSE'
|
46 |
44 |
)
|
47 |
45 |
|
48 |
|
category = _('Business Process Connectors')
|
49 |
|
_category_ordering = [_('Family'), _('Activities')]
|
|
46 |
category = 'Connecteurs métiers'
|
|
47 |
_category_ordering = ['Famille', 'Activités']
|
50 |
48 |
|
51 |
49 |
class Meta:
|
52 |
|
verbose_name = _('Toulouse Maelis')
|
|
50 |
verbose_name = 'Toulouse Maelis'
|
53 |
51 |
|
54 |
52 |
def get_client(self, wsdl_short_name):
|
55 |
53 |
wsse = UsernameToken(self.zeep_wsse_username, self.zeep_wsse_password)
|
56 |
54 |
wsdl_name = wsdl_short_name + 'Service?wsdl'
|
57 |
55 |
wsdl_url = urljoin(self.base_wsdl_url, wsdl_name)
|
58 |
56 |
return self.soap_client(wsdl_url=wsdl_url, wsse=wsse)
|
59 |
57 |
|
60 |
58 |
def call(self, wsdl_short_name, service, **kwargs):
|
... | ... | |
157 |
155 |
'''send null fields as empty SOAP tag to tell maelis to empty the value'''
|
158 |
156 |
for key, value in dico.items():
|
159 |
157 |
if isinstance(value, dict):
|
160 |
158 |
self.replace_null_values(value)
|
161 |
159 |
if value is None:
|
162 |
160 |
dico[key] = ''
|
163 |
161 |
|
164 |
162 |
@endpoint(
|
165 |
|
display_category=_('Family'),
|
|
163 |
display_category='Famille',
|
166 |
164 |
description='Liste des catégories',
|
167 |
165 |
name='read-category-list',
|
168 |
166 |
perm='can_access',
|
169 |
167 |
)
|
170 |
168 |
def read_category_list(self, request):
|
171 |
169 |
return {'data': self.get_referential('Category')['list']}
|
172 |
170 |
|
173 |
171 |
@endpoint(
|
174 |
|
display_category=_('Family'),
|
|
172 |
display_category='Famille',
|
175 |
173 |
description='Liste des civilités',
|
176 |
174 |
name='read-civility-list',
|
177 |
175 |
perm='can_access',
|
178 |
176 |
)
|
179 |
177 |
def read_civility_list(self, request):
|
180 |
178 |
return {'data': self.get_referential('Civility')['list']}
|
181 |
179 |
|
182 |
180 |
@endpoint(
|
183 |
|
display_category=_('Family'),
|
|
181 |
display_category='Famille',
|
184 |
182 |
description='Liste des compléments du numéro de voie',
|
185 |
183 |
name='read-complement-list',
|
186 |
184 |
perm='can_access',
|
187 |
185 |
)
|
188 |
186 |
def read_complement_list(self, request):
|
189 |
187 |
return {'data': self.get_referential('Complement')['list']}
|
190 |
188 |
|
191 |
189 |
@endpoint(
|
192 |
|
display_category=_('Family'),
|
|
190 |
display_category='Famille',
|
193 |
191 |
description='liste des catégories socio-professionnelles',
|
194 |
192 |
name='read-csp-list',
|
195 |
193 |
perm='can_access',
|
196 |
194 |
)
|
197 |
195 |
def read_csp_list(self, request):
|
198 |
196 |
data = self.get_referential('CSP')['list']
|
199 |
197 |
|
200 |
198 |
# remove redundant codes
|
... | ... | |
203 |
201 |
for item in data:
|
204 |
202 |
item['text'] = item['text'].strip()
|
205 |
203 |
if item['text'] not in uniq_text:
|
206 |
204 |
uniq_data.append(item)
|
207 |
205 |
uniq_text.add(item['text'])
|
208 |
206 |
return {'data': uniq_data}
|
209 |
207 |
|
210 |
208 |
@endpoint(
|
211 |
|
display_category=_('Family'),
|
|
209 |
display_category='Famille',
|
212 |
210 |
description='liste des qualités du référenciel',
|
213 |
211 |
name='read-quality-list',
|
214 |
212 |
perm='can_access',
|
215 |
213 |
)
|
216 |
214 |
def read_quality_list(self, request):
|
217 |
215 |
return {'data': self.get_referential('Quality')['list']}
|
218 |
216 |
|
219 |
217 |
@endpoint(
|
220 |
|
display_category=_('Family'),
|
|
218 |
display_category='Famille',
|
221 |
219 |
description='Liste des sexes',
|
222 |
220 |
name='read-sex-list',
|
223 |
221 |
perm='can_access',
|
224 |
222 |
)
|
225 |
223 |
def read_sex_list(self, request):
|
226 |
224 |
return {'data': self.get_referential('Sex')['list']}
|
227 |
225 |
|
228 |
226 |
@endpoint(
|
229 |
|
display_category=_('Family'),
|
|
227 |
display_category='Famille',
|
230 |
228 |
description='liste des situations',
|
231 |
229 |
name='read-situation-list',
|
232 |
230 |
perm='can_access',
|
233 |
231 |
)
|
234 |
232 |
def read_situation_list(self, request):
|
235 |
233 |
return {'data': self.get_referential('Situation')['list']}
|
236 |
234 |
|
237 |
235 |
@endpoint(
|
238 |
|
display_category=_('Family'),
|
239 |
|
description=_('Create link between user and family'),
|
|
236 |
display_category='Famille',
|
|
237 |
description='Lier un compte usager à une famille',
|
240 |
238 |
perm='can_access',
|
241 |
|
parameters={'NameID': {'description': _('Publik ID')}},
|
|
239 |
parameters={'NameID': {'description': 'Publik NameID'}},
|
242 |
240 |
post={'request_body': {'schema': {'application/json': schemas.LINK_SCHEMA}}},
|
243 |
241 |
)
|
244 |
242 |
def link(self, request, NameID, post_data):
|
245 |
243 |
family_id = post_data['family_id']
|
246 |
244 |
response = self.call('Family', 'readFamily', dossierNumber=family_id)
|
247 |
245 |
if not (
|
248 |
246 |
response['RL1']['firstname'] == post_data['firstname'].upper()
|
249 |
247 |
and response['RL1']['lastname'] == post_data['lastname'].upper()
|
250 |
248 |
and response['RL1']['dateBirth'].strftime('%Y-%m-%d') == post_data['dateBirth']
|
251 |
249 |
):
|
252 |
250 |
raise APIError("RL1 does not match '%s' family" % family_id, err_code='not-found')
|
253 |
251 |
Link.objects.update_or_create(resource=self, name_id=NameID, defaults={'family_id': family_id})
|
254 |
252 |
return {'data': 'ok'}
|
255 |
253 |
|
256 |
254 |
@endpoint(
|
257 |
|
display_category=_('Family'),
|
258 |
|
description=_('Delete link between user and family'),
|
|
255 |
display_category='Famille',
|
|
256 |
description='Supprimer une liaison entre un compte usager et une famille',
|
259 |
257 |
methods=['post'],
|
260 |
258 |
perm='can_access',
|
261 |
259 |
parameters={
|
262 |
|
'NameID': {'description': _('Publik ID')},
|
|
260 |
'NameID': {'description': 'Publik NameID'},
|
263 |
261 |
},
|
264 |
262 |
)
|
265 |
263 |
def unlink(self, request, NameID):
|
266 |
264 |
link = self.get_link(NameID)
|
267 |
265 |
link.delete()
|
268 |
266 |
return {'data': 'ok'}
|
269 |
267 |
|
270 |
268 |
@endpoint(
|
271 |
|
display_category=_('Family'),
|
|
269 |
display_category='Famille',
|
272 |
270 |
description='Informations sur la famille',
|
273 |
271 |
perm='can_access',
|
274 |
272 |
name='read-family',
|
275 |
|
parameters={'NameID': {'description': _('Publik ID')}},
|
|
273 |
parameters={'NameID': {'description': 'Publik NameID'}},
|
276 |
274 |
)
|
277 |
275 |
def read_family(self, request, NameID):
|
278 |
276 |
family_id = self.get_link(NameID).family_id
|
279 |
277 |
data = self.get_family(family_id)
|
280 |
278 |
return {'data': data}
|
281 |
279 |
|
282 |
280 |
@endpoint(
|
283 |
|
display_category=_('Family'),
|
|
281 |
display_category='Famille',
|
284 |
282 |
description="Informations sur un responsable légal",
|
285 |
283 |
perm='can_access',
|
286 |
284 |
name='read-rl',
|
287 |
285 |
parameters={
|
288 |
|
'NameID': {'description': _('Publik ID')},
|
|
286 |
'NameID': {'description': 'Publik NameID'},
|
289 |
287 |
'rl_id': {'description': 'Numéro du représentant légal'},
|
290 |
288 |
},
|
291 |
289 |
)
|
292 |
290 |
def read_rl(self, request, NameID, rl_id):
|
293 |
291 |
family_id = self.get_link(NameID).family_id
|
294 |
292 |
data = self.get_family(family_id)
|
295 |
293 |
if data['RL1']['num'] == rl_id:
|
296 |
294 |
data = data['RL1']
|
297 |
295 |
elif data['RL2'] and data['RL2']['num'] == rl_id:
|
298 |
296 |
data = data['RL2']
|
299 |
297 |
else:
|
300 |
298 |
raise APIError("no '%s' RL on '%s' family" % (rl_id, family_id), err_code='not-found')
|
301 |
299 |
return {'data': data}
|
302 |
300 |
|
303 |
301 |
@endpoint(
|
304 |
|
display_category=_('Family'),
|
|
302 |
display_category='Famille',
|
305 |
303 |
description="Informations sur une personne autorisée à récupérer les enfants ou à prévenir en cas d'urgence",
|
306 |
304 |
perm='can_access',
|
307 |
305 |
name='read-person',
|
308 |
306 |
parameters={
|
309 |
|
'NameID': {'description': _('Publik ID')},
|
|
307 |
'NameID': {'description': 'Publik NameID'},
|
310 |
308 |
'person_id': {'description': 'Numéro de la personne'},
|
311 |
309 |
'kind': {'description': "'authorized' (par defaut) ou 'emergency'"},
|
312 |
310 |
},
|
313 |
311 |
)
|
314 |
312 |
def read_person(self, request, NameID, person_id, kind='authorized'):
|
315 |
313 |
if kind not in ('authorized', 'emergency'):
|
316 |
314 |
raise APIError("wrong '%s' value for kind parameter" % kind)
|
317 |
315 |
family_id = self.get_link(NameID).family_id
|
... | ... | |
321 |
319 |
break
|
322 |
320 |
else:
|
323 |
321 |
raise APIError(
|
324 |
322 |
"no '%s' %s person on '%s' family" % (person_id, kind, family_id), err_code='not-found'
|
325 |
323 |
)
|
326 |
324 |
return {'data': person}
|
327 |
325 |
|
328 |
326 |
@endpoint(
|
329 |
|
display_category=_('Family'),
|
|
327 |
display_category='Famille',
|
330 |
328 |
description="Informations sur un enfant",
|
331 |
329 |
perm='can_access',
|
332 |
330 |
name='read-child',
|
333 |
331 |
parameters={
|
334 |
|
'NameID': {'description': _('Publik ID')},
|
|
332 |
'NameID': {'description': 'Publik NameID'},
|
335 |
333 |
'child_id': {'description': "Numéro de l'enfant"},
|
336 |
334 |
},
|
337 |
335 |
)
|
338 |
336 |
def read_child(self, request, NameID, child_id):
|
339 |
337 |
family_id = self.get_link(NameID).family_id
|
340 |
338 |
data = self.get_family(family_id)
|
341 |
339 |
for child in data['childList']:
|
342 |
340 |
if child['num'] == child_id:
|
343 |
341 |
break
|
344 |
342 |
else:
|
345 |
343 |
raise APIError("no '%s' child on '%s' family" % (child_id, family_id), err_code='not-found')
|
346 |
344 |
return {'data': child}
|
347 |
345 |
|
348 |
346 |
@endpoint(
|
349 |
|
display_category=_('Family'),
|
|
347 |
display_category='Famille',
|
350 |
348 |
description="Vérifier qu'un responsable légal existe en base",
|
351 |
349 |
perm='can_access',
|
352 |
350 |
name='is-rl-exists',
|
353 |
351 |
post={'request_body': {'schema': {'application/json': schemas.ISEXISTS_SCHEMA}}},
|
354 |
352 |
)
|
355 |
353 |
def is_rl_exists(self, request, post_data):
|
356 |
354 |
response = self.call('Family', 'isRLExists', **post_data)
|
357 |
355 |
return {'data': response}
|
358 |
356 |
|
359 |
357 |
@endpoint(
|
360 |
|
display_category=_('Family'),
|
|
358 |
display_category='Famille',
|
361 |
359 |
description="Vérifier qu'un responsable légal existe en base",
|
362 |
360 |
perm='can_access',
|
363 |
361 |
name='is-child-exists',
|
364 |
362 |
post={'request_body': {'schema': {'application/json': schemas.ISEXISTS_SCHEMA}}},
|
365 |
363 |
)
|
366 |
364 |
def is_child_exists(self, request, post_data):
|
367 |
365 |
response = self.call('Family', 'isChildExists', **post_data)
|
368 |
366 |
return {'data': response}
|
369 |
367 |
|
370 |
368 |
@endpoint(
|
371 |
|
display_category=_('Family'),
|
|
369 |
display_category='Famille',
|
372 |
370 |
description='Création de la famille',
|
373 |
371 |
name='create-family',
|
374 |
372 |
perm='can_access',
|
375 |
|
parameters={'NameID': {'description': _('Publik ID')}},
|
|
373 |
parameters={'NameID': {'description': 'Publik NameID'}},
|
376 |
374 |
post={'request_body': {'schema': {'application/json': schemas.CREATE_FAMILY_SCHEMA}}},
|
377 |
375 |
)
|
378 |
376 |
def create_family(self, request, NameID, post_data):
|
379 |
377 |
if self.link_set.filter(name_id=NameID).exists():
|
380 |
378 |
raise APIError('User already linked to family', err_code='already-linked')
|
381 |
379 |
|
382 |
380 |
response = self.call('Family', 'createFamily', **post_data)
|
383 |
381 |
data = serialize_object(response)
|
... | ... | |
386 |
384 |
errors = data.get('rl1ErrorList') + data.get('childErrorList')
|
387 |
385 |
err_codes = [x.split(':')[0][:4] for x in errors]
|
388 |
386 |
raise APIError(' ; '.join(errors), err_code=', '.join(err_codes))
|
389 |
387 |
|
390 |
388 |
Link.objects.create(resource=self, name_id=NameID, family_id=family_id)
|
391 |
389 |
return {'data': data}
|
392 |
390 |
|
393 |
391 |
@endpoint(
|
394 |
|
display_category=_('Family'),
|
|
392 |
display_category='Famille',
|
395 |
393 |
description='Modification de la famille',
|
396 |
394 |
name='update-family',
|
397 |
395 |
perm='can_access',
|
398 |
|
parameters={'NameID': {'description': _('Publik ID')}},
|
|
396 |
parameters={'NameID': {'description': 'Publik NameID'}},
|
399 |
397 |
post={'request_body': {'schema': {'application/json': schemas.UPDATE_FAMILY_SCHEMA}}},
|
400 |
398 |
)
|
401 |
399 |
def update_family(self, request, NameID, post_data):
|
402 |
400 |
family_id = self.get_link(NameID).family_id
|
403 |
401 |
self.replace_null_values(post_data)
|
404 |
402 |
|
405 |
403 |
response = self.call('Family', 'updateFamily', dossierNumber=family_id, **post_data)
|
406 |
404 |
data = serialize_object(response)
|
407 |
405 |
family_id = data.get('number')
|
408 |
406 |
if not family_id:
|
409 |
407 |
errors = data.get('rl1ErrorList') + data.get('childErrorList')
|
410 |
408 |
err_codes = [x.split(':')[0][:4] for x in errors]
|
411 |
409 |
raise APIError(' ; '.join(errors), err_code=', '.join(err_codes))
|
412 |
410 |
return {'data': data}
|
413 |
411 |
|
414 |
412 |
@endpoint(
|
415 |
|
display_category=_('Family'),
|
|
413 |
display_category='Famille',
|
416 |
414 |
description="Mise à jour des coordonnées d'une personne",
|
417 |
415 |
name='update-coordinate',
|
418 |
416 |
perm='can_access',
|
419 |
417 |
parameters={
|
420 |
|
'NameID': {'description': _('Publik ID')},
|
|
418 |
'NameID': {'description': 'Publik NameID'},
|
421 |
419 |
'rl_id': {'description': 'Numéro du représentant légal'},
|
422 |
420 |
},
|
423 |
421 |
post={'request_body': {'schema': {'application/json': schemas.UPDATE_COORDINATE_SCHEMA}}},
|
424 |
422 |
)
|
425 |
423 |
def update_coordinate(self, request, NameID, rl_id, post_data):
|
426 |
424 |
family_id = self.get_link(NameID).family_id
|
427 |
425 |
self.replace_null_values(post_data)
|
428 |
426 |
|
429 |
427 |
self.call('Family', 'updateCoordinate', numDossier=family_id, numPerson=rl_id, **post_data)
|
430 |
428 |
return {'data': 'ok'}
|
431 |
429 |
|
432 |
430 |
@endpoint(
|
433 |
|
display_category=_('Family'),
|
|
431 |
display_category='Famille',
|
434 |
432 |
description="Création d'une personne autorisée à récupérer les enfants ou à prévenir en cas d'urgence",
|
435 |
433 |
name='create-person',
|
436 |
434 |
perm='can_access',
|
437 |
435 |
parameters={
|
438 |
|
'NameID': {'description': _('Publik ID')},
|
|
436 |
'NameID': {'description': 'Publik NameID'},
|
439 |
437 |
'kind': {'description': "'authorized' (par defaut) ou 'emergency'"},
|
440 |
438 |
},
|
441 |
439 |
post={'request_body': {'schema': {'application/json': schemas.FAMILYPERSON_SCHEMA}}},
|
442 |
440 |
)
|
443 |
441 |
def create_person(self, request, NameID, post_data, kind='authorized'):
|
444 |
442 |
if kind not in ('authorized', 'emergency'):
|
445 |
443 |
raise APIError("wrong '%s' value for kind parameter" % kind)
|
446 |
444 |
family_id = self.get_link(NameID).family_id
|
... | ... | |
454 |
452 |
'categorie': family['category'],
|
455 |
453 |
'situation': family['situation'],
|
456 |
454 |
kind + 'PersonList': [{'personList': personList}],
|
457 |
455 |
}
|
458 |
456 |
self.call('Family', 'updateFamily', **payload)
|
459 |
457 |
return {'data': 'ok'}
|
460 |
458 |
|
461 |
459 |
@endpoint(
|
462 |
|
display_category=_('Family'),
|
|
460 |
display_category='Famille',
|
463 |
461 |
description="Mise à jour d'une personne autorisée à récupérer les enfants ou à prévenir en cas d'urgence",
|
464 |
462 |
name='update-person',
|
465 |
463 |
perm='can_access',
|
466 |
464 |
parameters={
|
467 |
|
'NameID': {'description': _('Publik ID')},
|
|
465 |
'NameID': {'description': 'Publik NameID'},
|
468 |
466 |
'person_id': {'description': 'Numéro de la personne'},
|
469 |
467 |
'kind': {'description': "'authorized' (par defaut) ou 'emergency'"},
|
470 |
468 |
},
|
471 |
469 |
post={'request_body': {'schema': {'application/json': schemas.FAMILYPERSON_SCHEMA}}},
|
472 |
470 |
)
|
473 |
471 |
def update_person(self, request, NameID, person_id, post_data, kind='authorized'):
|
474 |
472 |
if kind not in ('authorized', 'emergency'):
|
475 |
473 |
raise APIError("wrong '%s' value for kind parameter" % kind)
|
... | ... | |
492 |
490 |
'categorie': family['category'],
|
493 |
491 |
'situation': family['situation'],
|
494 |
492 |
kind + 'PersonList': [{'personList': personList}],
|
495 |
493 |
}
|
496 |
494 |
self.call('Family', 'updateFamily', **payload)
|
497 |
495 |
return {'data': 'ok'}
|
498 |
496 |
|
499 |
497 |
@endpoint(
|
500 |
|
display_category=_('Family'),
|
|
498 |
display_category='Famille',
|
501 |
499 |
description="Suppression d'une personne autorisée à récupérer les enfants ou à prévenir en cas d'urgence",
|
502 |
500 |
name='delete-person',
|
503 |
501 |
perm='can_access',
|
504 |
502 |
parameters={
|
505 |
|
'NameID': {'description': _('Publik ID')},
|
|
503 |
'NameID': {'description': 'Publik NameID'},
|
506 |
504 |
'person_id': {'description': 'Numéro de la personne'},
|
507 |
505 |
'kind': {'description': "'authorized' (par defaut) ou 'emergency'"},
|
508 |
506 |
},
|
509 |
507 |
methods=['post'],
|
510 |
508 |
)
|
511 |
509 |
def delete_person(self, request, NameID, person_id, kind='authorized'):
|
512 |
510 |
if kind not in ('authorized', 'emergency'):
|
513 |
511 |
raise APIError("wrong '%s' value for kind parameter" % kind)
|
514 |
|
-
|