Projet

Général

Profil

0001-solis-try-to-convert-files-to-PDF-21997.patch

Thomas Noël, 20 février 2018 17:19

Télécharger (7,96 ko)

Voir les différences:

Subject: [PATCH] solis: try to convert files to PDF (#21997)

 debian/control                  |  3 ++-
 passerelle/apps/solis/models.py | 42 +++++++++++++++++++++++++++++++++-----
 setup.py                        |  1 +
 tests/test_solis.py             | 45 ++++++++++++++++++++++++++++++++++++-----
 4 files changed, 80 insertions(+), 11 deletions(-)
debian/control
26 26
    python-cmislib (>= 0.5), python-cmislib (< 0.6),
27 27
    python-lxml,
28 28
    python-dateutil,
29
    python-pyproj
29
    python-pyproj,
30
    python-pil
30 31
Recommends: python-soappy, python-phpserialize
31 32
Description: Uniform access to multiple data sources and services (Python module)
32 33

  
passerelle/apps/solis/models.py
18 18
import json
19 19
import re
20 20
import unicodedata
21
from PIL import Image
22
from StringIO import StringIO
21 23

  
22 24
from django.db import models
23 25
from django.template.loader import get_template
......
62 64
    return dict_
63 65

  
64 66

  
67
def convert_to_pdf(content, content_type):
68
    content_type = content_type.lower()
69
    if content_type == 'application/pdf':
70
        return content
71
    if content_type.startswith('image/'):
72
        image = Image.open(StringIO(content))
73
        if image.mode != 'RGB':
74
            # PDF cannot handle alpha (RGBA)
75
            image = image.convert('RGB')
76
        out = StringIO()
77
        image.save(out, format='PDF')
78
        return out.getvalue()
79
    raise ValueError('cannot convert %s to PDF' % content_type)
80

  
81

  
65 82
def keystore_upload_to(instance, filename):
66 83
    return '%s/%s/keystore/%s' % (instance.get_connector_slug(), instance.id, filename)
67 84

  
......
302 319
        # handle specific file: and del: keys
303 320
        files = []
304 321
        delete_keys = []
322
        files_failed_pdf_conversion = []
305 323
        for key, value in payload.items():
306 324
            # extract files from payload, to send them before the request
307 325
            if key.startswith('file:'):
308
                if (isinstance(value, dict) and 'content' in value and 'content_type' in value):
309
                    filename = key[5:]
310
                    binary_content = base64.b64decode(value['content'])
311
                    files.append(('files', (filename, binary_content, value['content_type'])))
312 326
                delete_keys.append(key)
327
                if value is None:
328
                    continue
329
                filename = key[5:]
330
                if (isinstance(value, dict) and 'content' in value and 'content_type' in value):
331
                    content = base64.b64decode(value['content'])
332
                    content_type = value['content_type']
333
                    try:
334
                        pdf_content = convert_to_pdf(content, content_type)
335
                    except:
336
                        files_failed_pdf_conversion.append(filename)
337
                    else:
338
                        files.append(('files', (filename, pdf_content, 'application.pdf')))
339
                else:
340
                    files_failed_pdf_conversion.append(filename)
313 341
            # Solis doesn't accept somes values or dict-of-values if there are empty
314 342
            # (for example is there is not "conjoint"): remove all these keys if a
315 343
            # specific "del:key_prefix":true entry exists (for example "del:conjoint")
......
340 368
            integration_data['uidPiecesJointes'] = sendfiles.get('id')
341 369

  
342 370
        response = self.request('asg/apa/integrationDemandeApa', data=integration_data)
343
        return {'data': response, 'sendfiles': sendfiles}
371
        return {
372
            'data': response,
373
            'files_sent': sendfiles,
374
            'files_failed_pdf_conversion': files_failed_pdf_conversion
375
        }
344 376

  
345 377
    @endpoint(name='referential', perm='can_access',
346 378
              pattern=r'^(?P<module>[\w-]+)/(?P<name>[\w-]+)/$',
setup.py
101 101
            'feedparser',
102 102
            'lxml',
103 103
            'python-dateutil',
104
            'Pillow',
104 105
        ],
105 106
        cmdclass={
106 107
            'build': build,
tests/test_solis.py
507 507
        assert requests_post.call_args[1]['json']['demandeApa']['conjoint']['nom'] == 'Conjnom'
508 508
        assert resp.json['err'] == 0
509 509

  
510
        # add a file
510
        # add files
511 511
        requests_post.reset_mock()
512 512
        requests_post.side_effect = [
513
            utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 1}', status_code=200),
513
            utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 3}', status_code=200),
514 514
            utils.FakedResponse(content='', status_code=204)]
515 515
        demande['file:etat_civil_001.pdf'] = {
516
            'content': 'Y29pbg==',
516
            'content': 'JVBERmZha2U=',
517 517
            'content_type': 'application/pdf',
518 518
            'filename': 'whatever.pdf',
519 519
        }
520
        demande['file:etat_civil_002.pdf'] = None
520
        demande['file:etat_civil_002.pdf'] = {
521
            # jpeg, will be converted to PDF
522
            'content': '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCw'
523
                'kJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=',
524
            'content_type': 'image/jpeg',
525
            'filename': 'image.jpg',
526
        }
527
        demande['file:etat_civil_003.pdf'] = {
528
            # transparent png (RGBA), will be converted to RGB and then PDF
529
            'content': 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQ'
530
                'ABDQottAAAAABJRU5ErkJggg==',
531
            'content_type': 'image/png',
532
            'filename': 'image.png',
533
        }
534
        demande['file:etat_civil_004.pdf'] = {
535
            'content': 'Y29pbg==',  # bad content, conversion will fail
536
            'content_type': 'image/png',
537
            'filename': 'image.png',
538
        }
539
        demande['file:etat_civil_005.pdf'] = {
540
            'content': 'Y29pbg==',
541
            'content_type': 'video/mp4',  # not a image, cannot convert
542
            'filename': 'video.mp4',
543
        }
544
        demande['file:etat_civil_006.pdf'] = {
545
            'content_type': 'video/mp4',  # no content, cannot convert
546
        }
547
        demande['file:etat_civil_007.pdf'] = None
521 548
        resp = app.post_json(url, params=demande, status=200)
549
        assert requests_post.call_count == 2  # post files + demandeApa
550
        sent_files = requests_post.call_args_list[0][1]['files']
551
        assert len(sent_files) == 3
552
        for file_ in sent_files:
553
            assert file_[1][1].startswith('%PDF')
522 554
        # file entries are removed from demandeApa JSON dict
523 555
        assert 'file:etat_civil_001.pdf' not in requests_post.call_args[1]['json']['demandeApa']
524 556
        assert 'file:etat_civil_002.pdf' not in requests_post.call_args[1]['json']['demandeApa']
525 557
        assert resp.json['err'] == 0
526 558
        assert resp.json['data'] is None
527
        assert resp.json['sendfiles'] == {'id': 'foo', 'nbFichiersAcceptes': 1}
559
        assert resp.json['files_sent'] == {'id': 'foo', 'nbFichiersAcceptes': 3}
560
        assert set(resp.json['files_failed_pdf_conversion']) == set(['etat_civil_004.pdf',
561
                                                                     'etat_civil_005.pdf',
562
                                                                     'etat_civil_006.pdf'])
528 563

  
529 564
        # invalid inputs
530 565
        requests_post.reset_mock()
531
-