Projet

Général

Profil

0001-wf-export_to_model-support-XML-templates-56537.patch

Benjamin Dauvergne, 10 septembre 2021 14:57

Télécharger (6,64 ko)

Voir les différences:

Subject: [PATCH] wf/export_to_model: support XML templates (#56537)

 tests/test_workflows.py   | 59 ++++++++++++++++++++++++++++++++++++++-
 wcs/wf/export_to_model.py | 48 +++++++++++++++++++++++++++----
 2 files changed, 101 insertions(+), 6 deletions(-)
tests/test_workflows.py
45 45
from wcs.formdata import Evolution
46 46
from wcs.formdef import FormDef
47 47
from wcs.qommon.errors import ConnectionError
48
from wcs.qommon.form import Form, UploadedFile
48
from wcs.qommon.form import Form, UploadedFile, UploadValidationError
49 49
from wcs.qommon.http_request import HTTPRequest
50 50
from wcs.qommon.upload_storage import PicklableUpload
51 51
from wcs.wf.aggregation_email import (
......
3987 3987
    assert b'>A &lt;&gt; name<' in new_content
3988 3988

  
3989 3989

  
3990
def test_export_to_model_xml(two_pubs):
3991
    pub = two_pubs
3992
    LoggedError = pub.loggederror_class
3993
    if LoggedError:
3994
        LoggedError.wipe()
3995

  
3996
    formdef = FormDef()
3997
    formdef.name = 'foo-export-to-template-with-django'
3998
    formdef.fields = [
3999
        StringField(id='1', label='String', type='string', varname='string'),
4000
    ]
4001
    formdef.store()
4002
    formdata = formdef.data_class()()
4003
    formdata.data = {'1': 'écho'}
4004
    formdata.just_created()
4005
    formdata.store()
4006

  
4007
    # good XML
4008
    item = ExportToModel()
4009
    item.method = 'non-interactive'
4010
    item.attach_to_history = True
4011

  
4012
    def run(template, filename='/foo/template.xml', content_type='application/xml'):
4013
        upload = QuixoteUpload(filename, content_type=content_type)
4014
        upload.fp = io.BytesIO()
4015
        upload.fp.write(template.encode())
4016
        upload.fp.seek(0)
4017
        item.model_file = UploadedFile(pub.app_dir, None, upload)
4018
        item.convert_to_pdf = False
4019
        pub.substitutions.reset()
4020
        pub.substitutions.feed(formdata)
4021
        item.perform(formdata)
4022
        with open(formdata.evolution[0].parts[-1].filename) as fd:
4023
            return fd.read()
4024

  
4025
    # good XML
4026
    assert run(template='<a>{{ form_var_string }}</a>') == '<a>écho</a>'
4027
    assert (
4028
        run(template='<a>{{ form_var_string }}</a>', content_type='application/octet-stream') == '<a>écho</a>'
4029
    )
4030
    assert run(template='<a>{{ form_var_string }}</a>', filename='/foo/template.svg') == '<a>écho</a>'
4031

  
4032
    # unknown file format
4033
    with pytest.raises(UploadValidationError):
4034
        run(
4035
            template='<a>{{ form_var_string }}</a>',
4036
            filename='/foo/template.txt',
4037
            content_type='application/octet-stream',
4038
        )
4039

  
4040
    # malformed XML
4041
    assert not LoggedError or LoggedError.count() == 0
4042
    assert run(template='<a>{{ form_var_string }}<a>') == '<a>écho<a>'
4043
    # on error in the XML correctness no exception is raised but an error is logged
4044
    assert not LoggedError or LoggedError.count() == 1
4045

  
4046

  
3990 4047
@pytest.mark.parametrize('filename', ['template-form-details.odt', 'template-form-details-no-styles.odt'])
3991 4048
def test_export_to_model_form_details_section(pub, filename):
3992 4049
    BlockDef.wipe()
wcs/wf/export_to_model.py
282 282
            fp = upload.get_file()
283 283
        else:
284 284
            raise UploadValidationError('unknown upload object %r' % upload)
285

  
286
        # RTF
285 287
        if upload.content_type and upload.content_type == 'application/rtf':
286 288
            return 'rtf'
287 289
        if (
......
292 294
        if fp.read(10).startswith(b'{\\rtf'):
293 295
            fp.seek(0)
294 296
            return 'rtf'
297

  
298
        # OpenDocument
295 299
        fp.seek(0)
296 300
        if upload.content_type and upload.content_type.startswith('application/vnd.oasis.opendocument.'):
297 301
            return 'opendocument'
......
302 306
                return 'opendocument'
303 307
        if is_opendocument(fp):
304 308
            return 'opendocument'
305
        raise UploadValidationError(_('Only RTF and OpenDocument files can be used'))
309

  
310
        # XML
311
        fp.seek(0)
312
        xml_prefix = fp.read(1)
313
        fp.seek(0)
314
        if (upload.content_type and upload.content_type in ('text/xml', 'application/xml')) or (
315
            upload.base_filename and upload.base_filename.endswith('.xml') and xml_prefix == b'<'
316
        ):
317
            return 'xml'
318
        raise UploadValidationError(_('Only OpenDocument and XML files can be used'))
306 319

  
307 320
    def get_parameters(self):
308 321
        parameters = ('model_file',)
......
486 499
            outstream = self.apply_rtf_template_to_formdata(formdata)
487 500
        elif kind == 'opendocument':
488 501
            outstream = self.apply_od_template_to_formdata(formdata)
502
        elif kind == 'xml':
503
            outstream = self.apply_text_template_to_formdata(formdata)
489 504
        else:
490 505
            raise Exception('unsupported model kind %r' % kind)
491
        if self.convert_to_pdf:
492
            if transform_to_pdf is None:
493
                raise Exception('libreoffice is missing')
494
            return transform_to_pdf(outstream)
506
        if kind == 'xml':
507
            outstream.seek(0)
508
            try:
509
                ET.parse(outstream)
510
            except ET.ParseError as e:
511
                get_publisher().record_error(
512
                    _('The rendered template is not a valid XML document.'), formdata=formdata, exception=e
513
                )
514
                # we do not reraise to let people see the result of the
515
                # templating to debug the XML correctness
516
            finally:
517
                outstream.seek(0)
518
        else:
519
            if self.convert_to_pdf:
520
                if transform_to_pdf is None:
521
                    raise Exception('libreoffice is missing')
522
                return transform_to_pdf(outstream)
495 523
        return outstream
496 524

  
525
    def apply_text_template_to_formdata(self, formdata):
526
        return io.BytesIO(
527
            force_bytes(
528
                template_on_formdata(
529
                    formdata,
530
                    self.model_file.get_file().read().decode(errors='surrogateescape'),
531
                )
532
            )
533
        )
534

  
497 535
    def apply_rtf_template_to_formdata(self, formdata):
498 536
        try:
499 537
            # force ezt_only=True because an RTF file may contain {{ characters
500
-