Projet

Général

Profil

0001-backoffice-use-a-single-page-for-all-processing-afte.patch

Frédéric Péters, 29 décembre 2020 17:35

Télécharger (23,7 ko)

Voir les différences:

Subject: [PATCH] backoffice: use a single page for all processing afterjob
 pages (#49772)

 tests/admin_pages/test_all.py                 |  8 +-
 tests/backoffice_pages/test_carddata.py       |  1 -
 tests/backoffice_pages/test_export.py         |  4 +-
 wcs/admin/forms.py                            | 67 ++-------------
 wcs/admin/settings.py                         | 44 +++-------
 wcs/backoffice/data_management.py             | 47 ++++++-----
 wcs/backoffice/management.py                  | 82 ++++++-------------
 wcs/backoffice/root.py                        | 16 +++-
 wcs/qommon/afterjobs.py                       |  3 +
 wcs/qommon/static/css/dc2/admin.css           |  1 +
 .../wcs/backoffice/card-data-import-form.html | 28 -------
 wcs/templates/wcs/backoffice/processing.html  | 18 ++++
 12 files changed, 111 insertions(+), 208 deletions(-)
 create mode 100644 wcs/templates/wcs/backoffice/processing.html
tests/admin_pages/test_all.py
654 654
    resp = resp.form.submit('cancel')
655 655
    resp = app.get('/backoffice/settings/export')
656 656
    resp = resp.form.submit('submit')
657
    assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
657
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
658 658
    job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
659 659
    resp = resp.follow()
660 660
    assert 'completed' in resp.text
......
702 702

  
703 703
    resp = app.get('/backoffice/settings/export')
704 704
    resp = resp.form.submit('submit')
705
    assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
705
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
706 706
    job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
707 707
    resp = resp.follow()
708 708
    resp = resp.click('Download Export')
......
782 782
    resp.form['datasources'] = False
783 783
    resp.form['wscalls'] = False
784 784
    resp = resp.form.submit('submit')
785
    assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
785
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
786 786
    job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
787 787
    resp = resp.follow()
788 788
    resp = resp.click('Download Export')
......
816 816
    pub.write_cfg()
817 817
    resp = app.get('/backoffice/settings/export')
818 818
    resp = resp.form.submit('submit')
819
    assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
819
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
820 820
    job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
821 821
    resp = resp.follow()
822 822
    resp = resp.click('Download Export')
tests/backoffice_pages/test_carddata.py
356 356
                                   'text/csv')
357 357
    resp = resp.forms[0].submit().follow()
358 358
    assert 'Importing data into cards' in resp
359
    assert 'Column File will be ignored: type File Upload not supported.' in resp
360 359
    assert carddef.data_class().count() == 149
361 360
    card1, card2 = carddef.data_class().select(order_by='id')[:2]
362 361
    assert card1.data['1'] == '48.81;2.37'
tests/backoffice_pages/test_export.py
187 187
    app = login(get_app(pub))
188 188
    resp = app.get('/backoffice/management/form-title/')
189 189
    resp = resp.click('Export as CSV File')
190
    assert resp.location.startswith('http://example.net/backoffice/management/form-title/export?job=')
190
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
191 191
    resp = resp.follow()
192 192
    assert 'completed' in resp.text
193 193
    resp = resp.click('Download Export')
......
201 201

  
202 202
    resp = app.get('/backoffice/management/form-title/')
203 203
    resp = resp.click('Export a Spreadsheet')
204
    assert resp.location.startswith('http://example.net/backoffice/management/form-title/export?job=')
204
    assert resp.location.startswith('http://example.net/backoffice/processing?job=')
205 205
    job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
206 206
    resp = resp.follow()
207 207
    assert 'completed' in resp.text
wcs/admin/forms.py
1247 1247
        if get_publisher().is_using_postgresql():
1248 1248
            raise TraversalError()
1249 1249

  
1250
        if get_request().form.get('job'):
1251
            return self.archive_processing()
1252 1250
        if get_request().form.get('download'):
1253 1251
            return self.archive_download()
1254 1252

  
......
1315 1313
            job = get_response().add_after_job(
1316 1314
                str(N_('Archiving forms')),
1317 1315
                archiver.archive)
1318
            return redirect('archive?job=%s' % job.id)
1316
            job.done_action_url = self.formdef.get_admin_url() + 'archive?job=%s' % job.id
1317
            job.done_action_label = _('Download Archive')
1318
            job.store()
1319
            return redirect(job.get_processing_url())
