From 07b56cdddbe8f086b5928cf37d64fb087a4a1c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 8 Jun 2020 21:58:35 +0200 Subject: [PATCH] gdc: replace SOAPpy usage by straight POSTs (#43756) --- passerelle/apps/gdc/models.py | 62 ++++++++++++++++++++++++++++------- passerelle/apps/gdc/views.py | 50 +++++++++++----------------- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/passerelle/apps/gdc/models.py b/passerelle/apps/gdc/models.py index 5aad422b..784176d3 100644 --- a/passerelle/apps/gdc/models.py +++ b/passerelle/apps/gdc/models.py @@ -1,7 +1,4 @@ -try: - import SOAPpy -except ImportError: - SOAPpy = None +import xml.etree.ElementTree as ET try: import phpserialize @@ -17,8 +14,26 @@ from passerelle.base.models import BaseResource from passerelle.utils.api import endpoint +def deep_bytes2str(obj): + if obj is None or isinstance(obj, (int, str)): + return obj + if isinstance(obj, bytes): + try: + return obj.decode('utf-8') + except UnicodeDecodeError: + return obj + if isinstance(obj, list): + return [deep_bytes2str(x) for x in obj] + if isinstance(obj, dict): + new_d = {} + for k, v in obj.items(): + new_d[force_text(k)] = deep_bytes2str(v) + return new_d + return obj + + def phpserialize_loads(s): - return phpserialize.loads(s.encode('utf-8')) + return deep_bytes2str(phpserialize.loads(s.encode('utf-8'))) class Gdc(BaseResource): @@ -31,22 +46,47 @@ class Gdc(BaseResource): class Meta: verbose_name = _('GDC Web Service') + def call_soap(self, action, *args, **kwargs): + params = [] + for i, arg in enumerate(args): + params.append('%(value)s' % {'i': i + 1, 'value': arg}) + for key, value in kwargs.items(): + type_ = 'int' if isinstance(value, int) else 'string' + params.append('<%(key)s xsi:type="xsd:%(type)s">%(value)s' % { + 'key': key, 'type': type_, 'value': value}) + + data = """ + + +<%(action)s SOAP-ENC:root="1"> +%(params)s + + +""" % {'action': action, 'params': ''.join(params)} + resp = self.requests.post(self.service_url, data=data) + return ET.ElementTree(ET.fromstring(resp.content)) + + @endpoint() def communes(self, request, *args, **kwargs): - server = SOAPpy.SOAPProxy(self.service_url) - soap_result = phpserialize_loads(server.getListeCommune()['listeCommune']) + resp = self.call_soap('getListeCommune') + soap_result = phpserialize_loads(resp.findall('.//listeCommune')[0].text) result = [] for k, v in soap_result.items(): result.append({'id': k, 'text': force_text(v, 'utf-8')}) - result.sort(lambda x,y: cmp(x['id'], y['id'])) + result.sort(key=lambda x: x['id']) return result @endpoint() def objets(self, request, *args, **kwargs): - server = SOAPpy.SOAPProxy(self.service_url) - soap_result = phpserialize_loads(server.getListeObjet()['listeObjet']) + resp = self.call_soap('getListeObjet') + soap_result = phpserialize_loads(resp.findall('.//listeObjet')[0].text) result = [] for k, v in soap_result.items(): result.append({'id': k, 'text': force_text(v, 'utf-8')}) - result.sort(lambda x,y: cmp(x['id'], y['id'])) + result.sort(key=lambda x: x['id']) return result diff --git a/passerelle/apps/gdc/views.py b/passerelle/apps/gdc/views.py index 48410f4f..3ed308af 100644 --- a/passerelle/apps/gdc/views.py +++ b/passerelle/apps/gdc/views.py @@ -1,4 +1,5 @@ from django.http import Http404 +from django.utils.encoding import force_text from django.views.generic.base import View from django.views.generic.detail import SingleObjectMixin, DetailView @@ -6,7 +7,7 @@ from passerelle.compat import json_loads import passerelle.utils as utils from passerelle.utils.conversion import normalize -from .models import Gdc, phpserialize, phpserialize_loads, SOAPpy +from .models import Gdc, phpserialize, phpserialize_loads class GdcCrash(Exception): @@ -17,12 +18,11 @@ class StatusView(View, SingleObjectMixin): model = Gdc def get(self, request, *args, **kwargs): - if SOAPpy is None: - raise Http404 ref = int(kwargs.get('ref')) - server = SOAPpy.SOAPProxy(self.get_object().service_url) + service = self.get_object() try: - soap_result = server.getDemandeControleurEtat(ref)['listeInfo'] + resp = service.call_soap('getDemandeControleurEtat', ref) + soap_result = resp.findall('.//listeInfo')[0].text except: # if there's a gdc crash don't return anything and hopefully the # w.c.s. workflow will handle that and retry later. @@ -30,18 +30,14 @@ class StatusView(View, SingleObjectMixin): else: gdc_result = phpserialize_loads(soap_result) result = { - 'status_id': gdc_result['STATUT_ID'] + 'status_id': gdc_result['STATUT_ID'], } return utils.response_for_json(request, {'data': result}) -def get_voies(service_url, insee): - server = SOAPpy.SOAPProxy(service_url) - try: - raw_soap_result = server.getListeVoieCommune(insee) - except: - raise GdcCrash() - soap_result = phpserialize_loads(raw_soap_result['listeVoie']) +def get_voies(service, insee): + resp = service.call_soap('getListeVoieCommune', insee) + soap_result = phpserialize_loads(resp.findall('.//listeVoie')[0].text) result = [] prefix_map = { 'ALL': 'ALLEE', @@ -84,7 +80,7 @@ def get_voies(service_url, insee): if v.startswith(prefix + ' '): v = (full + v[len(prefix):]).strip() result.append({'id': k, 'text': v}) - result.sort(lambda x,y: cmp(x['id'], y['id'])) + result.sort(key=lambda x: x['id']) return result @@ -92,11 +88,9 @@ class VoiesView(View, SingleObjectMixin): model = Gdc def get(self, request, *args, **kwargs): - if SOAPpy is None: - raise Http404 insee = kwargs.get('insee') try: - result = get_voies(self.get_object().service_url, insee) + result = get_voies(self.get_object(), insee) except GdcCrash: result = [] q = request.GET.get('q') @@ -110,7 +104,7 @@ class PostDemandeView(View, SingleObjectMixin): model = Gdc @utils.protected_api('can_post_request') - def post(self, request, *args, **kwargs): + def get(self, request, *args, **kwargs): # # # @@ -122,10 +116,7 @@ class PostDemandeView(View, SingleObjectMixin): # # # - if SOAPpy is None: - raise Http404 data = json_loads(request.body) - server = SOAPpy.SOAPProxy(self.get_object().service_url) voie_id = data['fields'].get('voie_raw') voie_str = data['fields'].get('voie') insee = data['fields'].get('commune_raw') @@ -133,7 +124,7 @@ class PostDemandeView(View, SingleObjectMixin): # look for a voie with that name, so we can provide an identifier # to gdc try: - voies = get_voies(self.get_object().service_url, insee) + voies = get_voies(self.get_object(), insee) except GdcCrash: result = {'result': 'gdc soap crash'} return utils.response_for_json(request, result) @@ -152,9 +143,9 @@ class PostDemandeView(View, SingleObjectMixin): 'prenom': data['fields'].get('prenom'), 'mail': data['fields'].get('mail'), 'telephone': data['fields'].get('telephone'), - 'objet_externe': objet, + 'objet_externe': int(objet), 'commentaire': data['fields'].get('commentaire'), - 'insee_commune': insee, + 'insee_commune': int(insee), 'voie_id': voie_id, 'voie_str': voie_str, 'voie_num': data['fields'].get('voie_num'), @@ -165,12 +156,13 @@ class PostDemandeView(View, SingleObjectMixin): kwargs['picture_b64'] = data['fields']['picture']['content'] try: - soap_result = server.addDemandeExterneParticulier(**kwargs) - except: + resp = self.get_object().call_soap('addDemandeExterneParticulier', **kwargs) + except IOError: result = {'result': 'gdc soap crash'} else: - result = phpserialize_loads(soap_result['listeInfo']) - result = {'result': soap_result['code_retour'], + code_retour = force_text(resp.findall('.//code_retour')[0].text) + result = phpserialize_loads(resp.findall('.//listeInfo')[0].text) + result = {'result': code_retour, 'display_id': result.get('IDENTIFIANT'), 'id': result.get('IDENTIFIANT'), 'details': result} @@ -185,6 +177,4 @@ class GdcDetailView(DetailView): context = super(GdcDetailView, self).get_context_data(**kwargs) if phpserialize is None: context['missing_phpserialize'] = True - if SOAPpy is None: - context['missing_soappy'] = True return context