Projet

Général

Profil

0001-field-display-attachment-utf-8-filenames-34783.patch

Nicolas Roche (absent jusqu'au 3 avril), 09 octobre 2019 10:42

Télécharger (20,6 ko)

Voir les différences:

Subject: [PATCH] field: display attachment utf-8 filenames (#34783)

 tests/test_admin_pages.py                     |  4 +-
 tests/test_fields.py                          |  5 +--
 tests/test_form_pages.py                      | 42 +++++++++++++------
 tests/test_formdata.py                        |  3 +-
 tests/test_formdef_import.py                  |  2 +-
 tests/test_sessions.py                        | 17 ++++++++
 tests/test_workflow_import.py                 |  2 +-
 tests/test_workflows.py                       |  8 ++--
 wcs/compat.py                                 |  3 +-
 wcs/formdata.py                               |  2 +-
 wcs/formdef.py                                |  2 +-
 wcs/qommon/form.py                            |  2 +-
 wcs/qommon/http_request.py                    | 25 +++++++++++
 .../templates/qommon/forms/widgets/file.html  |  2 +-
 wcs/root.py                                   |  2 +-
 15 files changed, 88 insertions(+), 33 deletions(-)
tests/test_admin_pages.py
24 24
import mock
25 25

  
26 26
from quixote import cleanup, get_publisher
27
from quixote.http_request import Upload as QuixoteUpload
28 27

  
29 28
from wcs.qommon import errors, sessions
30 29
from wcs.qommon.form import UploadedFile
31 30
from wcs.qommon.ident.password_accounts import PasswordAccount
32 31
from wcs.qommon.http_request import HTTPRequest
32
from wcs.qommon.http_request import Upload as QommonUpload
33 33
from wcs.qommon.template import get_current_theme
34 34
from wcs.qommon.bounces import Bounce
35 35
from wcs.admin.settings import UserFieldsFormDef
......
4154 4154
    st1 = wf.add_status('Status1', 'st1')
4155 4155
    export_to = ExportToModel()
4156 4156
    export_to.label = 'test'
4157
    upload = QuixoteUpload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
4157
    upload = QommonUpload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
4158 4158
    file_content = '''PK\x03\x04\x14\x00\x00\x08\x00\x00\'l\x8eG^\xc62\x0c\'\x00'''
4159 4159
    upload.fp = StringIO.StringIO()
4160 4160
    upload.fp.write(file_content)
tests/test_fields.py
7 7
import pytest
8 8

  
9 9
from quixote import cleanup
10
from quixote.http_request import Upload
11
from wcs.qommon.http_request import HTTPRequest
10
from wcs.qommon.http_request import HTTPRequest, Upload
12 11
from wcs.qommon import sessions
13 12
from wcs import fields
14 13
from wcs.qommon.form import Form
......
134 133

  
135 134
def test_file():
136 135
    upload = Upload('/foo/bar', content_type='text/plain')
137
    assert fields.FileField().get_csv_value(upload) == ['/foo/bar']
136
    assert fields.FileField().get_csv_value(upload) == ['bar']
138 137

  
139 138
def test_page():
140 139
    formdef = FormDef()
tests/test_form_pages.py
19 19
except ImportError:
20 20
    Image = None
21 21

  
22
from quixote.http_request import Upload as QuixoteUpload
23 22
from wcs.qommon.emails import docutils
24 23
from wcs.qommon.form import UploadedFile
25 24
from wcs.qommon.ident.password_accounts import PasswordAccount
25
from wcs.qommon.http_request import Upload as QommonUpload
26 26
from wcs.carddef import CardDef
27 27
from wcs.formdef import FormDef
28 28
from wcs.workflows import (Workflow, EditableWorkflowStatusItem,
......
2680 2680
    assert 'fargo.js' not in resp.body
2681 2681
    assert 'use-file-from-fargo' not in resp.body
2682 2682

  
2683
def test_form_file_field_upload(pub):
2684
    user = create_user(pub)
2685
    formdef = create_formdef()
2686
    formdef.fields = [fields.FileField(id='0', type='file')]
2687
    formdef.store()
2688
    formdef.data_class().wipe()
2689

  
2690
    upload = Upload(u'C:\\ding\\dong\\téêèst👀.txt', 'foobar', 'text/plain')
2691

  
2692
    resp = get_app(pub).get('/test/')
2693
    resp.forms[0]['f0$file'] = upload
2694
    resp = resp.forms[0].submit('submit')
2695
    assert 'Check values then click submit.' in resp.body
2696
    assert 'dong' not in resp.text
2697
    assert u'téêèst👀.txt' in resp.text
2698

  
2683 2699
def test_form_file_field_submit(pub):
2684 2700
    formdef = create_formdef()
2685 2701
    formdef.fields = [fields.FileField(id='0', label='file')]
......
3149 3165
    export_to = ExportToModel()
3150 3166
    export_to.convert_to_pdf = False
3151 3167
    export_to.label = 'create doc'
3152
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3168
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3153 3169
    upload.fp = StringIO.StringIO()
3154 3170
    upload.fp.write('HELLO WORLD')
3155 3171
    upload.fp.seek(0)
......
3197 3213

  
3198 3214
    # change export model to now be a RTF file, do the action again on the same form and
3199 3215
    # check that both the old .odt file and the new .rtf file are there and valid.
3200
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3216
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3201 3217
    upload.fp = StringIO.StringIO()
3202 3218
    upload.fp.write('HELLO NEW WORLD')
3203 3219
    upload.fp.seek(0)
......
3213 3229
    assert resp.click('test.rtf', index=1).follow().body == 'HELLO NEW WORLD'
3214 3230

  
3215 3231
    # use substitution variables on rtf: only ezt format is accepted
3216
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3232
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3217 3233
    upload.fp = StringIO.StringIO()
3218 3234
    upload.fp.write('HELLO {{DJANGO}} WORLD [form_name]')
3219 3235
    upload.fp.seek(0)
......
3241 3257
    export_to.label = 'create doc'
3242 3258
    template_filename = os.path.join(os.path.dirname(__file__), odt_template)
3243 3259
    template = open(template_filename).read()
3244
    upload = QuixoteUpload('/foo/' + odt_template, content_type='application/octet-stream')
3260
    upload = QommonUpload('/foo/' + odt_template, content_type='application/octet-stream')
3245 3261
    upload.fp = StringIO.StringIO()
3246 3262
    upload.fp.write(template)
3247 3263
    upload.fp.seek(0)
......
3303 3319
        assert_equal_zip(StringIO.StringIO(resp.body), f)
3304 3320

  
3305 3321
    # change file content, same name
3306
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3322
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3307 3323
    upload.fp = StringIO.StringIO()
3308 3324
    upload.fp.write('HELLO NEW WORLD')
3309 3325
    upload.fp.seek(0)
......
3330 3346
    export_to.varname = 'created_doc'
3331 3347
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
3332 3348
    template = open(template_filename).read()
3333
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
3349
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
3334 3350
    upload.fp = StringIO.StringIO()
3335 3351
    upload.fp.write(template)
3336 3352
    upload.fp.seek(0)
......
3380 3396
        assert_equal_zip(StringIO.StringIO(resp.body), f)
3381 3397

  
3382 3398
    # change file content, same name
3383
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3399
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3384 3400
    upload.fp = StringIO.StringIO()
3385 3401
    upload.fp.write('HELLO NEW WORLD')
3386 3402
    upload.fp.seek(0)
......
3448 3464
    export_to.varname = 'created_doc'
3449 3465
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
3450 3466
    template = open(template_filename).read()
3451
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
3467
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
3452 3468
    upload.fp = StringIO.StringIO()
3453 3469
    upload.fp.write(template)
3454 3470
    upload.fp.seek(0)
......
3515 3531
    export_to.varname = 'created_doc'
3516 3532
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
3517 3533
    template = open(template_filename).read()
3518
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
3534
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
3519 3535
    upload.fp = StringIO.StringIO()
3520 3536
    upload.fp.write(template)
3521 3537
    upload.fp.seek(0)
......
3603 3619
    export_to.method = 'non-interactive'
3604 3620
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
3605 3621
    template = open(template_filename).read()
3606
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
3622
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
3607 3623
    upload.fp = StringIO.StringIO()
3608 3624
    upload.fp.write(template)
3609 3625
    upload.fp.seek(0)
......
3663 3679
    export_to.method = 'non-interactive'
3664 3680
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
3665 3681
    template = open(template_filename).read()
3666
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
3682
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
3667 3683
    upload.fp = StringIO.StringIO()
3668 3684
    upload.fp.write(template)
3669 3685
    upload.fp.seek(0)
......
3729 3745
    st1.visibility = ['_receiver']
3730 3746
    export_to = ExportToModel()
3731 3747
    export_to.label = 'create doc'
3732
    upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
3748
    upload = QommonUpload('/foo/test.rtf', content_type='application/rtf')
3733 3749
    upload.fp = StringIO.StringIO()
3734 3750
    upload.fp.write('HELLO WORLD')
3735 3751
    upload.fp.seek(0)
tests/test_formdata.py
6 6
import time
7 7

  
8 8
from quixote import cleanup
9
from quixote.http_request import Upload
10 9
from wcs.qommon.template import Template
11 10
from wcs.qommon.form import PicklableUpload
12
from wcs.qommon.http_request import HTTPRequest
11
from wcs.qommon.http_request import HTTPRequest, Upload
13 12
from wcs import fields, formdef
14 13
from wcs.categories import Category
15 14
from wcs.conditions import Condition
tests/test_formdef_import.py
195 195
    assert fd2.workflow_options == formdef.workflow_options
196 196

  
197 197
def test_workflow_options_with_file():
198
    from quixote.http_request import Upload
199 198
    from wcs.qommon.form import UploadedFile
199
    from wcs.qommon.http_request import Upload
200 200

  
201 201
    upload = Upload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
202 202
    file_content = '''PK\x03\x04\x14\x00\x00\x08\x00\x00\'l\x8eG^\xc62\x0c\'\x00'''
tests/test_sessions.py
1
# -*- coding: utf-8 -*-
2

  
1 3
import os
2 4
import shutil
3 5
import time
......
199 201
    assert pub.session_manager.session_class.count() == 1
200 202
    session_id = pub.session_manager.session_class.select()[0].id
201 203
    assert 'COM1' in resp.body
204

  
205
def test_tmp_upload(pub, user, app):
206
    user_agent = {'User-agent': 'Mozilla/5.0'}
207
    files = [('field0', u'C:\\ding\\dong\\téêèst👀.txt', r'file content')]
208

  
209
    # submit a file using the endpoint
210
    resp = app.post('/tmp-upload', headers=user_agent, upload_files=files)
211
    assert resp.json[0]['name'] == u'téêèst👀.txt'
212
    token = resp.json[0]['token']
213

  
214
    # retrieve the file from session
215
    session = pub.session_manager.session_class.select()[0]
216
    tempfile = session.get_tempfile_path(token)
217
    with open(tempfile) as handler:
218
        assert handler.read() == r'file content'
tests/test_workflow_import.py
256 256
    wf.store()
257 257
    st1 = wf.add_status('Status1', 'st1')
258 258

  
259
    from quixote.http_request import Upload
260 259
    from wcs.qommon.form import UploadedFile
260
    from wcs.qommon.http_request import Upload
261 261
    from wcs.workflows import ExportToModel
262 262

  
263 263
    export_to = ExportToModel()
tests/test_workflows.py
14 14

  
15 15
from quixote import cleanup, get_response
16 16
from wcs.qommon.errors import ConnectionError
17
from quixote.http_request import Upload as QuixoteUpload
18 17
from wcs.qommon.http_request import HTTPRequest
18
from wcs.qommon.http_request import Upload as QommonUpload
19 19
from wcs.qommon.form import *
20 20

  
21 21
from wcs.formdef import FormDef
......
2887 2887
    item.method = 'non-interactive'
2888 2888
    template_filename = os.path.join(os.path.dirname(__file__), 'template-with-image.odt')
2889 2889
    template = open(template_filename).read()
2890
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
2890
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
2891 2891
    upload.fp = StringIO()
2892 2892
    upload.fp.write(template)
2893 2893
    upload.fp.seek(0)
......
2948 2948
    item.convert_to_pdf = False
2949 2949
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
2950 2950
    template = open(template_filename).read()
2951
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
2951
    upload = QommonUpload('/foo/template.odt', content_type='application/octet-stream')
2952 2952
    upload.fp = StringIO()
2953 2953
    upload.fp.write(template)
2954 2954
    upload.fp.seek(0)
......
3005 3005
    item.attach_to_history = True
3006 3006
    template_filename = os.path.join(os.path.dirname(__file__), 'template-django.odt')
3007 3007
    template = open(template_filename).read()
3008
    upload = QuixoteUpload('/foo/template-django.odt', content_type='application/octet-stream')
3008
    upload = QommonUpload('/foo/template-django.odt', content_type='application/octet-stream')
3009 3009
    upload.fp = StringIO()
3010 3010
    upload.fp.write(template)
3011 3011
    upload.fp.seek(0)
wcs/compat.py
23 23

  
24 24
from quixote import get_publisher, get_request
25 25
from quixote.errors import PublishError
26
from quixote.http_request import Upload
27 26

  
28 27
from django.http import HttpResponse
29 28
from django.conf import settings
......
34 33
from .qommon import template
35 34
from .qommon.publisher import get_cfg, set_publisher_class
36 35
from .publisher import WcsPublisher
37
from .qommon.http_request import HTTPRequest
36
from .qommon.http_request import HTTPRequest, Upload
38 37
from .qommon.http_response import HTTPResponse
39 38

  
40 39

  
wcs/formdata.py
23 23
import time
24 24

  
25 25
from quixote import get_request, get_publisher, get_session
26
from quixote.http_request import Upload
27 26

  
28 27
from .qommon import _
29 28
from .qommon.storage import StorableObject, Intersects, Contains
30 29
from .qommon import misc
31 30
from .qommon.evalutils import make_datetime
31
from .qommon.http_request import Upload
32 32
from .qommon.publisher import get_cfg
33 33
from .qommon.substitution import Substitutions, invalidate_substitution_cache
34 34
from .qommon.template import Template
wcs/formdef.py
25 25
import datetime
26 26

  
27 27
from quixote import get_request, get_publisher
28
from quixote.http_request import Upload
29 28

  
30 29
from .qommon import _
31 30
from .qommon.storage import StorableObject, fix_key
32 31
from .qommon.cron import CronJob
33 32
from .qommon.form import *
33
from .qommon.http_request import Upload
34 34
from .qommon.misc import simplify, get_as_datetime
35 35
from .qommon import get_cfg
36 36
from .qommon.substitution import Substitutions
wcs/qommon/form.py
57 57
import quixote.form.widget
58 58

  
59 59
from quixote import get_publisher, get_request, get_response, get_session
60
from quixote.http_request import Upload
61 60
from quixote.form import *
62 61
from quixote.html import htmltext, htmltag, htmlescape, TemplateIO
63 62
from quixote.util import randbytes
......
75 74
from . import _, ngettext
76 75
from . import misc
77 76
from .humantime import humanduration2seconds, seconds2humanduration, timewords
77
from .http_request import Upload
78 78
from .misc import strftime, C_, HAS_PDFTOPPM
79 79
from .publisher import get_cfg
80 80
from .template_utils import render_block_to_string
wcs/qommon/http_request.py
181 181

  
182 182
    def trace(self, msg):
183 183
        print('%.4f' % (time.time() - self.t0), msg)
184

  
185

  
186
class Upload(quixote.http_request.Upload):
187
    def __init__(self, orig_filename, content_type=None, charset=None):
188
        if orig_filename:
189
            bspos = orig_filename.rfind("\\")
190
            cpos = orig_filename.rfind(":")
191
            spos = orig_filename.rfind("/")
192
            if bspos != -1:                 # eg. "\foo\bar" or "D:\ding\dong"
193
                filename = orig_filename[bspos+1:]
194
            elif cpos != -1:                # eg. "C:foo" or ":ding:dong:foo"
195
                filename = orig_filename[cpos+1:]
196
            elif spos != -1:                # eg. "foo/bar/baz" or "/tmp/blah"
197
                filename = orig_filename[spos+1:]
198
            else:
199
                filename = orig_filename
200

  
201
            self.orig_filename = filename
202
            self.base_filename = quixote.http_request.make_safe_filename(filename)
203
        else:
204
            self.orig_filename = None
205
            self.base_filename = None
206
        self.content_type = content_type
207
        self.charset = charset
208
        self.fp = None
wcs/qommon/templates/qommon/forms/widgets/file.html
21 21
       data-error="{% trans "Error during upload." %}"></div>
22 22
</div>
23 23
<div class="fileinfo {% if widget.readonly and widget.has_tempfile_image %}thumbnail{% endif %}">
24
  <span class="filename">{{ widget.tempfile.base_filename }}</span>
24
  <span class="filename">{{ widget.tempfile.orig_filename }}</span>
25 25
{% if not widget.readonly %}
26 26
  <a href="#" class="remove" title="{% trans 'Remove this file' %}">{% trans "remove" %}</a>
27 27
{% elif widget.has_tempfile_image %}
wcs/root.py
296 296
        for k, v in get_request().form.items():
297 297
            if hasattr(v, 'fp'):
298 298
                tempfile = get_session().add_tempfile(v)
299
                results.append({'name': tempfile.get('base_filename'),
299
                results.append({'name': tempfile.get('orig_filename'),
300 300
                                'type': tempfile.get('content_type'),
301 301
                                'size': tempfile.get('size'),
302 302
                                'token': tempfile.get('token')})
303
-