1319 1320
        else:
1320 1321
            archiver.archive()
1321 1322

  
......
1325 1326
                'attachment; filename=%s-archive.wcs' % self.formdef.url_name)
1326 1327
            return archiver.fd.getvalue()
1327 1328

  
1328
    def archive_processing(self):
1329
        try:
1330
            job = AfterJob.get(get_request().form.get('job'))
1331
        except KeyError:
1332
            return redirect('.')
1333

  
1334
        self.html_top(title=_('Archiving'))
1335
        r = TemplateIO(html=True)
1336
        r += get_session().display_message()
1337
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
1338
        r += htmltext('<dl class="job-status">')
1339
        r += htmltext('<dt>')
1340
        r += _(job.label)
1341
        r += htmltext('</dt>')
1342
        r += htmltext('<dd>')
1343
        r += htmltext('<span class="afterjob" id="%s">') % job.id
1344
        r += _(job.status)
1345
        r += htmltext('</span>')
1346
        r += htmltext('</dd>')
1347
        r += htmltext('</dl>')
1348

  
1349
        r += htmltext('<div class="done">')
1350
        r += htmltext('<a href="archive?download=%s">%s</a>') % (job.id, _('Download Archive'))
1351
        r += htmltext('</div>')
1352
        return r.getvalue()
1353

  
1354 1329
    def archive_download(self):
1355 1330
        try:
1356 1331
            job = AfterJob.get(get_request().form.get('download'))
......
1366 1341
        return job.file_content
1367 1342

  
1368 1343
    def anonymise(self):
1369
        if get_request().form.get('job'):
1370
            return self.anonymise_processing()
1371

  
1372 1344
        endpoints = []
1373 1345
        for status in self.formdef.workflow.get_endpoint_status():
1374 1346
            endpoints.append((str(status.id), status.name, str(status.id)))
......
1428 1400
            job = get_response().add_after_job(
1429 1401
                str(N_('Anonymising forms')),
1430 1402
                anonymiser.anonymise)
1431
            return redirect('anonymise?job=%s' % job.id)
1403
            job.done_action_url = self.formdef.get_admin_url()
1404
            job.done_action_label = _('Back')
1405
            job.store()
1406
            return redirect(job.get_processing_url())
1432 1407
        else:
1433 1408
            anonymiser.anonymise()
1434 1409

  
1435 1410
        return redirect('.')
1436 1411

  
1437
    def anonymise_processing(self):
1438
        try:
1439
            job = AfterJob.get(get_request().form.get('job'))
1440
        except KeyError:
1441
            return redirect('.')
1442

  
1443
        html_top('forms', title=_('Anonymising'))
1444
        r = TemplateIO(html=True)
1445
        r += get_session().display_message()
1446
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
1447
        r += htmltext('<dl class="job-status">')
1448
        r += htmltext('<dt>')
1449
        r += _(job.label)
1450
        r += htmltext('</dt>')
1451
        r += htmltext('<dd>')
1452
        r += htmltext('<span class="afterjob" id="%s">') % job.id
1453
        r += _(job.status)
1454
        r += htmltext('</span>')
1455
        r += htmltext('</dd>')
1456
        r += htmltext('</dl>')
1457

  
1458
        r += htmltext('<div class="done">')
1459
        r += htmltext('<a href="./">%s</a>') % _('Back')
1460
        r += htmltext('</div>')
1461
        return r.getvalue()
1462

  
1463 1412
    def enable(self):
1464 1413
        self.formdef.disabled = False
1465 1414
        self.formdef.store(comment=_('Enable'))
wcs/admin/settings.py
858 858
        get_publisher().write_cfg()
859 859

  
860 860
    def export(self):
861
        if get_request().form.get('job') or get_request().form.get('download'):
862
            return self.export_pending()
861
        if get_request().form.get('download'):
862
            return self.export_download()
863 863

  
864 864
        form = Form(enctype="multipart/form-data")
865 865
        form.add(CheckboxWidget, 'formdefs', title = _('Forms'), value = True)
......
961 961
        job = get_response().add_after_job(
962 962
                N_('Exporting site settings'),
963 963
                exporter.export)
964
        job.done_action_url = get_request().get_url() + '?download=%s' % job.id
965
        job.done_action_label = _('Download Export')
966
        job.done_button_attributes = {'download': 'export.wcs'}
964 967
        job.store()
965
        return redirect('export?job=%s' % job.id)
968
        return redirect(job.get_processing_url())
966 969

  
967
    def export_pending(self):
