Projet

Général

Profil

0001-general-remove-support-for-advanced-fargo-features-1.patch

Frédéric Péters, 01 avril 2017 18:01

Télécharger (52,6 ko)

Voir les différences:

Subject: [PATCH 1/2] general: remove support for advanced fargo features
 (#15720)

 tests/test_backoffice_pages.py            | 240 ------------------------------
 tests/test_fields.py                      |   3 +-
 tests/test_form_pages.py                  |  98 ------------
 tests/test_formdata.py                    | 120 ---------------
 tests/test_formdef.py                     |  43 +++---
 tests/test_formdef_import.py              |  15 --
 wcs/backoffice/management.py              |   2 +-
 wcs/fields.py                             |  46 ++----
 wcs/forms/common.py                       |  57 +------
 wcs/portfolio.py                          |  88 -----------
 wcs/qommon/form.py                        | 114 ++------------
 wcs/qommon/static/css/qommon.css          |  10 --
 wcs/qommon/static/js/qommon.fileupload.js |  45 +-----
 13 files changed, 45 insertions(+), 836 deletions(-)
tests/test_backoffice_pages.py
10 10

  
11 11
import pytest
12 12
from webtest import Upload
13
import mock
14 13

  
15 14
from quixote import cleanup, get_publisher
16 15
from wcs.qommon import errors, sessions
17 16
from qommon.ident.password_accounts import PasswordAccount
18
from qommon.misc import json_loads
19 17
from wcs.qommon.http_request import HTTPRequest
20 18
from wcs.roles import Role
21 19
from wcs.workflows import (Workflow, CommentableWorkflowStatusItem,
......
2500 2498
    assert resp.body == 'foo(%s);' % menu_json_str
2501 2499
    assert resp.headers['content-type'] == 'application/javascript'
2502 2500

  
2503
def test_backoffice_file_field_fargo_no_metadata(pub, fargo_url):
2504
    document_type = {
2505
        'id': 'justificatif-de-domicile',
2506
        'fargo': True,
2507
        'mimetypes': ['application/pdf'],
2508
        'label': 'Justificatif de domicile',
2509
    }
2510
    user = create_user(pub, is_admin=True)
2511
    user.name_identifiers = ['12345']
2512
    user.store()
2513
    FormDef.wipe()
2514
    formdef = FormDef()
2515
    formdef.name = 'form title'
2516
    formdef.fields = [fields.FileField(
2517
        id='0', label='1st field', type='file',
2518
        document_type=document_type)]
2519
    formdef.store()
2520
    formdef.data_class().wipe()
2521
    upload = Upload('test.pdf', '%PDF-1.4', 'application/pdf')
2522
    digest = hashlib.sha256('%PDF-1.4').hexdigest()
2523
    app = login(get_app(pub))
2524
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
2525
        resp = app.get('/form-title/')
2526
        assert fargo_get.call_count == 0
2527
    resp.forms[0]['f0$file'] = upload
2528
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
2529
        resp = resp.forms[0].submit('submit')
2530
        assert fargo_get.call_count == 0
2531
    assert 'Check values then click submit.' in resp.body
2532
    resp = resp.forms[0].submit('submit').follow()
2533
    assert formdef.data_class().count() == 1
2534
    formdata = formdef.data_class().select()[0]
2535
    form_id = formdata.id
2536
    assert not hasattr(formdata.data['0'], 'metadata')
2537
    assert not '0_structured' in formdata.data
2538
    resp = app.get('/backoffice/management/form-title/%s/' % form_id)
2539
    assert not 'Validate' in resp.body
2540
    with mock.patch('wcs.portfolio.fargo_post_json') as fargo_post_json:
2541
        resp = app.get('/backoffice/management/form-title/%s/validate?field_id=0' % form_id)
2542
        assert fargo_post_json.call_count == 0
2543
    resp = resp.follow()
2544
    assert not 'Valid ' in resp.body
2545
    assert not 'Validate' in resp.body
2546

  
2547

  
2548
def test_backoffice_file_field_validation(pub, fargo_url):
2549
    document_type = {
2550
        'id': 'justificatif-de-domicile',
2551
        'fargo': True,
2552
        'mimetypes': ['application/pdf'],
2553
        'label': 'Justificatif de domicile',
2554
        'metadata': [
2555
            {'label': 'Nom', 'varname': 'nom', 'type': 'string'},
2556
            {'label': 'Prénom(s)', 'varname': 'prenoms', 'type': 'string'},
2557
            {'label': 'Numéro', 'varname': 'numero', 'type': 'string'},
2558
            {'label': 'Rue', 'varname': 'rue', 'type': 'string'},
2559
            {'label': 'Code postal', 'varname': 'code-postal', 'type': 'string'},
2560
            {'label': 'Ville', 'varname': 'ville', 'type': 'string'},
2561
        ],
2562
    }
2563
    metadata = {
2564
        'nom': 'Doe',
2565
        'prenoms': 'John',
2566
        'numero': '169',
2567
        'rue': 'rue du château',
2568
        'code-postal': '75014',
2569
        'ville': 'PARIS',
2570
    }
2571
    user = create_user(pub, is_admin=True)
2572
    user.name_identifiers = ['12345']
2573
    user.store()
2574
    FormDef.wipe()
2575
    formdef = FormDef()
2576
    formdef.name = 'form title'
2577
    formdef.fields = [fields.FileField(
2578
        id='0', label='1st field', type='file',
2579
        document_type=document_type)]
2580
    formdef.store()
2581
    formdef.data_class().wipe()
2582
    upload = Upload('test.pdf', '%PDF-1.4', 'application/pdf')
2583
    digest = hashlib.sha256('%PDF-1.4').hexdigest()
2584
    app = login(get_app(pub))
2585
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
2586
        fargo_get.return_value = {'result': 1, 'data': {'results': []}}
2587
        resp = app.get('/form-title/')
2588
        fargo_get.assert_called_once_with(
2589
            'api/validation/justificatif-de-domicile/?user_nameid=12345')
2590
    resp.forms[0]['f0$file'] = upload
2591
    for i, meta_field in enumerate(document_type['metadata']):
2592
        resp.forms[0]['f0$f%s' % i] = metadata[meta_field['varname']]
2593
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
2594
        fargo_get.return_value = {'result': 1, 'data': {'results': []}}
2595
        resp = resp.forms[0].submit('submit')
2596
        fargo_get.assert_called_once_with(
2597
            'api/validation/justificatif-de-domicile/?user_nameid=12345')
2598
    for key in metadata:
2599
        assert 'value="%s"' % metadata[key] in resp.body
2600
    assert 'Check values then click submit.' in resp.body
2601
    resp = resp.forms[0].submit('submit').follow()
2602
    for metadata_field in document_type['metadata']:
2603

  
2604
        fragment = '%s : %s' % (metadata_field['label'], metadata[metadata_field['varname']])
2605
        assert fragment in resp.body
2606
    assert formdef.data_class().count() == 1
2607
    formdata = formdef.data_class().select()[0]
2608
    form_id = formdata.id
2609
    assert formdata.data['0'].metadata == metadata
2610
    assert formdata.data['0_structured'] == metadata
2611
    resp = app.get('/backoffice/management/form-title/%s/' % form_id)
2612
    assert 'Validate' in resp.body
2613
    for metadata_field in document_type['metadata']:
2614

  
2615
        fragment = '%s : %s' % (metadata_field['label'], metadata[metadata_field['varname']])
2616
        assert fragment in resp.body
2617
    with mock.patch('wcs.portfolio.fargo_post_json') as fargo_post_json:
2618
        payload = {
2619
            'user_nameid': '12345',
2620
            'origin': 'example.net',
2621
            'creator': 'admin',
2622
            'content_hash': digest,
2623
        }
2624
        payload.update(metadata)
2625
        result = {
2626
            'result': 1,
2627
            'data': payload.copy()
2628
        }
2629
        result['data'].update({
2630
            'url': 'zob',
2631
            'created': '1970-01-01T10:10:10Z',
2632
            'start': '1970-01-01',
2633
            'end': '1978-01-01',
2634
            'display': 'John Doe, 169 rue du château, 75014 PARIS'
2635
        })
2636
        fargo_post_json.return_value = 201, result
2637
        resp = app.get('/backoffice/management/form-title/%s/validate?field_id=0' % form_id)
2638
        assert fargo_post_json.call_count == 1
2639
        assert fargo_post_json.call_args[0][0] == '/api/validation/justificatif-de-domicile/'
2640
        assert fargo_post_json.call_args[0][1] == payload
2641
    resp = resp.follow()
2642

  
2643
    assert 'Valid from 1970-01-01 to 1978-01-01' in resp.body
2644

  
2645

  
2646
def test_backoffice_file_validation_no_upload(pub, fargo_url, fargo_secret):
2647
    document_type = {
2648
        'id': 'justificatif-de-domicile',
2649
        'fargo': True,
2650
        'mimetypes': ['application/pdf'],
2651
        'label': 'Justificatif de domicile',
2652
        'metadata': [
2653
            {'label': 'Nom', 'varname': 'nom', 'type': 'string'},
2654
            {'label': 'Prénom(s)', 'varname': 'prenoms', 'type': 'string'},
2655
            {'label': 'Numéro', 'varname': 'numero', 'type': 'string'},
2656
            {'label': 'Rue', 'varname': 'rue', 'type': 'string'},
2657
            {'label': 'Code postal', 'varname': 'code-postal', 'type': 'string'},
2658
            {'label': 'Ville', 'varname': 'ville', 'type': 'string'},
2659
        ],
2660
    }
2661
    metadata = {
2662
        'nom': 'Doe',
2663
        'prenoms': 'John',
2664
        'numero': '169',
2665
        'rue': 'rue du château',
2666
        'code-postal': '75014',
2667
        'ville': 'PARIS',
2668
    }
2669
    validation = {
2670
        'url': 'zob',
2671
        'creator': 'admin',
2672
        'created': '1970-01-01T10:10:10Z',
2673
        'start': '1970-01-01',
2674
        'end': '1978-01-01',
2675
        'display': 'John Doe, 169 rue du château, 75014 PARIS'
2676
    }
2677
    validation.update(metadata)
2678

  
2679
    user = create_user(pub, is_admin=True)
2680
    user.name_identifiers = ['12345']
2681
    user.store()
2682
    FormDef.wipe()
2683
    formdef = FormDef()
2684
    formdef.name = 'form title'
2685
    formdef.fields = [fields.FileField(
2686
        id='0', label='1st field', type='file',
2687
        document_type=document_type)]
2688
    formdef.store()
2689
    formdef.data_class().wipe()
2690
    app = login(get_app(pub))
2691
    return_value = {'result': 1, 'data': {'results': [validation]}}
2692
    with mock.patch('wcs.portfolio.http_get_page') as http_get_page:
2693
        http_get_page.return_value = None, 200, json.dumps(return_value), None
2694
        resp = app.get('/form-title/')
2695
        assert http_get_page.call_count == 1
2696
        assert http_get_page.call_args[0][0].startswith(
2697
            'http://fargo.example.net/api/validation/justificatif-de-domicile/?user_nameid=12345')
2698
        assert validation['display'] in resp.body
2699
    resp.forms[0]['f0$validation_url'] = 'zob'
2700
    for i, meta_field in enumerate(document_type['metadata']):
2701
        resp.forms[0]['f0$f%s' % i] = metadata[meta_field['varname']]
2702
    with mock.patch('wcs.portfolio.http_get_page') as http_get_page:
2703
        return_value2 = {
2704
            'result': 1,
2705
            'data': validation,
2706
        }
2707

  
2708
        def side_effect(url):
2709
            if url.startswith('http://fargo.example.net/zob'):
2710
                return None, 200, json.dumps(return_value2), None
2711
            else:
2712
                return None, 200, json.dumps(return_value), None
2713
        http_get_page.side_effect = side_effect
2714
        resp = resp.forms[0].submit('submit')
2715
        assert http_get_page.call_count == 3
2716
        assert 'api/validation/justificatif-de-domicile/?user_nameid=12345' in http_get_page.call_args_list[0][0][0]
2717
        assert http_get_page.call_args_list[1][0][0].startswith('http://fargo.example.net/zob')
2718
        assert http_get_page.call_args_list[2][0][0].startswith('http://fargo.example.net/zob')
2719
        for key in metadata:
2720
            assert 'value="%s"' % metadata[key] in resp.body
2721
        assert 'Check values then click submit.' in resp.body
2722
        resp = resp.forms[0].submit('submit').follow()
2723
    assert formdef.data_class().count() == 1
2724
    formdata = formdef.data_class().select()[0]
2725
    form_id = formdata.id
2726
    assert formdata.data['0'].metadata == validation
2727
    assert formdata.data['0_structured'] == validation
2728
    for metadata_field in document_type['metadata']:
2729

  
2730
        fragment = '%s : %s' % (metadata_field['label'], metadata[metadata_field['varname']])
2731
        assert fragment in resp.body
2732
    resp = app.get('/backoffice/management/form-title/%s/' % form_id)
2733
    assert not 'Validate' in resp.body
2734
    for metadata_field in document_type['metadata']:
2735

  
2736
        fragment = '%s : %s' % (metadata_field['label'], metadata[metadata_field['varname']])
2737
        assert fragment in resp.body
2738
    assert 'Valid from 1970-01-01 to 1978-01-01' in resp.body
2739

  
2740

  
2741 2501
def test_360_user_view(pub):
2742 2502
    if not pub.is_using_postgresql():
2743 2503
        pytest.skip('this requires SQL')
tests/test_fields.py
6 6
import pytest
7 7

  
8 8
from quixote import cleanup
9
from quixote.http_request import HTTPRequest, Upload
9
from quixote.http_request import Upload
10
from qommon.http_request import HTTPRequest
10 11
from wcs.qommon import sessions
11 12
from wcs import fields
12 13
from wcs.qommon.form import Form
tests/test_form_pages.py
1
# -*- coding: utf-8 -*-
2 1
import json
3 2
import pytest
4 3
import hashlib
......
3074 3073
    assert formdef.data_class().select()[0].data['3'] == '1'
3075 3074
    assert formdef.data_class().select()[0].data['3_display'] == 'barbar'
3076 3075

  
3077
def test_file_field_validation(pub, fargo_url):
3078
    document_type = {
3079
        'id': 'justificatif-de-domicile',
3080
        'fargo': True,
3081
        'label': 'Justificatif de domicile',
3082
        'metadata': [
3083
            {'label': 'Nom', 'varname': 'nom', 'type': 'string'},
3084
            {'label': 'Prénom(s)', 'varname': 'prenoms', 'type': 'string'},
3085
            {'label': 'Numéro', 'varname': 'numero', 'type': 'string'},
3086
            {'label': 'Rue', 'varname': 'rue', 'type': 'string'},
3087
            {'label': 'Code postal', 'varname': 'code-postal', 'type': 'string'},
3088
            {'label': 'Ville', 'varname': 'ville', 'type': 'string'},
3089
        ],
3090
    }
3091
    metadata = {
3092
        'nom': 'Doe',
3093
        'prenoms': 'John',
3094
        'numero': '169',
3095
        'rue': 'rue du château',
3096
        'code-postal': '75014',
3097
        'ville': 'PARIS',
3098
    }
3099
    user = create_user(pub)
3100
    user.name_identifiers = ['12345']
3101
    user.store()
3102
    FormDef.wipe()
3103
    formdef = FormDef()
3104
    formdef.name = 'form title'
3105
    formdef.fields = [fields.FileField(
3106
        id='0', label='1st field', type='file',
3107
        document_type=document_type)
3108
    ]
3109
    formdef.store()
3110
    formdef.data_class().wipe()
3111
    upload = Upload('test.pdf', '%PDF-1.4', 'application/pdf')
3112
    app = login(get_app(pub), username='foo', password='foo')
3113
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
3114
        fargo_get.return_value = {'result': 1, 'data': {'results': []}}
3115
        resp = app.get('/form-title/')
3116
        fargo_get.assert_called_once_with(
3117
            'api/validation/justificatif-de-domicile/?user_nameid=12345')
3118
    resp.forms[0]['f0$file'] = upload
3119
    for i, meta_field in enumerate(document_type['metadata']):
3120
        resp.forms[0]['f0$f%s' % i] = metadata[meta_field['varname']]
3121
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
3122
        fargo_get.return_value = {'result': 1, 'data': {'results': []}}
3123
        resp = resp.forms[0].submit('submit')
3124
        fargo_get.assert_called_once_with(
3125
            'api/validation/justificatif-de-domicile/?user_nameid=12345')
3126
    assert 'Check values then click submit.' in resp.body
3127
    resp = resp.forms[0].submit('submit')
3128
    assert resp.status_int == 302
3129
    resp = resp.follow()
3130
    assert 'The form has been recorded' in resp.body
3131
    assert formdef.data_class().count() == 1
3132
    formdata = formdef.data_class().select()[0]
3133
    assert formdata.data['0'].metadata == metadata
3134
    assert formdata.data['0_structured'] == metadata
3135

  
3136

  
3137
def test_file_field_fargo_no_metadata(pub, fargo_url):
3138
    document_type = {
3139
        'id': 'justificatif-de-domicile',
3140
        'fargo': True,
3141
        'label': 'Justificatif de domicile',
3142
    }
3143
    user = create_user(pub)
3144
    user.name_identifiers = ['12345']
3145
    user.store()
3146
    FormDef.wipe()
3147
    formdef = FormDef()
3148
    formdef.name = 'form title'
3149
    formdef.fields = [fields.FileField(
3150
        id='0', label='1st field', type='file',
3151
        document_type=document_type)
3152
    ]
3153
    formdef.store()
3154
    formdef.data_class().wipe()
3155
    upload = Upload('test.pdf', '%PDF-1.4', 'application/pdf')
3156
    app = login(get_app(pub), username='foo', password='foo')
3157
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
3158
        resp = app.get('/form-title/')
3159
        assert fargo_get.call_count == 0
3160
    resp.forms[0]['f0$file'] = upload
3161
    with mock.patch('wcs.portfolio.fargo_get') as fargo_get:
3162
        resp = resp.forms[0].submit('submit')
3163
        assert fargo_get.call_count == 0
3164
    assert 'Check values then click submit.' in resp.body
3165
    resp = resp.forms[0].submit('submit')
3166
    assert resp.status_int == 302
3167
    resp = resp.follow()
3168
    assert 'The form has been recorded' in resp.body
3169
    assert formdef.data_class().count() == 1
3170
    formdata = formdef.data_class().select()[0]
3171
    assert not hasattr(formdata.data['0'], 'metadata')
3172
    assert not '0_structured' in formdata.data
3173

  
3174 3076
def test_form_string_field_autocomplete(pub):
3175 3077
    formdef = create_formdef()
3176 3078
    formdef.fields = [fields.StringField(id='0', label='string', type='string', required=False)]
tests/test_formdata.py
1
# -*- coding: utf-8 -*-
2 1
import pytest
3 2
import sys
4 3
import shutil
......
15 14
from wcs.wf.anonymise import AnonymiseWorkflowStatusItem
16 15
from wcs.wf.wscall import JournalWsCallErrorPart
17 16
from wcs.wf.register_comment import JournalEvolutionPart
18
from wcs.qommon.form import NoUpload
19
import mock
20 17

  
21 18
from utilities import create_temporary_pub, clean_temporary_pub
22 19

  
......
159 156
    assert substvars.get('form_var_foo_url').endswith('/foobar/1/download?f=0')
160 157
    assert isinstance(substvars.get('form_var_foo_raw'), Upload)
161 158

  
162
    formdata.data = {'0': None}
163
    substvars = formdata.get_substitution_variables()
164
    assert substvars['form_var_foo'] is None
165
    assert substvars['form_var_foo_raw'] is None
166
    assert substvars['form_var_foo_url'] is None
167

  
168
    formdata.data = {}
169
    substvars = formdata.get_substitution_variables()
170
    assert substvars['form_var_foo'] is None
171
    assert substvars['form_var_foo_raw'] is None
172
    assert substvars['form_var_foo_url'] is None
173

  
174
def test_file_field_fargo_no_metadata(pub):
175
    document_types = {
176
        'justificatif-de-domicile': {
177
            'id': 'justificatif-de-domicile',
178
            'fargo': True,
179
            'label': 'Justificatif de domicile',
180
        }
181
    }
182
    formdef.data_class().wipe()
183
    formdef.fields = [fields.FileField(id='0', label='file', varname='foo',
184
                                       document_type=document_types['justificatif-de-domicile'])]
185
    formdef.store()
186
    formdata = formdef.data_class()()
187
    upload = Upload('test.txt', 'text/plain', 'ascii')
188
    upload.receive(['first line', 'second line'])
189
    formdata.data = {'0': upload}
190
    formdata.id = 1
191
    substvars = formdata.get_substitution_variables()
192
    assert substvars.get('form_var_foo') == 'test.txt'
193
    assert substvars.get('form_var_foo_url').endswith('/foobar/1/download?f=0')
194
    assert isinstance(substvars.get('form_var_foo_raw'), Upload)
195

  
196

  
197
def test_file_field_with_metadata(pub):
198
    document_types = {
199
        'justificatif-de-domicile': {
200
            'id': 'justificatif-de-domicile',
201
            'fargo': True,
202
            'label': 'Justificatif de domicile',
203
            'metadata': [
204
                {'label': 'Nom', 'varname': 'nom', 'type': 'string'},
205
                {'label': 'Prénom(s)', 'varname': 'prenoms', 'type': 'string'},
206
                {'label': 'Numéro', 'varname': 'numero', 'type': 'string'},
207
                {'label': 'Rue', 'varname': 'rue', 'type': 'string'},
208
                {'label': 'Code postal', 'varname': 'code-postal', 'type': 'string'},
209
                {'label': 'Ville', 'varname': 'ville', 'type': 'string'},
210
            ],
211
        }
212
    }
213
    formdef.data_class().wipe()
214
    formdef.fields = [fields.FileField(id='0', label='file', varname='foo',
215
                                       document_type=document_types['justificatif-de-domicile'])]
216
    formdef.store()
217
    formdata = formdef.data_class()()
218
    upload = Upload('test.txt', 'text/plain', 'ascii')
219
    upload.receive(['first line', 'second line'])
220
    upload.metadata = {
221
        'nom': 'Doe',
222
        'prenoms': 'John',
223
        'numero': '169',
224
        'rue': 'rue du château',
225
        'code-postal': '75014',
226
        'ville': 'PARIS',
227
    }
228
    formdata.data = {'0': upload, '0_structured': upload.metadata}
229
    formdata.id = 1
230
    substvars = formdata.get_substitution_variables()
231
    assert substvars.get('form_var_foo') == 'test.txt'
232
    assert substvars.get('form_var_foo_url').endswith('/foobar/1/download?f=0')
233
    assert isinstance(substvars.get('form_var_foo_raw'), Upload)
234
    for key in upload.metadata:
235
        assert substvars.get('form_var_foo_%s' % key) == upload.metadata[key]
236

  
237

  
238
def test_file_field_no_file_with_metadata(pub):
239
    document_types = {
240
        'justificatif-de-domicile': {
241
            'id': 'justificatif-de-domicile',
242
            'fargo': True,
243
            'label': 'Justificatif de domicile',
244
            'metadata': [
245
                {'label': 'Nom', 'varname': 'nom', 'type': 'string'},
246
                {'label': 'Prénom(s)', 'varname': 'prenoms', 'type': 'string'},
247
                {'label': 'Numéro', 'varname': 'numero', 'type': 'string'},
248
                {'label': 'Rue', 'varname': 'rue', 'type': 'string'},
249
                {'label': 'Code postal', 'varname': 'code-postal', 'type': 'string'},
250
                {'label': 'Ville', 'varname': 'ville', 'type': 'string'},
251
            ],
252
        }
253
    }
254
    formdef.data_class().wipe()
255
    formdef.fields = [fields.FileField(id='0', label='file', varname='foo',
256
                                       document_type=document_types['justificatif-de-domicile'])]
257
    formdef.store()
258
    formdata = formdef.data_class()()
259
    metadata = {
260
        'nom': 'Doe',
261
        'prenoms': 'John',
262
        'numero': '169',
263
        'rue': 'rue du château',
264
        'code-postal': '75014',
265
        'ville': 'PARIS',
266
    }
267
    with mock.patch('wcs.portfolio.get_validation', return_value=metadata):
268
        upload = NoUpload('http://whatever.com/')
269
    formdata.data = {'0': upload, '0_structured': upload.metadata}
270
    formdata.id = 1
271
    substvars = formdata.get_substitution_variables()
272
    assert isinstance(substvars.get('form_var_foo'), NoUpload)
273
    assert substvars['form_var_foo_url'] is None
274
    assert isinstance(substvars.get('form_var_foo_raw'), NoUpload)
275
    for key in upload.metadata:
276
        assert substvars.get('form_var_foo_%s' % key) == upload.metadata[key]
277

  
278

  
279 159
def test_get_submitter(pub):
280 160
    formdef.data_class().wipe()
281 161
    formdef.fields = [fields.StringField(id='0', label='email', varname='foo',
tests/test_formdef.py
6 6

  
7 7
import pytest
8 8

  
9
from mock import patch
10

  
11 9
from quixote import cleanup
12 10
from wcs import formdef
13 11
from wcs.formdef import FormDef
......
170 168
                'application/vnd.ms-excel',
171 169
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
172 170
             'label': 'Documents'}}
173
    with patch('wcs.portfolio.get_document_types') as get_document_types:
174
        get_document_types.return_value = {
175
                'justificatif-de-domicile': {
176
                    'id': 'justificatif-de-domicile',
177
                    'label': 'Justificatif de domicile',
178
                    'fargo': True,
179
                },
180
        }
181
        FormDef.wipe()
182
        formdef = FormDef()
183
        formdef.name = 'foo'
184
        formdef.fields = [
185
                FileField(type='file', id='1', label='images & docs'),
186
                FileField(type='file', id='2', label='images')]
187
        formdef.fields[0].__dict__['file_type'] = ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
188
        formdef.fields[1].__dict__['file_type'] = ['image/*']
189
        formdef.store()
190
        formdef = FormDef.get(1)
191
        assert 'file_type' not in formdef.fields[0].__dict__
192
        assert formdef.fields[0].document_type
193
        assert formdef.fields[0].document_type['id'] == '_legacy'
194
        assert formdef.fields[0].document_type['mimetypes'] == ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
195
        assert formdef.fields[1].document_type['label'] == 'Image files'
196
        assert formdef.fields[0].document_type['label'] == 'Image files, Documents'
171

  
172
    FormDef.wipe()
173
    formdef = FormDef()
174
    formdef.name = 'foo'
175
    formdef.fields = [
176
            FileField(type='file', id='1', label='images & docs'),
177
            FileField(type='file', id='2', label='images')]
178
    formdef.fields[0].__dict__['file_type'] = ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
179
    formdef.fields[1].__dict__['file_type'] = ['image/*']
180
    formdef.store()
181
    formdef = FormDef.get(1)
182
    assert 'file_type' not in formdef.fields[0].__dict__
183
    assert formdef.fields[0].document_type
184
    assert formdef.fields[0].document_type['id'] == '_legacy'
185
    assert formdef.fields[0].document_type['mimetypes'] == ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
186
    assert formdef.fields[1].document_type['label'] == 'Image files'
187
    assert formdef.fields[0].document_type['label'] == 'Image files, Documents'
tests/test_formdef_import.py
243 243
    assert_xml_import_export_works(formdef)
244 244
    assert_json_import_export_works(formdef, include_id=True)
245 245
    assert_json_import_export_works(formdef)
246
    formdef = FormDef()
247
    formdef.name = 'foo'
248
    formdef.fields = [fields.FileField(type='file', id='1', document_type={
249
        'id': 'justificatif-de-domicile',
250
        'fargo': True,
251
        'mimetypes': ['application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'image/*'],
252
        'metadata': [
253
            {'varname': 'nom', 'label': 'Nom', 'type': 'string'},
254
            {'varname': 'rue', 'label': 'Rue', 'type': 'string'},
255
        ]
256
    })]
257
    assert_xml_import_export_works(formdef, include_id=True)
258
    assert_xml_import_export_works(formdef)
259
    assert_json_import_export_works(formdef, include_id=True)
260
    assert_json_import_export_works(formdef)
261 246

  
262 247
def test_invalid_field_type():
263 248
    formdef = FormDef()
wcs/backoffice/management.py
1838 1838

  
1839 1839

  
1840 1840
class FormBackOfficeStatusPage(FormStatusPage):
1841
    _q_exports_orig = ['', 'download', 'json', 'action', 'inspect', 'validate']
1841
    _q_exports_orig = ['', 'download', 'json', 'action', 'inspect']
1842 1842
    form_page_class = FormFillPage
1843 1843

  
1844 1844
    def html_top(self, title = None):
wcs/fields.py
15 15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import datetime
18
import json
19 18
import time
20 19
import random
21 20
import re
......
754 753
        self.document_type = self.document_type or {}
755 754

  
756 755
    @property
757
    def metadata(self):
758
        return self.document_type.get('metadata', [])
759

  
760
    @property
761 756
    def file_type(self):
762
        return self.document_type.get('mimetypes', [])
757
        return (self.document_type or {}).get('mimetypes', [])
763 758

  
764 759
    def fill_admin_form(self, form):
765 760
        WidgetField.fill_admin_form(self, form)
766 761
        document_types = self.get_document_types()
767
        cur_dt = self.document_type
762
        cur_dt = self.document_type or {}
768 763
        # SingleSelectWidget compare the value and not the keys, so if we want
769 764
        # the current value not to be hidden, we must reset it with the corresponding
770 765
        # value from settings based on the 'id'
......
780 775
        form.add(FileSizeWidget, 'max_file_size', title=_('Max file size'),
781 776
                value=self.max_file_size,
782 777
                advanced=not(self.max_file_size))
783
        form.add(CheckboxWidget, 'allow_portfolio_picking',
784
                title=_('Allow user to pick a file from a portfolio'),
785
                value=self.allow_portfolio_picking,
786
                advanced=(self.allow_portfolio_picking is True))
778
        if portfolio.has_portfolio():
779
            form.add(CheckboxWidget, 'allow_portfolio_picking',
780
                    title=_('Allow user to pick a file from a portfolio'),
781
                    value=self.allow_portfolio_picking,
782
                    advanced=(self.allow_portfolio_picking is True))
787 783

  
788 784
    def get_admin_attributes(self):
789 785
        return WidgetField.get_admin_attributes(self) + [
790 786
                'document_type', 'max_file_size', 'allow_portfolio_picking']
791 787

  
792 788
    def get_view_value(self, value):
793
        r = TemplateIO(html=True)
794
        if not getattr(value, 'no_file', False):
795
            r += htmltext('<a download="%s" href="[download]?f=%s">%s</a>') % (
789
        return htmltext('<a download="%s" href="[download]?f=%s">%s</a>') % (
796 790
                value.base_filename, self.id, value)
797
        for meta_field in self.metadata:
798
            if 'varname' in meta_field:
799
                metadata_value = getattr(value, 'metadata', {}).get(meta_field['varname'], '')
800
                r += htmltext('<p>%s&nbsp;: %s</p>') % (meta_field['label'], metadata_value)
801
        return r.getvalue()
802 791

  
803 792
    def get_csv_value(self, value, hint=None, **kwargs):
804 793
        if not value:
......
833 822
            value = get_request().get_field(self.field_key)
834 823
            if value and hasattr(value, 'token'):
835 824
                get_request().form[self.field_key + '$token'] = value.token
836
        kwargs['document_type'] = self.document_type
837 825

  
838 826
    def get_document_types(self):
839 827
        document_types = {
......
852 840
        }
853 841
        # Local document types
854 842
        document_types.update(get_cfg('filetypes', {}))
855
        # Remote documents types
856
        document_types.update(portfolio.get_document_types())
857 843
        for key, document_type in document_types.iteritems():
858 844
            document_type['id'] = key
859 845
        # add current file type if it does not exist anymore in the settings
860
        cur_dt = self.document_type
846
        cur_dt = self.document_type or {}
861 847
        if cur_dt and cur_dt['id'] not in document_types:
862 848
            document_types[cur_dt['id']] = cur_dt
863 849
        return document_types
......
900 886
        if self.document_type and self.document_type.get('mimetypes'):
901 887
            old_value = self.document_type['mimetypes']
902 888
            self.document_type['mimetypes'] = '|'.join(self.document_type['mimetypes'])
903
        if self.document_type and self.document_type.get('metadata'):
904
            self.document_type['metadata'] = json.dumps(self.document_type['metadata'])
905 889
        result = super(FileField, self).export_to_xml(charset, include_id=include_id)
906 890
        if self.document_type and self.document_type.get('mimetypes'):
907 891
            self.document_type['mimetypes'] = old_value
908
        if self.document_type and self.document_type.get('metadata'):
909
            self.document_type['metadata'] = json.loads(self.document_type['metadata'])
910 892
        return result
911 893

  
912 894
    def init_with_xml(self, element, charset, include_id=False):
......
916 898
            self.document_type['mimetypes'] = self.document_type['mimetypes'].split('|')
917 899
        if self.document_type and self.document_type.get('fargo'):
918 900
            self.document_type['fargo'] = self.document_type['fargo'] == 'True'
919
        if self.document_type and self.document_type.get('metadata'):
920
            self.document_type['metadata'] = json.loads(self.document_type['metadata'])
921

  
922
    def store_structured_value(self, data, field_id):
923
        value = data.get(field_id)
924
        return getattr(value, 'metadata', {})
925

  
926
    def __setstate__(self, state):
927
        self.__dict__ = state
928
        self.document_type = self.document_type or {}
929 901

  
930 902

  
931 903
register_field_class(FileField)
wcs/forms/common.py
99 99
    def html_top(self, title = None):
100 100
        template.html_top(title = title, default_org = _('Forms'))
101 101

  
102
    def validate(self):
103
        if not portfolio.has_portfolio():
104
            return redirect('.')
105
        field_id = get_request().form.get('field_id')
106
        if not field_id:
107
            return redirect('.')
108
        for field in self.formdef.fields:
109
            if field.id == field_id:
110
                break
111
        else:
112
            return redirect('.')
113
        if field.key != 'file':
114
            return redirect('.')
115
        if not field.document_type.get('fargo', False):
116
            return redirect('.')
117
        if not field.document_type.get('metadata', []):
118
            return redirect('.')
119
        value = self.filled.data.get(field_id)
120
        portfolio.validate(self.filled, field, value)
121
        return redirect('.')
122

  
123 102
    def __init__(self, formdef, filled, register_workflow_subdirs=True):
124 103
        get_publisher().substitutions.feed(filled)
125 104
        self.formdef = formdef
......
683 662

  
684 663
    def display_file_field(self, form_url, field, value):
685 664
        r = TemplateIO(html=True)
686
        validated = None
687
        is_fargo_dt = field.document_type.get('fargo', False)
688
        has_metadata = bool(field.document_type.get('metadata', []))
689
        if portfolio.has_portfolio() and is_fargo_dt and has_metadata:
690
            validated = portfolio.is_valid(self.filled, field, value)
691
            if validated is False:
692
                extra_class = ' invalid'
693
            else:
694
                extra_class = ' valid'
695
            r += htmltext('<div class="value%s">' % extra_class)
696
        else:
697
            r += htmltext('<div class="value">')
665
        r += htmltext('<div class="value">')
698 666
        s = field.get_view_value(value)
699 667
        s = s.replace(str('[download]'), str('%sdownload' % form_url))
700 668
        r += s
701
        if validated is not None and get_request().is_in_backoffice():
702
            r += htmltext('<div class="file-validation">')
703
            if validated:
704
                creator = value.metadata['creator']
705
                created = misc.localstrftime(
706
                    time.localtime(
707
                        misc.parse_isotime(value.metadata['created'])))
708
                r += htmltext('<p class="validation-validated">%s</p>') % _(
709
                    'validated by %(creator)s on %(created)s') % {
710
                        'creator': creator, 'created': created}
711
                r += htmltext('<p>%s</p>') % (_('Valid from %(start)s to %(end)s') % {
712
                    'start': strftime(
713
                        misc.date_format(),
714
                        misc.get_as_datetime(value.metadata['start'])),
715
                    'end': strftime(
716
                        misc.date_format(),
717
                        misc.get_as_datetime(value.metadata['end'])),
718
                })
719
            elif self.filled.user:
720
                r += htmltext('<form method="post" action="./validate?field_id=%s">'
721
                              '<button>%s</button></form>') % (
722
                    field.id, _('Validate'))
723
            r += htmltext('</div>')
724 669
        r += htmltext('</div>')
725 670
        return str(r)
726 671

  
wcs/portfolio.py
80 80
    return hashlib.sha256(upload.get_content()).hexdigest()
81 81

  
82 82

  
83
def get_document_types():
84
    if not has_portfolio():
85
        return {}
86
    try:
87
        response = fargo_get('/document-types/')
88
    except ConnectionError:
89
        get_logger().warning('unable to retrieve document types from fargo')
90
        return {}
91
    if response.get('err') == 0:
92
        result = {}
93
        for schema in response['data']:
94
            d = {
95
                'id': schema['name'],
96
                'label': schema['label'],
97
                'fargo': True,
98
            }
99
            if 'mimetypes' in schema:
100
                d['mimetypes'] = schema['mimetypes']
101
            result[d['id']] = d
102
            d['metadata'] = schema.get('metadata', [])
103
        return result
104
    return {}
105

  
106

  
107
def get_validation(url):
108
    try:
109
        result = fargo_get(url)
110
    except ConnectionError:
111
        get_logger().warning('unable to retrieve validation from fargo')
112
        return None
113
    return result['data'] if result else None
114

  
115

  
116
def get_validations(document_type):
117
    request = get_request()
118
    document_type_id = document_type['id']
119
    qs = {}
120
    if not request.user:
121
        return []
122
    if request.user.name_identifiers:
123
        qs['user_nameid'] = request.user.name_identifiers[0]
124
    elif request.user.email:
125
        qs['user_email'] = request.user.email
126
    else:
127
        return []
128
    path = 'api/validation/%s/' % urllib.quote(document_type_id)
129
    try:
130
        validations = fargo_get(path + '?%s' % urllib.urlencode(qs))
131
    except ConnectionError:
132
        get_logger().warning('unable to retrieve validations from fargo')
133
        return []
134
    if validations and validations.get('data', {}).get('results', []):
135
        return validations['data']['results']
136
    return []
137

  
138

  
139
def is_valid(filled, field, upload):
140
    '''Check validation of the uploaded file with Fargo'''
141
    return 'url' in getattr(upload, 'metadata', {})
142

  
143

  
144
def validate(filled, field, upload):
145
    '''Compute link to Fargo to validate the given document'''
146
    document_type_id = field.document_type['id']
147
    url = '/api/validation/%s/' % urllib.quote(document_type_id)
148
    payload = {}
149
    if filled.user:
150
        if filled.user.name_identifiers:
151
            payload['user_nameid'] = filled.user.name_identifiers[0]
152
        else:
153
            payload['user_email'] = filled.user.email
154
    payload['origin'] = get_request().get_server()
155
    payload['creator'] = get_request().user.display_name
156
    payload['content_hash'] = sha256_of_upload(upload)
157
    for meta_field in field.metadata:
158
        if 'varname' in meta_field:
159
            payload[meta_field['varname']] = upload.metadata.get(meta_field['varname'], '')
160
    try:
161
        status, response = fargo_post_json(url, payload)
162
    except ConnectionError:
163
        get_logger().warning('unable to validate document on fargo for %s', filled.get_display_id())
164
        return
165
    if status == 201:
166
        upload.metadata = response['data']
167
        filled.data['%s_structured' % field.id] = upload.metadata
168
        filled.store()
169

  
170

  
171 83
def push_document(user, filename, stream):
172 84
    if not user:
173 85
        return
wcs/qommon/form.py
65 65
import misc
66 66
from strftime import strftime
67 67
from publisher import get_cfg
68
from wcs import portfolio
69 68
from . import ezt
70 69

  
71 70
QuixoteForm = Form
......
601 600
            self.value = None
602 601

  
603 602

  
604
class NoUpload(object):
605
    no_file = True
606
    metadata = None
607

  
608
    def __init__(self, validation_url):
609
        self.metadata = portfolio.get_validation(validation_url)
610

  
611

  
612 603
class FileWithPreviewWidget(CompositeWidget):
613 604
    """Widget that proposes a File Upload widget but that stores the file
614 605
    ondisk so it has a "readonly" mode where the filename is shown."""
......
617 608
    max_file_size = None
618 609
    file_type = None
619 610

  
620
    max_file_size_bytes = None  # will be filled automatically
611
    max_file_size_bytes = None # will be filled automatically
621 612

  
622 613
    def __init__(self, name, value=None, **kwargs):
623
        from wcs import fields
624

  
625 614
        CompositeWidget.__init__(self, name, value, **kwargs)
626 615
        self.value = value
627
        self.document_type = kwargs.pop('document_type', None) or {}
628 616
        self.readonly = kwargs.get('readonly')
629 617
        self.max_file_size = kwargs.pop('max_file_size', None)
630 618
        self.allow_portfolio_picking = kwargs.pop('allow_portfolio_picking', True)
......
635 623
            hint = ''
636 624
            if self.allow_portfolio_picking:
637 625
                root_url = get_publisher().get_root_url()
638
                if (portfolio.has_portfolio()
639
                        and get_request().user
640
                        and not self.readonly):
626
                if get_request().user:
641 627
                    get_response().add_javascript(['fargo.js'])
642 628
                    params = (root_url,
643 629
                              _('Pick a file from the portfolio'),
......
657 643
                # this could be used for client size validation of file size
658 644
                attrs['data-max-file-size'] = str(self.max_file_size_bytes)
659 645
            self.add(FileWidget, 'file', hint=hint, render_br=False, attrs=attrs)
660
        if self.document_type.get('metadata'):
661
            if self.readonly:
662
                self.add(HiddenWidget, 'validation_url')
663
            else:
664
                validations = portfolio.get_validations(self.document_type)
665
                if validations:
666
                    options = [('', _('Known documents'), '')]
667
                    options += [(v['url'], v['display'], v['url']) for v in validations]
668
                    for validation in validations:
669
                        for i, meta_field in enumerate(self.metadata):
670
                            # translate varname to f<self.id>$f<subwidget.id>
671
                            if meta_field['varname'] in validation:
672
                                value = validation.pop(meta_field['varname'])
673
                                validation['f%s' % i] = value
674
                    self.add(SingleSelectWidget, 'validation_url', options=options,
675
                             attrs={'data-validations': json.dumps(validations)})
676
            for i, meta_field in enumerate(self.metadata):
677
                field = fields.get_field_class_by_type(meta_field.get('type', 'string'))()
678
                field.id = i
679
                field.init_with_json(meta_field, include_id=False)
680
                if meta_field.get('varname'):
681
                    subvalue = getattr(value, 'metadata', {}).get(meta_field['varname'])
682
                else:
683
                    subvalue = None
684
                # required only if composite field is required
685
                field.required = field.required and self.required
686
                field.extra_css_class = 'subwidget'
687
                if self.readonly:
688
                    # preview
689
                    field.add_to_view_form(self, subvalue)
690
                else:
691
                    field.add_to_form(self, subvalue)
692 646
        if value:
693 647
            self.set_value(value)
694 648

  
......
704 658
                self.get_widget('token').set_value(self.value.token)
705 659

  
706 660
    def render_content(self):
707
        get_response().add_javascript(['jquery.js', 'jquery-ui.js', 'jquery.iframe-transport.js',
708
                                       'jquery.fileupload.js', 'qommon.fileupload.js'])
661
        get_response().add_javascript(['jquery.js', 'jquery-ui.js',
662
                        'jquery.iframe-transport.js', 'jquery.fileupload.js',
663
                        'qommon.fileupload.js'])
709 664

  
710 665
        temp = get_session().get_tempfile(self.get('token')) or {}
711 666

  
712 667
        r = TemplateIO(html=True)
713
        if self.get_widget('file'):
714
            r += self.get_widget('file').render()
668
        for widget in self.get_widgets():
669
            r += widget.render()
715 670

  
716 671
        r += htmltext('<div class="fileprogress" style="display: none;">')
717 672
        r += htmltext(' <div class="bar">%s</div>' % _('Upload in progress...'))
718 673
        r += htmltext('</div>')
719
        r += htmltext('<div class="fileinfo"><span class="filename">%s</span>'
720
                      % temp.get('base_filename', ''))
674
        r += htmltext('<div class="fileinfo"><span class="filename">%s</span>' % temp.get('base_filename', ''))
721 675
        if not self.readonly:
722
            r += htmltext(' <a href="#" class="remove" title="%s">%s</a>'
723
                          % (_('Remove this file'), _('remove')))
676
            r += htmltext(' <a href="#" class="remove" title="%s">%s</a>' % (
677
                                    _('Remove this file'),
678
                                    _('remove')))
724 679
        elif temp:
725 680
            filetype = mimetypes.guess_type(temp.get('orig_filename', ''))
726 681
            include_image = False
......
736 691
                r += htmltext('<img alt="" src="tempfile?t=%s&thumbnail=1" />' %
737 692
                              self.get('token'))
738 693
        r += htmltext('</div>')
739

  
740
        for widget in self.get_widgets():
741
            if widget is self.get_widget('file'):
742
                continue
743
            r += widget.render()
744

  
745 694
        return r.getvalue()
746 695

  
747
    @property
748
    def metadata(self):
749
        return self.document_type.get('metadata', [])
750

  
751 696
    def _parse(self, request):
752 697
        self.value = None
753 698
        if self.get('token'):
754 699
            token = self.get('token')
755
        elif self.get('validation_url'):
756
            self.value = NoUpload(self.get('validation_url'))
757
            return
758 700
        elif self.get('file'):
759 701
            token = get_session().add_tempfile(self.get('file'))
760 702
            request.form[self.get_widget('token').get_name()] = token
......
763 705

  
764 706
        session = get_session()
765 707
        if token and session.tempfiles and session.tempfiles.has_key(token):
708
            temp = session.tempfiles[token]
766 709
            self.value = session.get_tempfile_content(token)
767 710

  
768 711
        if self.value is None:
769
            # there's no file, check all metadata field are empty too
770
            # if not file and required metadata field become required
771
            if (self.get_widget('file')
772
                    and not self.required
773
                    and any([self.get('f%s' % i) for i, meta_field in enumerate(self.metadata)])):
774
                self.get_widget('file').required = True
775
                self.get_widget('file').set_error(self.REQUIRED_ERROR)
776
                for i, meta_field in enumerate(self.metadata):
777
                    name = 'f%s' % i
778
                    required = meta_field.get('required', True)
779
                    if required:
780
                        widget = self.get_widget(name)
781
                        widget.required = True
782
                        if not self.get(name):
783
                            widget.set_error(self.REQUIRED_ERROR)
712
            # there's no file, the other checks are irrelevant.
784 713
            return
785 714

  
786
        # There is some file, check all required metadata files have been filled
787
        for i, meta_field in enumerate(self.metadata):
788
            name = 'f%s' % i
789
            required = meta_field.get('required', True)
790
            if required:
791
                widget = self.get_widget(name)
792
                widget.required = True
793
                if not self.get(name):
794
                    widget.set_error(self.REQUIRED_ERROR)
795

  
796
        if self.metadata:
797
            self.value.metadata = {}
798
            for i, meta_field in enumerate(self.metadata):
799
                name = 'f%s' % i
800
                if 'varname' in meta_field:
801
                    self.value.metadata[meta_field['varname']] = self.get(name)
802

  
803 715
        # Don't trust the browser supplied MIME type, update the Upload object
804 716
        # with a MIME type created with magic (or based on the extension if the
805 717
        # module is missing).
wcs/qommon/static/css/qommon.css
87 87
	display: inline-block;
88 88
}
89 89

  
90
/* nested widgets */
91
.widget .subwidget {
92
	padding-left: 2em;
93
}
94
div.FileWithPreviewWidget .validation {
95
	display: inline-block;
96
	font-size: xx-small;
97
	margin-right: 2em;
98
}
99

  
100 90
p.use-file-from-fargo span {
101 91
	border-bottom: 1px dotted #999;
102 92
	cursor: pointer;
wcs/qommon/static/js/qommon.fileupload.js
7 7
        } else {
8 8
            $(base_widget).find('.fileinfo').hide();
9 9
        }
10
        function disable() {
11
            base_widget.find('.subwidget input').prop('disabled', true);
12
            $('form').on('submit', function () {
13
                $('input').prop('disabled', false);
14
            });
15
        }
16
        function enable() {
17
            if (base_widget.find('.subwidget input:disabled').length) {
18
                base_widget.find('.subwidget input').val('');
19
                base_widget.find('.subwidget input').prop('disabled', false);
20
            }
21
        }
22 10
        $(this).find('input[type=file]').fileupload({
23 11
            dataType: 'json',
24 12
            add: function (e, data) {
......
32 20
                $(base_widget).find('.fileprogress').hide();
33 21
                $(base_widget).find('.filename').text(data.result[0].name);
34 22
                $(base_widget).find('.fileinfo').show();
35
                $(base_widget).find('input[name$="$token"]').val(data.result[0].token);
36
                $(base_widget).find('select[name$="$validation_url"]').val('');
37
                enable();
23
                $(base_widget).find('input[type=hidden]').val(data.result[0].token);
38 24
                $(base_widget).parents('form').find('input[name=submit]').prop('disabled', false);
39 25
                $(this).hide();
40 26
                $(base_widget).find('.use-file-from-fargo').hide();
......
45 31
            }
46 32
        });
47 33
        $(this).find('a.remove').click(function() {
48
            $(base_widget).find('input[name$="$token"]').val('');
34
            $(base_widget).find('input[type=hidden]').val('');
49 35
            $(base_widget).find('.fileinfo').hide();
50 36
            $(base_widget).find('input[type=file]').show();
51 37
            $(base_widget).find('.use-file-from-fargo').show();
......
55 41
            $(base_widget).find('input[type=file]').click();
56 42
            return false;
57 43
        });
58
        if ($(this).find('select[name$="$validation_url"] option:selected').val()) {
59
            disable();
60
        }
61
        $(this).find('select[name$="$validation_url"]').on('change', function() {
62
            var url = $(this).find(':selected').val();
63
            if (url) {
64
                var validations = $(this).data('validations');
65

  
66
                for (var i = 0; i < validations.length; i++) {
67
                    if (validations[i].url == url) {
68
                        base_widget.find('a.remove').trigger('click');
69
                        for (var item in validations[i]) {
70
                            if (! item) {
71
                                continue;
72
                            }
73
                            var $input = base_widget.find('input[name$="$' + item + '"]');
74
                            if ($input.length) {
75
                                $input.val(validations[i][item]);
76
                            }
77
                        }
78
                        disable();
79
                    }
80
                }
81
            } else {
82
                enable();
83
            }
84
        });
85 44
    });
86 45
});
87
-