Projet

Général

Profil

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

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

Télécharger (7,61 ko)

Voir les différences:

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

 debian/control                  |  3 ++-
 passerelle/apps/solis/models.py | 38 +++++++++++++++++++++++++++++-----
 setup.py                        |  1 +
 tests/test_solis.py             | 45 ++++++++++++++++++++++++++++++++++++-----
 4 files changed, 76 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
16 16

  
17 17
import base64
18 18
import json
19
from PIL import Image
19 20
import re
21
from StringIO import StringIO
20 22
import unicodedata
21 23

  
22 24
from django.db import models
......
62 64
    return dict_
63 65

  
64 66

  
67
def convert_to_pdf(content):
68
    if content.startswith('%PDF'):
69
        return content
70
    image = Image.open(StringIO(content))
71
    if image.mode != 'RGB':
72
        # PDF cannot handle alpha (RGBA)
73
        image = image.convert('RGB')
74
    out = StringIO()
75
    image.save(out, format='PDF')
76
    return out.getvalue()
77

  
78

  
65 79
def keystore_upload_to(instance, filename):
66 80
    return '%s/%s/keystore/%s' % (instance.get_connector_slug(), instance.id, filename)
67 81

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

  
342 366
        response = self.request('asg/apa/integrationDemandeApa', data=integration_data)
343
        return {'data': response, 'sendfiles': sendfiles}
367
        return {
368
            'data': response,
369
            'files_sent': sendfiles,
370
            'files_failed_pdf_conversion': files_failed_pdf_conversion
371
        }
344 372

  
345 373
    @endpoint(name='referential', perm='can_access',
346 374
              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
-