968
        job_id = get_request().form.get('job') or get_request().form.get('download')
970
    def export_download(self):
971
        job_id = get_request().form.get('download')
969 972
        try:
970 973
            job = AfterJob.get(job_id)
971 974
        except KeyError:
972 975
            return redirect('.')
973 976

  
974
        if get_request().form.get('download'):
975
            response = get_response()
976
            response.set_content_type('application/x-wcs')
977
            response.set_header('content-disposition', 'attachment; filename=export.wcs')
978
            return job.file_content
979

  
980
        html_top('settings', title=_('Exporting'))
981
        r = TemplateIO(html=True)
982
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
983
        r += htmltext('<h2>%s</h2>') % _('Export')
984
        r += htmltext('<div class="section"><dl class="job-status">')
985
        r += htmltext('<dt>')
986
        r += _(job.label)
987
        r += htmltext('</dt>')
988
        r += htmltext('<dd>')
989
        r += htmltext('<span class="afterjob" id="%s">') % job.id
990
        r += _(job.status)
991
        r += htmltext('</span>')
992
        r += htmltext('</dd>')
993
        r += htmltext('</dl>')
994

  
995
        r += htmltext('<div class="done">')
996
        r += htmltext('<a download="export.wcs" href="export?download=%s">%s</a>') % (
997
                job.id, _('Download Export'))
998
        r += htmltext('</div>')
999
        r += htmltext('</div>')
1000
        return r.getvalue()
977
        response = get_response()
978
        response.set_content_type('application/x-wcs')
979
        response.set_header('content-disposition', 'attachment; filename=export.wcs')
980
        return job.file_content
1001 981

  
1002 982
    def p_import(self):
1003 983
        form = Form(enctype='multipart/form-data')
wcs/backoffice/data_management.py
188 188
        if not self.can_user_add_cards():
189 189
            raise errors.AccessForbiddenError()
190 190
        context = {
191
            'unsupported_fields': [],
192 191
            'required_fields': []
193 192
        }
194
        try:
195
            job = AfterJob.get(get_request().form.get('job'))
196
            get_response().add_javascript(['jquery.js', 'afterjob.js'])
197
            context['job'] = job
198
        except KeyError:
199
            form = Form(enctype='multipart/form-data', use_tokens=False)
200
            form.add(FileWidget, 'file', title=_('File'), required=True)
201
            form.add_submit('submit', _('Submit'))
202
            form.add_submit('cancel', _('Cancel'))
203
            if form.get_widget('cancel').parse():
204
                return redirect('.')
205

  
206
            if form.is_submitted() and not form.has_errors():
207
                try:
208
                    return self.import_csv_submit(form.get_widget('file').parse().fp)
209
                except ValueError as e:
210
                    form.set_error('file', e)
211
            context['form'] = form
193

  
194
        form = Form(enctype='multipart/form-data', use_tokens=False)
195
        form.add(FileWidget, 'file', title=_('File'), required=True)
196
        form.add_submit('submit', _('Submit'))
197
        form.add_submit('cancel', _('Cancel'))
198
        if form.get_widget('cancel').parse():
199
            return redirect('.')
200

  
201
        if form.is_submitted() and not form.has_errors():
202
            try:
203
                return self.import_csv_submit(form.get_widget('file').parse().fp)
204
            except ValueError as e:
205
                form.set_error('file', e)
212 206

  
213 207
        get_response().breadcrumb.append(('import_csv', _('Import CSV')))
214 208
        html_top('data_management', _('Import CSV'))
209
        context['form'] = form
215 210

  
216 211
        for field in self.get_import_csv_fields():
217
            if field.convert_value_from_str is None:
218
                context['unsupported_fields'].append(field)
219 212
            if not hasattr(field, 'required'):
220 213
                continue
221 214
            if field.required and field.convert_value_from_str is None:
......
293 286
        job = ImportFromCsvAfterJob(carddef=self.formdef, data_lines=data_lines)
294 287
        if afterjob:
295 288
            get_response().add_after_job(job)
296
            return redirect('import-csv?job=%s' % job.id)
289
            return redirect(job.get_processing_url())
297 290
        else:
298 291
            job.execute()
299 292

  
......
378 371
            data_instance.just_created()
379 372
            data_instance.store()
380 373
            data_instance.perform_workflow()
374

  
375
    def done_action_url(self):
376
        carddef = self.kwargs['carddef_class'].get(self.kwargs['carddef_id'])
377
        return carddef.get_url()
