Projet

Général

Profil

0002-sp_fr-implement-response-flow-33838.patch

Benjamin Dauvergne, 24 juin 2019 22:50

Télécharger (8,18 ko)

Voir les différences:

Subject: [PATCH 2/2] sp_fr: implement response flow (#33838)

 passerelle/apps/sp_fr/models.py | 133 ++++++++++++++++++++++++++++++--
 1 file changed, 128 insertions(+), 5 deletions(-)
passerelle/apps/sp_fr/models.py
23 23
import base64
24 24
import datetime
25 25
import unicodedata
26
import uuid
26 27

  
27 28
from lxml import etree as ET
28 29

  
......
170 171
                    try:
171 172
                        move, error = handler()
172 173
                    except Exception:
174
                        count -= 1
173 175
                        self.logger.exception('handling of file "%s" failed', filename)
174
                        # sftp.rename(filename, 'FAILED/' + filename)
176
                        sftp.rename(filename, 'FAILED/' + filename)
175 177
                    else:
176 178
                        if move and error:
179
                            count -= 1
177 180
                            self.logger.error('handling of file "%s" failed: %s', filename, error)
178
                            # sftp.rename(filename, 'FAILED/' + filename)
181
                            sftp.rename(filename, 'FAILED/' + filename)
179 182
                        else:
180 183
                            if error:
184
                                count -= 1
181 185
                                self.logger.warning('handling of file "%s" failed: %s', filename, error)
182 186
                            elif move:
187
                                count -= 1
183 188
                                sftp.rename(filename, 'DONE/' + filename)
184 189
                    if not count:
185 190
                        break
......
226 231
                    return False, 'error during response to service-public.fr %r' % e
227 232
                self.request.state = Request.STATE_RETURNED
228 233
                self.request.save()
234
                self.resource.logger.info('%s responded, closed', self.request.filename)
229 235
            return True, None
230 236

  
231 237
        def process(self, fd):
......
330 336
            return submitter.result.backoffice_url
331 337

  
332 338
        def response(self):
333
            raise NotImplementedError
339
            with self.resource.output_sftp.client() as client:
340
                with client.open(self.request.response_zip_filename, mode='w') as fd:
341
                    self.request.build_response_zip(
342
                        fd,
343
                        etat='100',
344
                        commentaire=u'Demande transmise à la collectivité')
345
            with self.resource.input_sftp.client() as client:
346
                with client.open('DONE/' + self.request.response_zip_filename, mode='w') as fd:
347
                    self.request.build_response_zip(
348
                        fd,
349
                        etat='100',
350
                        commentaire=u'Demande transmise à la collectivité')
334 351

  
335 352
        def get_data(self, data, name):
336 353
            # prevent error in manual mapping
......
626 643
    STATE_ERROR = 'error'
627 644
    STATES = [
628 645
        (STATE_RECEIVED, _('Received')),
629
        (STATE_TRANSFERED, _('Transfered')),
630
        (STATE_ERROR, _('Transfered')),
646
        (STATE_TRANSFERED, _('Transferred')),
647
        (STATE_ERROR, _('Error')),
631 648
        (STATE_RETURNED, _('Returned')),
632 649
    ]
633 650

  
......
668 685
            self.resource.logger.error('could not delete %s', self.archive)
669 686
        return super(Request, self).delete(*args, **kwargs)
670 687

  
688
    @property
689
    def message_xml(self):
690
        # FileField can be closed, or open, you never know, and used as a
691
        # contextmanager, __enter__ does not re-open/re-seek(0) it :/
692
        self.archive.open()
693

  
694
        with self.archive as fd:
695
            with zipfile.ZipFile(fd) as archive:
696
                with archive.open('message.xml') as message_xml_fd:
697
                    s = message_xml_fd.read()
698
                    return ET.fromstring(s)
699

  
700
    @property
701
    def id_enveloppe(self):
702
        message_xml = self.message_xml
703
        ns = {
704
            'pec': 'http://finances.gouv.fr/dgme/pec/message/v1',
705
            'mdel': 'http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier'
706
        }
707
        return message_xml.find('.//{%(pec)s}MessageId' % ns).text.split()[1]
708

  
709
    def build_message_xml_retour(self, etat, commentaire):
710
        message_xml = self.message_xml
711

  
712
        ns = {
713
            'pec': 'http://finances.gouv.fr/dgme/pec/message/v1',
714
            'mdel': 'http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier'
715
        }
716

  
717
        template = '''<ns2:Message xmlns:ns2="http://finances.gouv.fr/dgme/pec/message/v1" xmlns="http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier">
718
    <ns2:Header>
719
        <ns2:Routing>
720
            <ns2:MessageId/>
721
            <ns2:RefToMessageId/>
722
            <ns2:FlowType/>
723
            <ns2:Sender/>
724
            <ns2:Recipients>
725
                <ns2:Recipient/>
726
            </ns2:Recipients>
727
        </ns2:Routing>
728
        <ns2:Security>
729
            <ns2:Horodatage>false</ns2:Horodatage>
730
        </ns2:Security>
731
    </ns2:Header>
732
    <ns2:Body>
733
        <ns2:Content><ns2:Retour>
734
                <ns2:Enveloppe>
735
                    <ns2:NumeroTeledemarche/>
736
                    <ns2:MotDePasse/>
737
                </ns2:Enveloppe>
738
                <ns2:Instruction>
739
                    <ns2:Maj>
740
                        <ns2:Etat/>
741
                        <ns2:Commentaire/>
742
                    </ns2:Maj>
743
                </ns2:Instruction>
744
            </ns2:Retour>
745
        </ns2:Content>
746
    </ns2:Body>
747
</ns2:Message>'''  # NOQA E501
748

  
749
        response = ET.XML(template)
750

  
751
        message_id = message_xml.find('.//{%(pec)s}MessageId' % ns).text
752
        response.find('.//{%(pec)s}MessageId' % ns).text = 'RET-1-' + message_id # str(uuid.uuid4().hex)
753
        response.find('.//{%(pec)s}RefToMessageId' % ns).text = message_id
754
        response.find('.//{%(pec)s}FlowType' % ns).text = message_xml.find('.//{%(pec)s}FlowType' % ns).text
755
        response.find('.//{%(pec)s}Sender' % ns).extend(
756
            message_xml.find('.//{%(pec)s}Recipient' % ns))
757
        response.find('.//{%(pec)s}Recipient' % ns).extend(
758
            message_xml.find('.//{%(pec)s}Sender' % ns))
759

  
760
        response.find('.//{%(pec)s}FlowType' % ns).text = message_xml.find('.//{%(pec)s}FlowType' % ns).text
761

  
762
        # Strangely the same node in the response does not have the same
763
        # namespace as the node in the request, whatever...
764
        response.find('.//{%(pec)s}NumeroTeledemarche' % ns).text = message_xml.find(
765
            './/{%(mdel)s}NumeroTeledemarche' % ns).text
766
        response.find('.//{%(pec)s}MotDePasse' % ns).text = message_xml.find('.//{%(mdel)s}MotDePasse' % ns).text
767
        response.find('.//{%(pec)s}Etat' % ns).text = '100'
768
        response.find('.//{%(pec)s}Commentaire' % ns).text = u'Dossier transmis à la collectivité'
769
        return response
770

  
771
    def build_response_zip(self, fd_or_filename, etat, commentaire):
772
        with zipfile.ZipFile(fd_or_filename, 'w') as archive:
773
            message_xml = self.build_message_xml_retour(
774
                etat=etat, commentaire=commentaire)
775
            archive.writestr('message.xml',
776
                             '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
777
                             + ET.tostring(message_xml, encoding='utf-8'))
778

  
779
    @property
780
    def response_zip_filename(self):
781
        m = FILE_PATTERN.match(self.filename)
782

  
783
        numero_teledossier = m.group('identifier')
784
        code_demarche = m.group('procedure')
785
        id_enveloppe = self.id_enveloppe
786
        numero_sequence = '1'
787

  
788
        return '%s-%s-%s-%s.zip' % (
789
            numero_teledossier,
790
            code_demarche,
791
            id_enveloppe,
792
            numero_sequence)
793

  
671 794
    class Meta:
672 795
        verbose_name = _('MDEL request')
673 796
        verbose_name_plural = _('MDEL requests')
674
-