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 |
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()
|
229 |
|
return True, None
|
|
234 |
self.resource.logger.info('%s responded, closed', self.request.filename)
|
|
235 |
return False, None
|
230 |
236 |
|
231 |
237 |
def process(self, fd):
|
232 |
238 |
try:
|
... | ... | |
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
|
... | ... | |
627 |
644 |
STATES = [
|
628 |
645 |
(STATE_RECEIVED, _('Received')),
|
629 |
646 |
(STATE_TRANSFERED, _('Transfered')),
|
630 |
|
(STATE_ERROR, _('Transfered')),
|
|
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 |
|
-
|