378

  
379
    def done_action_label(self):
380
        return _('Back to Listing')
381

  
382
    def done_button_attributes(self):
383
        return {'data-redirect-auto': 'true'}
wcs/backoffice/management.py
1963 1963
                    action_id=action['action'].id,
1964 1964
                    item_ids=item_ids))
1965 1965
        job.store()
1966
        return redirect('./?job=%s' % job.id)
1967

  
1968
    def job_multi(self):
1969
        try:
1970
            job = AfterJob.get(get_request().form.get('job'))
1971
        except KeyError:
1972
            return redirect('.')
1973

  
1974
        html_top('management', title=_('Executing Task'))
1975
        r = TemplateIO(html=True)
1976
        r += get_session().display_message()
1977
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
1978
        r += htmltext('<dl class="job-status">')
1979
        r += htmltext('<dt>')
1980
        r += job.label
1981
        r += htmltext('</dt>')
1982
        r += htmltext('<dd>')
1983
        r += htmltext('<span class="afterjob" id="%s">') % job.id
1984
        r += _(job.status)
1985
        r += htmltext('</span>')
1986
        r += htmltext('</dd>')
1987
        r += htmltext('</dl>')
1988

  
1989
        r += htmltext('<div class="done">')
1990
        r += htmltext('<a data-redirect-auto="true" href="./?%s">%s</a>') % (job.query_string, _('Back to Listing'))
1991
        r += htmltext('</div>')
1992
        return r.getvalue()
1966
        return redirect(job.get_processing_url())
1993 1967

  
1994 1968
    def csv(self):
1995 1969
        self.check_access()
......
2014 1988
        if count > self.WCS_SYNC_EXPORT_LIMIT:
2015 1989
            job = get_response().add_after_job(job)
2016 1990
            job.store()
2017
            return redirect('export?job=%s' % job.id)
1991
            return redirect(job.get_processing_url())
2018 1992
        else:
2019 1993
            job.execute()
2020 1994

  
......
2025 1999

  
2026 2000
    def export(self):
2027 2001
        self.check_access()
2028
        if get_request().form.get('download'):
2029
            return self.export_download()
2030

  
2031
        try:
2032
            job = AfterJob.get(get_request().form.get('job'))
2033
        except KeyError:
2034
            return redirect('.')
2035

  
2036
        html_top('management', title=_('Exporting'))
2037
        r = TemplateIO(html=True)
2038
        r += get_session().display_message()
2039
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
2040
        r += htmltext('<dl class="job-status">')
2041
        r += htmltext('<dt>')
2042
        r += _(job.label)
2043
        r += htmltext('</dt>')
2044
        r += htmltext('<dd>')
2045
        r += htmltext('<span class="afterjob" id="%s">') % job.id
2046
        r += _(job.status)
2047
        r += htmltext('</span>')
2048
        r += htmltext('</dd>')
2049
        r += htmltext('</dl>')
2050

  
2051
        r += htmltext('<div class="done">')
2052
        r += htmltext('<a download="%s" href="export?download=%s">%s</a>') % (
2053
                job.file_name, job.id, _('Download Export'))
2054
        r += htmltext('</div>')
2055
        return r.getvalue()
2056

  
2057
    def export_download(self):
2058 2002
        try:
2059 2003
            job = AfterJob.get(get_request().form.get('download'))
2060 2004
        except KeyError:
......
2092 2036
        if count > self.WCS_SYNC_EXPORT_LIMIT and not get_request().is_api_url():
2093 2037
            job = get_response().add_after_job(job)
2094 2038
            job.store()
2095
            return redirect('export?job=%s' % job.id)
2039
            return redirect(job.get_processing_url())
2096 2040
        else:
2097 2041
            job.execute()
2098 2042

  
......
3419 3363
            self.completion_status = '{}/{}'.format(i + 1, len(formdatas))
3420 3364
            self.store()
3421 3365

  
3366
    def done_action_url(self):
3367
        formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id'])
3368
        return formdef.get_url(backoffice=True)
3369

  
3370
    def done_action_label(self):
3371
        return _('Back to Listing')
3372

  
3373
    def done_button_attributes(self):
3374
        return {'data-redirect-auto': 'true'}
3375

  
3422 3376

  
3423 3377
class CsvExportAfterJob(AfterJob):
3424 3378
    label = N_('Exporting forms in CSV')
......
3476 3430
        self.content_type = 'text/csv'
3477 3431
        self.store()
3478 3432

  
3433
    def done_action_url(self):
3434
        formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id'])
