Projet

Général

Profil

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

Benjamin Dauvergne, 02 septembre 2021 15:36

Télécharger (7,79 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 | 54 ++++++++++++++++++++++++++++++++---
 2 files changed, 106 insertions(+), 7 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 (
......
60 60
from wcs.wf.criticality import MODE_DEC, MODE_INC, MODE_SET, ModifyCriticalityWorkflowStatusItem
61 61
from wcs.wf.dispatch import DispatchWorkflowStatusItem
62 62
from wcs.wf.edit_carddata import EditCarddataWorkflowStatusItem
63
from wcs.wf.export_to_model import ExportToModel, transform_to_pdf
63
from wcs.wf.export_to_model import ExportToModel, TemplatingError, transform_to_pdf
64 64
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
65 65
from wcs.wf.geolocate import GeolocateWorkflowStatusItem
66 66
from wcs.wf.jump import JumpWorkflowStatusItem, _apply_timeouts
......
3779 3779
    formdata.data = {'3': upload}
3780 3780
    formdata.just_created()
3781 3781
    formdata.store()
3782
    pub.substitutions.feed(formdata)
3783 3782

  
3784 3783
    item = ExportToModel()
3785 3784
    item.convert_to_pdf = False
......
3987 3986
    assert b'>A &lt;&gt; name<' in new_content
3988 3987

  
3989 3988

  
3989
def test_export_to_model_xml(two_pubs):
3990
    pub = two_pubs
3991
    formdef = FormDef()
3992
    formdef.name = 'foo-export-to-template-with-django'
3993
    formdef.fields = [
3994
        StringField(id='1', label='String', type='string', varname='string'),
3995
    ]
3996
    formdef.store()
3997
    formdata = formdef.data_class()()
3998
    formdata.data = {'1': 'écho'}
3999
    formdata.just_created()
4000
    formdata.store()
4001

  
4002
    # good XML
4003
    item = ExportToModel()
4004
    item.method = 'non-interactive'
4005
    item.attach_to_history = True
4006

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

  
4020
    # good XML
4021
    assert run(template='<a>{{ form_var_string }}</a>') == '<a>écho</a>'
4022
    assert (
4023
        run(template='<a>{{ form_var_string }}</a>', content_type='application/octet-stream') == '<a>écho</a>'
4024
    )
4025
    assert run(template='<a>{{ form_var_string }}</a>', filename='/foo/template.svg') == '<a>écho</a>'
4026

  
4027
    # unknown file format
4028
    with pytest.raises(UploadValidationError):
4029
        run(
4030
            template='<a>{{ form_var_string }}</a>',
4031
            filename='/foo/template.txt',
4032
            content_type='application/octet-stream',
4033
        )
4034

  
4035
    # malformed XML
4036
    LoggedError = pub.loggederror_class
4037
    assert not LoggedError or LoggedError.count() == 0
4038
    assert run(template='<a>{{ form_var_string }}<a>') == '<a>écho<a>'
4039
    # on error in the XML correctness no exception is raised but an error is logged
4040
    assert not LoggedError or LoggedError.count() == 1
4041

  
4042

  
3990 4043
@pytest.mark.parametrize('filename', ['template-form-details.odt', 'template-form-details-no-styles.odt'])
3991 4044
def test_export_to_model_form_details_section(pub, filename):
3992 4045
    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'
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'
305 318
        raise UploadValidationError(_('Only RTF and OpenDocument files can be used'))
306 319

  
307 320
    def get_parameters(self):
......
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
                    _('Error in template for export to model'), 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
        try:
527
            # force ezt_only=True because an RTF file may contain {{ characters
528
            # and would be seen as a Django template
529
            return io.BytesIO(
530
                force_bytes(
531
                    template_on_formdata(
532
                        formdata,
533
                        self.model_file.get_file().read().decode(errors='surrogateescape'),
534
                    )
535
                )
536
            )
537
        except TemplateError as e:
538
            get_publisher().record_error(
539
                _('Error in template for export to model'), formdata=formdata, exception=e
540
            )
541
            raise TemplatingError(_('Error in template: %s') % str(e))
542

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