Projet

Général

Profil

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

Benjamin Dauvergne, 02 septembre 2021 13:23

Télécharger (6,98 ko)

Voir les différences:

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

 tests/test_workflows.py   | 50 +++++++++++++++++++++++++++++++++++++--
 wcs/wf/export_to_model.py | 50 +++++++++++++++++++++++++++++++++++----
 2 files changed, 94 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 (
......
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
......
3987 3987
    assert b'>A &lt;&gt; name<' in new_content
3988 3988

  
3989 3989

  
3990
def test_export_to_model_xml(pub):
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[0].filename) as fd:
4018
            return fd.read()
4019

  
4020
    # unknown file format
4021
    with pytest.raises(UploadValidationError):
4022
        run(
4023
            template='<a>{{ form_var_string }}</a>',
4024
            filename='/foo/template.txt',
4025
            content_type='application/octet-stream',
4026
        )
4027

  
4028
    # good XML
4029
    assert run(template='<a>{{ form_var_string }}</a>') == '<a>écho</a>'
4030

  
4031
    # malformed XML
4032
    with pytest.raises(TemplatingError):
4033
        run(template='<a>{{ form_var_string }}<a>')
4034

  
4035

  
3990 4036
@pytest.mark.parametrize('filename', ['template-form-details.odt', 'template-form-details-no-styles.odt'])
3991 4037
def test_export_to_model_form_details_section(pub, filename):
3992 4038
    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
        if (upload.content_type and upload.content_type in ('text/xml', 'application/xml')) or (
312
            upload.content_type is None and upload.base_filename and upload.base_filename.endswith('.rtf')
313
        ):
314
            return 'xml'
305 315
        raise UploadValidationError(_('Only RTF and OpenDocument files can be used'))
306 316

  
307 317
    def get_parameters(self):
......
486 496
            outstream = self.apply_rtf_template_to_formdata(formdata)
487 497
        elif kind == 'opendocument':
488 498
            outstream = self.apply_od_template_to_formdata(formdata)
499
        elif kind == 'xml':
500
            outstream = self.apply_text_template_to_formdata(formdata)
489 501
        else:
490 502
            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)
503
        if kind == 'xml':
504
            outstream.seek(0)
505
            try:
506
                ET.parse(outstream)
507
            except ET.ParseError as e:
508
                get_publisher().record_error(
509
                    _('Error in template for export to model'), formdata=formdata, exception=e
510
                )
511
                raise TemplatingError(_('Error in template: output is not valid XML (%s)') % str(e))
512
            finally:
513
                outstream.seek(0)
514
        else:
515
            if self.convert_to_pdf:
516
                if transform_to_pdf is None:
517
                    raise Exception('libreoffice is missing')
518
                return transform_to_pdf(outstream)
495 519
        return outstream
496 520

  
521
    def apply_text_template_to_formdata(self, formdata):
522
        try:
523
            # force ezt_only=True because an RTF file may contain {{ characters
524
            # and would be seen as a Django template
525
            return io.BytesIO(
526
                force_bytes(
527
                    template_on_formdata(
528
                        formdata,
529
                        self.model_file.get_file().read().decode(errors='surrogateescape'),
530
                    )
531
                )
532
            )
533
        except TemplateError as e:
534
            get_publisher().record_error(
535
                _('Error in template for export to model'), formdata=formdata, exception=e
536
            )
537
            raise TemplatingError(_('Error in template: %s') % str(e))
538

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