3435
        return formdef.get_url(backoffice=True) + 'export?download=%s' % self.id
3436

  
3437
    def done_action_label(self):
3438
        return _('Download Export')
3439

  
3440
    def done_button_attributes(self):
3441
        return {'download': self.file_name}
3442

  
3479 3443

  
3480 3444
class OdsExportAfterJob(CsvExportAfterJob):
3481 3445
    def __init__(self, formdef, **kwargs):
wcs/backoffice/root.py
25 25

  
26 26
from ..qommon import misc, get_cfg
27 27
from ..qommon import errors
28
from ..qommon import template
29
from ..qommon.afterjobs import AfterJob
28 30
from ..qommon.form import *
29 31

  
30 32
from wcs.formdef import FormDef
......
44 46

  
45 47

  
46 48
class RootDirectory(BackofficeRootDirectory):
47
    _q_exports = ['', 'pending', 'statistics', ('menu.json', 'menu_json')]
49
    _q_exports = ['', 'pending', 'statistics', ('menu.json', 'menu_json'), 'processing']
48 50

  
49 51
    forms = wcs.admin.forms.FormsDirectory()
50 52
    roles = wcs.admin.roles.RolesDirectory()
......
285 287
                    'studio', 'cards', 'data'):
286 288
                menu_items[-1]['icon'] = k.strip('/')
287 289
        return menu_items
290

  
291
    def processing(self):
292
        html_top('/')
293
        try:
294
            job = AfterJob.get(get_request().form.get('job'))
295
        except KeyError:
296
            return redirect('.')
297

  
298
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
299
        return template.QommonTemplateResponse(
300
                templates=['wcs/backoffice/processing.html'],
301
                context={'job': job})
wcs/qommon/afterjobs.py
97 97
            obj_dict['job_cmd'] = None
98 98
            return obj_dict
99 99
        return self.__dict__
100

  
101
    def get_processing_url(self):
102
        return '/backoffice/processing?job=%s' % self.id
wcs/qommon/static/css/dc2/admin.css
1753 1753

  
1754 1754
div.section > dl {
1755 1755
	padding-bottom: 0;
1756
	padding-top: 0;
1756 1757
}
1757 1758

  
1758 1759
div.data-source-preview ul {
wcs/templates/wcs/backoffice/card-data-import-form.html
8 8
{% endblock %}
9 9

  
10 10
{% block content %}
11
{% if job %}
12

  
13
{% if unsupported_fields %}
14
{% for field in unsupported_fields %}
15
<div class="warningnotice">
16
  {% blocktrans with label=field.label description=field.description %}
17
  Column {{ label }} will be ignored: type {{ description }} not supported.
18
  {% endblocktrans %}
19
</div>
20
{% endfor %}
21
{% endif %}
22

  
23
<dl class="job-status">
24
  <dt>{{ job.label }}</dt>
25
  {% if warnings %}
26
  <dt>
27
    {% for warning in warnings %}
28
    <div class="warningnotice">{{ warning }}</div>
29
    {% endfor %}
30
  </dt>
31
  {% endif %}
32
  <dd><span class="afterjob" id="{{ job.id }}">{% trans job.status %}</span></dd>
33
</dl>
34
<div class="done">
35
  <a data-redirect-auto="true" href=".">{% trans "Back to Listing" %}</a>
36
</div>
37
{% else %}
38 11

  
39 12
{% if required_fields %}
40 13
<div class="errornotice">
......
51 24
<p><a href="data-sample-csv">{% trans "Download sample file for this card" %}</a></p>
52 25
{{ form.render|safe }}
53 26
{% endif %}
54
{% endif %}
55 27
{% endblock %}
wcs/templates/wcs/backoffice/processing.html
1
{% extends "wcs/backoffice/base.html" %}
2
{% load i18n %}
3

  
4
{% block appbar-title %}{% trans "Executing task..." %}{% endblock %}
5

  
6
{% block content %}
7
<div class="section">
8
<dl class="job-status">
9
  <dt>{% trans job.label %}</dt>
10
  <dd><span class="afterjob" id="{{ job.id }}">{% trans job.status %}</span></dd>
11
</dl>
12
</div>
13

  
14
<div class="done" style="display: none">
15
  <a {% for attr in job.done_button_attributes.items %}{{ attr.0 }}="{{ attr.1 }}"{% endfor %}
16
     class="button" href="{{ job.done_action_url }}">{{ job.done_action_label }}</a>
17
</div>
18
{% endblock %}
0
-