Projet

Général

Profil

0005-general-remove-is_using_postgresql-conditionals-6719.patch

Frédéric Péters, 11 juillet 2022 13:36

Télécharger (202 ko)

Voir les différences:

Subject: [PATCH 5/7] general: remove is_using_postgresql conditionals (#67190)

 tests/api/test_formdata.py                  |  78 ++--
 tests/api/test_formdef.py                   |   7 +-
 tests/api/test_user.py                      |   8 -
 tests/backoffice_pages/test_all.py          | 176 +++------
 tests/backoffice_pages/test_carddata.py     |   4 -
 tests/backoffice_pages/test_columns.py      |  32 --
 tests/backoffice_pages/test_custom_view.py  |   4 -
 tests/backoffice_pages/test_export.py       |   4 -
 tests/backoffice_pages/test_filters.py      | 139 +++----
 tests/backoffice_pages/test_form_inspect.py |   8 -
 tests/backoffice_pages/test_statistics.py   |  24 +-
 tests/form_pages/test_all.py                |  85 ++--
 tests/form_pages/test_block.py              |  15 +-
 tests/form_pages/test_computed_field.py     |  48 +--
 tests/form_pages/test_file_field.py         |  13 +-
 tests/form_pages/test_formdata.py           |   9 +-
 tests/form_pages/test_live.py               |  36 +-
 tests/test_carddef.py                       |  30 +-
 tests/test_datasource.py                    | 226 +++++------
 tests/test_fc_auth.py                       |   6 +-
 tests/test_formdata.py                      | 143 +++----
 tests/test_formdef.py                       |  13 +-
 tests/test_sessions.py                      |   8 -
 tests/utilities.py                          |   2 -
 tests/workflow/test_all.py                  | 408 +++++++++-----------
 tests/workflow/test_carddata.py             |  24 +-
 tests/workflow/test_formdata.py             |  57 ++-
 wcs/admin/data_sources.py                   |   2 +-
 wcs/admin/forms.py                          | 106 -----
 wcs/admin/logged_errors.py                  |   3 +-
 wcs/admin/settings.py                       |   5 +-
 wcs/api.py                                  | 235 +++++------
 wcs/backoffice/cards.py                     |   3 -
 wcs/backoffice/management.py                | 309 ++++++---------
 wcs/backoffice/submission.py                |  12 +-
 wcs/carddef.py                              |   2 +-
 wcs/ctl/delete_tenant.py                    | 118 +++---
 wcs/ctl/rebuild_indexes.py                  |  12 -
 wcs/formdata.py                             |  29 +-
 wcs/formdef.py                              |  45 +--
 wcs/forms/backoffice.py                     | 110 +-----
 wcs/publisher.py                            |   8 +-
 wcs/qommon/cron.py                          |   3 +-
 wcs/qommon/tokens.py                        |  16 +-
 wcs/sql.py                                  |  13 +-
 wcs/statistics/views.py                     |   6 -
 wcs/users.py                                |   3 -
 wcs/variables.py                            |   5 +-
 wcs/wf/jump.py                              |  41 +-
 49 files changed, 929 insertions(+), 1764 deletions(-)
tests/api/test_formdata.py
788 788
    get_app(pub).get(sign_uri('/api/forms/test/list?filter=all&offset=plop', user=local_user), status=400)
789 789
    get_app(pub).get(sign_uri('/api/forms/test/list?filter=all&limit=plop', user=local_user), status=400)
790 790

  
791
    if pub.is_using_postgresql():
792
        # just check ordering
793
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=f0', user=local_user))
794
        assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(0, 30)]
791
    # just check ordering
792
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=f0', user=local_user))
793
    assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(0, 30)]
795 794

  
796
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=-f0', user=local_user))
797
        assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(29, -1, -1)]
795
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=-f0', user=local_user))
796
    assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(29, -1, -1)]
798 797

  
799
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=foobar', user=local_user))
800
        assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(0, 30)]
798
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=foobar', user=local_user))
799
    assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(0, 30)]
801 800

  
802
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=-foobar', user=local_user))
803
        assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(29, -1, -1)]
801
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&order_by=-foobar', user=local_user))
802
    assert [d['fields']['foobar'] for d in resp.json] == ['FOO BAR %02d' % i for i in range(29, -1, -1)]
804 803

  
805
        # check fts
806
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&q=foo', user=local_user))
807
        assert len(resp.json) == 30
808
        resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&q=baz', user=local_user))
809
        assert len(resp.json) == 14
804
    # check fts
805
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&q=foo', user=local_user))
806
    assert len(resp.json) == 30
807
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on&q=baz', user=local_user))
808
    assert len(resp.json) == 14
810 809

  
811 810

  
812 811
def test_api_list_formdata_order_by_rank(pub, local_user):
813
    if not pub.is_using_postgresql():
814
        pytest.skip('this requires SQL')
815 812
    pub.role_class.wipe()
816 813
    role = pub.role_class(name='test')
817 814
    role.store()
......
938 935
    params = [
939 936
        ('eq', 'FOO 2', 1),
940 937
        ('ne', 'FOO 2', 3),
941
        ('lt', 'FOO 2', 2 if pub.is_using_postgresql() else 3),
942
        ('lte', 'FOO 2', 3 if pub.is_using_postgresql() else 4),
938
        ('lt', 'FOO 2', 2),
939
        ('lte', 'FOO 2', 3),
943 940
        ('gt', 'FOO 2', 0),
944 941
        ('gt', '42', 0),
945 942
        ('gte', 'FOO 2', 1),
......
957 954
        ('eq', '10', 1),
958 955
        ('eq', '010', 1),
959 956
        ('ne', '10', 3),
960
        ('lt', '10', 1 if pub.is_using_postgresql() else 2),
961
        ('lte', '10', 2 if pub.is_using_postgresql() else 3),
957
        ('lt', '10', 1),
958
        ('lte', '10', 2),
962 959
        ('gt', '10', 1),
963 960
        ('gt', '9', 2),
964 961
        ('gte', '10', 2),
......
1021 1018
        ('eq', '10', 1),
1022 1019
        ('eq', '010', 1),
1023 1020
        ('ne', '10', 3),
1024
        ('lt', '10', 1 if pub.is_using_postgresql() else 2),
1025
        ('lte', '10', 2 if pub.is_using_postgresql() else 3),
1021
        ('lt', '10', 1),
1022
        ('lte', '10', 2),
1026 1023
        ('gt', '10', 1),
1027 1024
        ('gt', '9', 2),
1028 1025
        ('gte', '10', 2),
......
1041 1038
    params = [
1042 1039
        ('eq', 'foo', 1),
1043 1040
        ('ne', 'foo', 3),
1044
        ('lt', 'foo', 2 if pub.is_using_postgresql() else 3),
1045
        ('lte', 'foo', 3 if pub.is_using_postgresql() else 4),
1041
        ('lt', 'foo', 2),
1042
        ('lte', 'foo', 3),
1046 1043
        ('gt', 'foo', 0),
1047 1044
        ('gt', '42', 0),
1048 1045
        ('gte', 'foo', 1),
......
1182 1179
        formdata.store()
1183 1180

  
1184 1181
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?filter-bool=false', user=local_user))
1185
    assert len(resp.json) == 2 if pub.is_using_postgresql() else 3
1182
    assert len(resp.json) == 2
1186 1183
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?filter-bool=true', user=local_user))
1187 1184
    assert len(resp.json) == 1
1188 1185
    params = [
......
1209 1206

  
1210 1207

  
1211 1208
def test_api_list_formdata_date_filter(pub, local_user):
1212
    if not pub.is_using_postgresql():
1213
        pytest.skip('this requires SQL')
1214

  
1215 1209
    pub.role_class.wipe()
1216 1210
    role = pub.role_class(name='test')
1217 1211
    role.store()
......
1412 1406

  
1413 1407

  
1414 1408
def test_api_list_formdata_block_field_filter(pub, local_user):
1415
    if not pub.is_using_postgresql():
1416
        pytest.skip('this requires SQL')
1417

  
1418 1409
    NamedDataSource.wipe()
1419 1410
    data_source = NamedDataSource(name='foobar')
1420 1411
    data_source.data_source = {
......
2142 2133
            formdata.jump_status('finished')
2143 2134
        formdata.store()
2144 2135

  
2145
    if not pub.is_using_postgresql():
2146
        resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
2147
        pytest.skip('this requires SQL')
2148
        return
2149

  
2150 2136
    # check empty content if user doesn't have the appropriate role
2151 2137
    resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user))
2152 2138
    assert 'features' in resp.json
......
2170 2156
@pytest.mark.parametrize('user', ['query-email', 'api-access'])
2171 2157
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
2172 2158
def test_api_global_listing(pub, local_user, user, auth):
2173
    if not pub.is_using_postgresql():
2174
        resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
2175
        pytest.skip('this requires SQL')
2176
        return
2177

  
2178 2159
    pub.role_class.wipe()
2179 2160
    role = pub.role_class(name='test')
2180 2161
    role.store()
......
2279 2260

  
2280 2261

  
2281 2262
def test_api_global_listing_categories_filter(pub, local_user):
2282
    if not pub.is_using_postgresql():
2283
        pytest.skip('this requires SQL')
2284
        return
2285

  
2286 2263
    Category.wipe()
2287 2264
    category1 = Category()
2288 2265
    category1.name = 'Category 1'
......
2391 2368

  
2392 2369

  
2393 2370
def test_api_include_anonymised(pub, local_user):
2394
    if not pub.is_using_postgresql():
2395
        resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
2396
        pytest.skip('this requires SQL')
2397
        return
2398

  
2399 2371
    pub.role_class.wipe()
2400 2372
    role = pub.role_class(name='test')
2401 2373
    role.store()
......
2438 2410

  
2439 2411

  
2440 2412
def test_global_forms_api_user_uuid_filter(pub, local_user):
2441
    if not pub.is_using_postgresql():
2442
        pytest.skip('this requires SQL')
2443
        return
2444

  
2445 2413
    pub.role_class.wipe()
2446 2414
    role = pub.role_class(name='test')
2447 2415
    role.store()
tests/api/test_formdef.py
177 177
        formdata.store()
178 178

  
179 179
    resp = get_app(pub).get(sign_uri('/api/formdefs/?include-count=on'))
180
    if not pub.is_using_postgresql():
181
        assert resp.json['data'][0]['count'] == 8
182
    else:
183
        # 3*4 + 2*2 + 1*1
184
        assert resp.json['data'][0]['count'] == 17
180
    # 3*4 + 2*2 + 1*1
181
    assert resp.json['data'][0]['count'] == 17
185 182

  
186 183

  
187 184
def test_formdef_list_categories_filter(pub):
tests/api/test_user.py
410 410

  
411 411

  
412 412
def test_user_forms_limit_offset(pub, local_user):
413
    if not pub.is_using_postgresql():
414
        pytest.skip('this requires SQL')
415
        return
416

  
417 413
    FormDef.wipe()
418 414
    formdef = FormDef()
419 415
    formdef.name = 'test limit offset'
......
614 610

  
615 611

  
616 612
def test_user_forms_include_accessible(pub, local_user, access):
617
    if not pub.is_using_postgresql():
618
        pytest.skip('this requires SQL')
619
        return
620

  
621 613
    pub.role_class.wipe()
622 614
    role = pub.role_class(name='Foo bar')
623 615
    role.store()
tests/backoffice_pages/test_all.py
269 269
    assert '9 open on 50' in resp.text
270 270

  
271 271
    # anonymise some formdata, they should no longer be included
272
    if pub.is_using_postgresql():
273
        formdef = FormDef.get_by_urlname('form-title')
274
        for i, formdata in enumerate(
275
            formdef.data_class().select([st.Equal('status', 'wf-finished')], order_by='id')
276
        ):
277
            if i >= 20:
278
                break
279
            formdata.anonymise()
272
    formdef = FormDef.get_by_urlname('form-title')
273
    for i, formdata in enumerate(
274
        formdef.data_class().select([st.Equal('status', 'wf-finished')], order_by='id')
275
    ):
276
        if i >= 20:
277
            break
278
        formdata.anonymise()
280 279

  
281
        for i, formdata in enumerate(
282
            formdef.data_class().select([st.Equal('status', 'wf-new')], order_by='id')
283
        ):
284
            if i >= 5:
285
                break
286
            formdata.anonymise()
280
    for i, formdata in enumerate(formdef.data_class().select([st.Equal('status', 'wf-new')], order_by='id')):
281
        if i >= 5:
282
            break
283
        formdata.anonymise()
287 284

  
288
        resp = app.get('/backoffice/management/forms')
289
        assert 'Forms in your care' in resp.text
290
        assert '4 open on 25' in resp.text
285
    resp = app.get('/backoffice/management/forms')
286
    assert 'Forms in your care' in resp.text
287
    assert '4 open on 25' in resp.text
291 288

  
292 289

  
293 290
def test_backoffice_management_css_class(pub):
......
340 337
    resp = app.get('/backoffice/management/form-title/')
341 338
    resp.forms['listing-settings']['filter'] = 'all'
342 339
    resp = resp.forms['listing-settings'].submit()
343
    if pub.is_using_postgresql():
344
        assert resp.text.count('data-link') == 20
345
    else:
346
        # not using sql -> no pagination
347
        assert resp.text.count('data-link') == 50
340
    assert resp.text.count('data-link') == 20
348 341

  
349 342
    # check status filter <select>
350 343
    resp = app.get('/backoffice/management/form-title/')
351 344
    resp.forms['listing-settings']['filter'] = 'done'
352 345
    resp = resp.forms['listing-settings'].submit()
353
    if pub.is_using_postgresql():
354
        assert resp.text.count('data-link') == 20
355
        resp = resp.click('Next Page')
356
        assert resp.text.count('data-link') == 13
357
    else:
358
        assert resp.text.count('data-link') == 33
346
    assert resp.text.count('data-link') == 20
347
    resp = resp.click('Next Page')
348
    assert resp.text.count('data-link') == 13
359 349

  
360 350
    # add an extra status to workflow and move a few formdatas to it, they
361 351
    # should then be marked as open but not waiting for actions.
......
424 414

  
425 415

  
426 416
def test_backoffice_listing_pagination(pub):
427
    if not pub.is_using_postgresql():
428
        pytest.skip('this requires SQL')
429
        return
430 417
    create_superuser(pub)
431 418
    create_environment(pub)
432 419
    app = login(get_app(pub))
......
469 456

  
470 457

  
471 458
def test_backoffice_listing_anonymised(pub):
472
    if not pub.is_using_postgresql():
473
        pytest.skip('this requires SQL')
474
        return
475 459
    create_superuser(pub)
476 460
    create_environment(pub)
477 461
    app = login(get_app(pub))
......
488 472

  
489 473

  
490 474
def test_backoffice_listing_fts(pub):
491
    if not pub.is_using_postgresql():
492
        pytest.skip('this requires SQL')
493
        return
494 475
    create_superuser(pub)
495 476
    create_environment(pub)
496 477
    formdef = FormDef.get_by_urlname('form-title')
......
1366 1347
@pytest.mark.parametrize('notify_on_errors', [True, False])
1367 1348
@pytest.mark.parametrize('record_on_errors', [True, False])
1368 1349
def test_backoffice_wscall_on_error(http_requests, pub, emails, notify_on_errors, record_on_errors):
1369
    if not pub.is_using_postgresql():
1370
        pytest.skip('this requires SQL')
1371
        return
1372

  
1373 1350
    pub.cfg['debug'] = {'error_email': 'errors@localhost.invalid'}
1374 1351
    pub.cfg['emails'] = {'from': 'from@localhost.invalid'}
1375 1352
    pub.write_cfg()
......
1986 1963

  
1987 1964

  
1988 1965
def test_global_listing(pub):
1989
    if not pub.is_using_postgresql():
1990
        pytest.skip('this requires SQL')
1991
        return
1992

  
1993 1966
    create_user(pub)
1994 1967
    create_environment(pub)
1995 1968
    app = login(get_app(pub))
......
2105 2078

  
2106 2079

  
2107 2080
def test_global_listing_parameters_from_query_string(pub):
2108
    if not pub.is_using_postgresql():
2109
        pytest.skip('this requires SQL')
2110
        return
2111

  
2112 2081
    create_user(pub)
2113 2082
    create_environment(pub)
2114 2083
    app = login(get_app(pub))
......
2131 2100

  
2132 2101

  
2133 2102
def test_global_listing_user_label(pub):
2134
    if not pub.is_using_postgresql():
2135
        pytest.skip('this requires SQL')
2136
        return
2137

  
2138 2103
    create_user(pub)
2139 2104
    FormDef.wipe()
2140 2105

  
......
2170 2135

  
2171 2136

  
2172 2137
def test_management_views_with_no_formdefs(pub):
2173
    if not pub.is_using_postgresql():
2174
        pytest.skip('this requires SQL')
2175
        return
2176

  
2177 2138
    create_user(pub)
2178 2139
    create_environment(pub)
2179 2140
    FormDef.wipe()
......
2193 2154

  
2194 2155

  
2195 2156
def test_category_in_global_listing(pub):
2196
    if not pub.is_using_postgresql():
2197
        pytest.skip('this requires SQL')
2198
        return
2199

  
2200 2157
    FormDef.wipe()
2201 2158
    Category.wipe()
2202 2159

  
......
2283 2240

  
2284 2241

  
2285 2242
def test_datetime_in_global_listing(pub):
2286
    if not pub.is_using_postgresql():
2287
        pytest.skip('this requires SQL')
2288
        return
2289

  
2290 2243
    create_user(pub)
2291 2244
    create_environment(pub)
2292 2245

  
......
2324 2277

  
2325 2278

  
2326 2279
def test_global_listing_anonymised(pub):
2327
    if not pub.is_using_postgresql():
2328
        pytest.skip('this requires SQL')
2329
        return
2330

  
2331 2280
    create_user(pub)
2332 2281
    create_environment(pub)
2333 2282
    app = login(get_app(pub))
......
2346 2295

  
2347 2296

  
2348 2297
def test_global_listing_geojson(pub):
2349
    if not pub.is_using_postgresql():
2350
        pytest.skip('this requires SQL')
2351
        return
2352

  
2353 2298
    create_user(pub)
2354 2299
    create_environment(pub)
2355 2300

  
......
2381 2326

  
2382 2327

  
2383 2328
def test_global_map(pub):
2384
    if not pub.is_using_postgresql():
2385
        pytest.skip('this requires SQL')
2386
        return
2387

  
2388 2329
    create_user(pub)
2389 2330
    create_environment(pub)
2390 2331

  
......
2447 2388
    resp = resp.form.submit()
2448 2389
    assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
2449 2390

  
2450
    if pub.is_using_postgresql():
2451
        # check looking up on a custom display_id
2452
        formdata.id_display = '999999'
2453
        formdata.store()
2454
        assert formdata.get_display_id() == '999999'
2455
        resp = app.get('/backoffice/management/').follow()
2456
        resp.form['query'] = formdata.get_display_id()
2457
        resp = resp.form.submit()
2458
        assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
2459

  
2460
        # try it from the global listing
2461
        resp = app.get('/backoffice/management/listing')
2462
        assert 'id="lookup-box"' in resp.text
2463
        resp.forms[0]['query'] = formdata.tracking_code
2464
        resp = resp.forms[0].submit()
2465
        assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
2466
        resp = resp.follow()
2467
        assert 'The form has been recorded' in resp.text
2391
    # check looking up on a custom display_id
2392
    formdata.id_display = '999999'
2393
    formdata.store()
2394
    assert formdata.get_display_id() == '999999'
2395
    resp = app.get('/backoffice/management/').follow()
2396
    resp.form['query'] = formdata.get_display_id()
2397
    resp = resp.form.submit()
2398
    assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
2468 2399

  
2469
        resp = app.get('/backoffice/management/listing')
2470
        resp.forms[0]['query'] = 'AAAAAAAA'
2471
        resp = resp.forms[0].submit()
2472
        assert resp.location == 'http://example.net/backoffice/management/listing'
2473
        resp = resp.follow()
2474
        assert 'No such tracking code or identifier.' in resp.text
2400
    # try it from the global listing
2401
    resp = app.get('/backoffice/management/listing')
2402
    assert 'id="lookup-box"' in resp.text
2403
    resp.forms[0]['query'] = formdata.tracking_code
2404
    resp = resp.forms[0].submit()
2405
    assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
2406
    resp = resp.follow()
2407
    assert 'The form has been recorded' in resp.text
2408

  
2409
    resp = app.get('/backoffice/management/listing')
2410
    resp.forms[0]['query'] = 'AAAAAAAA'
2411
    resp = resp.forms[0].submit()
2412
    assert resp.location == 'http://example.net/backoffice/management/listing'
2413
    resp = resp.follow()
2414
    assert 'No such tracking code or identifier.' in resp.text
2475 2415

  
2476 2416

  
2477 2417
def test_backoffice_sidebar_user_context(pub):
2478
    if not pub.is_using_postgresql():
2479
        pytest.skip('this requires SQL')
2480
        return
2481

  
2482 2418
    user = create_user(pub)
2483 2419
    create_environment(pub)
2484 2420
    form_class = FormDef.get_by_urlname('form-title').data_class()
......
2576 2512

  
2577 2513

  
2578 2514
def test_count_open(pub):
2579
    if not pub.is_using_postgresql():
2580
        pytest.skip('this requires SQL')
2581
        return
2582 2515
    create_user(pub)
2583 2516

  
2584 2517
    FormDef.wipe()
......
2710 2643

  
2711 2644

  
2712 2645
def test_backoffice_backoffice_submission_in_global_listing(pub):
2713
    if not pub.is_using_postgresql():
2714
        pytest.skip('this requires SQL')
2715
        return
2716 2646
    create_superuser(pub)
2717 2647
    create_environment(pub)
2718 2648

  
......
2758 2688
    resp = app.get('/backoffice/management/form-title/')
2759 2689
    assert 'advisory-lock' not in resp.text
2760 2690

  
2761
    if pub.is_using_postgresql():
2762
        # check global view
2763
        resp = app2.get('/backoffice/management/listing?limit=100')
2764
        assert 'advisory-lock' in resp.text
2765
        resp = app.get('/backoffice/management/listing?limit=100')
2766
        assert 'advisory-lock' not in resp.text
2691
    # check global view
2692
    resp = app2.get('/backoffice/management/listing?limit=100')
2693
    assert 'advisory-lock' in resp.text
2694
    resp = app.get('/backoffice/management/listing?limit=100')
2695
    assert 'advisory-lock' not in resp.text
2767 2696

  
2768 2697
    resp = app.get('/backoffice/management/form-title/' + first_link)
2769 2698
    assert 'Be warned forms of this user are also being looked' not in resp.text
......
2810 2739

  
2811 2740

  
2812 2741
def test_backoffice_advisory_lock_related_formdatas(pub):
2813
    if not pub.is_using_postgresql():
2814
        pytest.skip('this requires SQL')
2815
        return
2816 2742
    pub.session_manager.session_class.wipe()
2817 2743
    user = create_superuser(pub)
2818 2744
    create_environment(pub)
......
3622 3548

  
3623 3549

  
3624 3550
def test_backoffice_logged_errors(pub):
3625
    if not pub.is_using_postgresql():
3626
        pytest.skip('this requires SQL')
3627
        return
3628

  
3629 3551
    Workflow.wipe()
3630 3552
    workflow = Workflow.get_default_workflow()
3631 3553
    workflow.id = '12'
......
4144 4066
    assert target_data_class.count() == 0
4145 4067
    # resubmit it through backoffice submission
4146 4068
    resp = resp.form.submit(name='button_resubmit')
4147
    if pub.is_using_postgresql():
4148
        assert pub.loggederror_class.count() == 0
4069
    assert pub.loggederror_class.count() == 0
4149 4070
    assert target_data_class.count() == 1
4150 4071
    target_formdata = target_data_class.select()[0]
4151 4072

  
......
4264 4185
    assert target_data_class.count() == 0
4265 4186
    # resubmit it through backoffice submission
4266 4187
    resp = resp.form.submit(name='button_resubmit')
4267
    if pub.is_using_postgresql():
4268
        assert pub.loggederror_class.count() == 0
4188
    assert pub.loggederror_class.count() == 0
4269 4189
    assert target_data_class.count() == 1
4270 4190
    target_formdata = target_data_class.select()[0]
4271 4191

  
tests/backoffice_pages/test_carddata.py
552 552

  
553 553

  
554 554
def test_backoffice_cards_wscall_failure_display(http_requests, pub):
555
    if not pub.is_using_postgresql():
556
        pytest.skip('this requires SQL')
557
        return
558

  
559 555
    user = create_user(pub)
560 556

  
561 557
    Workflow.wipe()
tests/backoffice_pages/test_columns.py
309 309
    resp = app.get('/backoffice/management/form-title/')
310 310
    assert resp.text.count('</th>') == 6  # four columns
311 311

  
312
    if not pub.is_using_postgresql():
313
        # no support for relation columns unless using SQL
314
        assert 'user-label$3' not in resp.forms['listing-settings'].fields
315
        return
316 312
    resp.forms['listing-settings']['user-label$3'].checked = True
317 313
    resp = resp.forms['listing-settings'].submit()
318 314
    assert resp.text.count('</th>') == 7
......
381 377
    app = login(get_app(pub))
382 378
    resp = app.get('/backoffice/management/form-title/')
383 379
    assert resp.text.count('</th>') == 6  # four columns
384
    if not pub.is_using_postgresql():
385
        # no support for relation columns unless using SQL
386
        assert '4$1' not in resp.forms['listing-settings'].fields
387
        return
388 380
    assert '4$0' not in resp.forms['listing-settings'].fields
389 381
    resp.forms['listing-settings']['4$1'].checked = True
390 382
    resp.forms['listing-settings']['4$2'].checked = True
......
415 407

  
416 408

  
417 409
def test_backoffice_block_columns(pub):
418
    if not pub.is_using_postgresql():
419
        pytest.skip('this requires SQL')
420
        return
421

  
422 410
    pub.user_class.wipe()
423 411
    create_superuser(pub)
424 412
    pub.role_class.wipe()
......
520 508

  
521 509

  
522 510
def test_backoffice_block_email_column(pub):
523
    if not pub.is_using_postgresql():
524
        pytest.skip('this requires SQL')
525
        return
526

  
527 511
    pub.user_class.wipe()
528 512
    create_superuser(pub)
529 513
    pub.role_class.wipe()
......
585 569

  
586 570

  
587 571
def test_backoffice_block_bool_column(pub):
588
    if not pub.is_using_postgresql():
589
        pytest.skip('this requires SQL')
590
        return
591

  
592 572
    pub.user_class.wipe()
593 573
    create_superuser(pub)
594 574
    pub.role_class.wipe()
......
649 629

  
650 630

  
651 631
def test_backoffice_block_date_column(pub):
652
    if not pub.is_using_postgresql():
653
        pytest.skip('this requires SQL')
654
        return
655

  
656 632
    pub.user_class.wipe()
657 633
    create_superuser(pub)
658 634
    pub.role_class.wipe()
......
713 689

  
714 690

  
715 691
def test_backoffice_block_file_column(pub):
716
    if not pub.is_using_postgresql():
717
        pytest.skip('this requires SQL')
718
        return
719

  
720 692
    pub.user_class.wipe()
721 693
    create_superuser(pub)
722 694
    pub.role_class.wipe()
......
780 752

  
781 753

  
782 754
def test_backoffice_block_column_position(pub):
783
    if not pub.is_using_postgresql():
784
        pytest.skip('this requires SQL')
785
        return
786

  
787 755
    pub.user_class.wipe()
788 756
    create_superuser(pub)
789 757
    pub.role_class.wipe()
tests/backoffice_pages/test_custom_view.py
827 827

  
828 828

  
829 829
def test_backoffice_custom_view_sort_field(pub):
830
    if not pub.is_using_postgresql():
831
        pytest.skip('this requires SQL')
832
        return
833

  
834 830
    create_superuser(pub)
835 831

  
836 832
    FormDef.wipe()
tests/backoffice_pages/test_export.py
589 589

  
590 590

  
591 591
def test_backoffice_csv_export_ordering(pub):
592
    if not pub.is_using_postgresql():
593
        pytest.skip('this requires SQL')
594
        return
595

  
596 592
    create_superuser(pub)
597 593

  
598 594
    FormDef.wipe()
tests/backoffice_pages/test_filters.py
349 349
    assert resp.text.count('<td>b</td>') == 0
350 350
    assert resp.text.count('<td>d</td>') > 0
351 351

  
352
    if not pub.is_using_postgresql():
353
        # in pickle all options are always displayed
352
    # in postgresql, option 'c' is never used so not even listed
353
    with pytest.raises(ValueError):
354 354
        resp.forms['listing-settings']['filter-4-value'].value = 'c'
355
        resp.forms['listing-settings']['filter-4-operator'].value = 'eq'
356
        resp = resp.forms['listing-settings'].submit()
357
        assert resp.text.count('<td>â</td>') == 0
358
        assert resp.text.count('<td>b</td>') == 0
359
        assert resp.text.count('<td>c</td>') == 0
360 355

  
361
    else:
362
        # in postgresql, option 'c' is never used so not even listed
363
        with pytest.raises(ValueError):
364
            resp.forms['listing-settings']['filter-4-value'].value = 'c'
356
    # check json view used to fill select filters from javascript
357
    resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&' + resp.request.query_string)
358
    assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
359
    resp2 = app.get(
360
        resp.request.path + 'filter-options?filter_field_id=4&_search=d&' + resp.request.query_string
361
    )
362
    assert [x['id'] for x in resp2.json['data']] == ['d']
363
    resp2 = app.get(
364
        resp.request.path + 'filter-options?filter_field_id=7&' + resp.request.query_string, status=404
365
    )
365 366

  
366
        # check json view used to fill select filters from javascript
367
    for status in ('all', 'waiting', 'pending', 'done', 'accepted'):
368
        resp.forms['listing-settings']['filter'] = status
369
        resp = resp.forms['listing-settings'].submit()
367 370
        resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&' + resp.request.query_string)
368
        assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
369
        resp2 = app.get(
370
            resp.request.path + 'filter-options?filter_field_id=4&_search=d&' + resp.request.query_string
371
        )
372
        assert [x['id'] for x in resp2.json['data']] == ['d']
373
        resp2 = app.get(
374
            resp.request.path + 'filter-options?filter_field_id=7&' + resp.request.query_string, status=404
375
        )
376

  
377
        for status in ('all', 'waiting', 'pending', 'done', 'accepted'):
378
            resp.forms['listing-settings']['filter'] = status
379
            resp = resp.forms['listing-settings'].submit()
380
            resp2 = app.get(
381
                resp.request.path + 'filter-options?filter_field_id=4&' + resp.request.query_string
382
            )
383
            if status == 'accepted':
384
                assert [x['id'] for x in resp2.json['data']] == []
385
            else:
386
                assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
371
        if status == 'accepted':
372
            assert [x['id'] for x in resp2.json['data']] == []
373
        else:
374
            assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
387 375

  
388 376

  
389 377
def test_backoffice_item_double_filter(pub):
390
    if not pub.is_using_postgresql():
391
        pytest.skip('this requires SQL')
392
        return
393 378
    pub.user_class.wipe()
394 379
    create_superuser(pub)
395 380
    pub.role_class.wipe()
......
566 551
    assert resp.text.count('<td>b</td>') == 0
567 552
    assert resp.text.count('<td>d</td>') > 0
568 553

  
569
    if not pub.is_using_postgresql():
570
        # in pickle all options are always displayed
554
    # in postgresql, option 'c' is never used so not even listed
555
    with pytest.raises(ValueError):
571 556
        resp.forms['listing-settings']['filter-bo0-1-value'].value = 'c'
572
        resp.forms['listing-settings']['filter-bo0-1-operator'].value = 'eq'
573
        resp = resp.forms['listing-settings'].submit()
574
        assert resp.text.count('<td>â</td>') == 0
575
        assert resp.text.count('<td>b</td>') == 0
576
        assert resp.text.count('<td>c</td>') == 0
577 557

  
578
    else:
579
        # in postgresql, option 'c' is never used so not even listed
580
        with pytest.raises(ValueError):
581
            resp.forms['listing-settings']['filter-bo0-1-value'].value = 'c'
558
    # check json view used to fill select filters from javascript
559
    resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=bo0-1&' + resp.request.query_string)
560
    assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
561
    resp2 = app.get(
562
        resp.request.path + 'filter-options?filter_field_id=bo0-1&_search=d&' + resp.request.query_string
563
    )
564
    assert [x['id'] for x in resp2.json['data']] == ['d']
582 565

  
583
        # check json view used to fill select filters from javascript
566
    for status in ('all', 'waiting', 'pending', 'done', 'accepted'):
567
        resp.forms['listing-settings']['filter'] = status
568
        resp = resp.forms['listing-settings'].submit()
584 569
        resp2 = app.get(
585 570
            resp.request.path + 'filter-options?filter_field_id=bo0-1&' + resp.request.query_string
586 571
        )
587
        assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
588
        resp2 = app.get(
589
            resp.request.path + 'filter-options?filter_field_id=bo0-1&_search=d&' + resp.request.query_string
590
        )
591
        assert [x['id'] for x in resp2.json['data']] == ['d']
592

  
593
        for status in ('all', 'waiting', 'pending', 'done', 'accepted'):
594
            resp.forms['listing-settings']['filter'] = status
595
            resp = resp.forms['listing-settings'].submit()
596
            resp2 = app.get(
597
                resp.request.path + 'filter-options?filter_field_id=bo0-1&' + resp.request.query_string
598
            )
599
            if status == 'accepted':
600
                assert [x['id'] for x in resp2.json['data']] == []
601
            else:
602
                assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
572
        if status == 'accepted':
573
            assert [x['id'] for x in resp2.json['data']] == []
574
        else:
575
            assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
603 576

  
604 577

  
605 578
def test_backoffice_items_filter(pub):
......
681 654
    assert resp.text.count('<td>â</td>') > 0
682 655
    assert resp.text.count('<td>b, d</td>') == 0
683 656

  
684
    if pub.is_using_postgresql():
685
        # option 'c' is never used so not even listed
686
        with pytest.raises(ValueError):
687
            resp.forms['listing-settings']['filter-4-value'].value = 'c'
688
    else:
657
    # option 'c' is never used so not even listed
658
    with pytest.raises(ValueError):
689 659
        resp.forms['listing-settings']['filter-4-value'].value = 'c'
690
        resp.forms['listing-settings']['filter-4-operator'].value = 'eq'
691
        resp = resp.forms['listing-settings'].submit()
692
        assert resp.text.count('<td>â, b</td>') == 0
693
        assert resp.text.count('<td>â</td>') == 0
694
        assert resp.text.count('<td>b, d</td>') == 0
695
        assert resp.text.count('data-link') == 0  # no rows
696 660

  
697 661

  
698 662
def test_backoffice_items_cards_filter(pub):
......
766 730
    resp.forms['listing-settings']['filter-1'].checked = True
767 731
    resp = resp.forms['listing-settings'].submit()
768 732

  
769
    if pub.is_using_postgresql():
770
        # option 'bar' is never used so not even listed
771
        assert [x[2] for x in resp.forms['listing-settings']['filter-1-value'].options] == [
772
            '',
773
            'card baz',
774
            'card foo',
775
            'card foo, bar',
776
        ]
777
    else:
778
        assert [x[2] for x in resp.forms['listing-settings']['filter-1-value'].options] == [
779
            '',
780
            'card bar',
781
            'card baz',
782
            'card foo',
783
            'card foo, bar',
784
        ]
733
    # option 'bar' is never used so not even listed
734
    assert [x[2] for x in resp.forms['listing-settings']['filter-1-value'].options] == [
735
        '',
736
        'card baz',
737
        'card foo',
738
        'card foo, bar',
739
    ]
785 740

  
786 741
    resp.forms['listing-settings']['filter-1-value'].value = card_ids['foo']
787 742
    resp = resp.forms['listing-settings'].submit()
......
957 912

  
958 913

  
959 914
def test_backoffice_date_filter(pub):
960
    if not pub.is_using_postgresql():
961
        pytest.skip('this requires SQL')
962
        return
963 915
    pub.user_class.wipe()
964 916
    create_superuser(pub)
965 917
    pub.role_class.wipe()
......
1363 1315

  
1364 1316

  
1365 1317
def test_backoffice_block_field_filter(pub):
1366
    if not pub.is_using_postgresql():
1367
        pytest.skip('this requires SQL')
1368

  
1369 1318
    pub.user_class.wipe()
1370 1319
    create_superuser(pub)
1371 1320
    pub.role_class.wipe()
tests/backoffice_pages/test_form_inspect.py
349 349

  
350 350

  
351 351
def test_inspect_page_with_related_objects(pub):
352
    if not pub.is_using_postgresql():
353
        pytest.skip('this requires SQL')
354
        return
355

  
356 352
    user = create_user(pub, is_admin=True)
357 353

  
358 354
    FormDef.wipe()
......
746 742

  
747 743

  
748 744
def test_inspect_page_lazy_list(pub):
749
    if not pub.is_using_postgresql():
750
        pytest.skip('this requires SQL')
751
        return
752

  
753 745
    FormDef.wipe()
754 746

  
755 747
    formdef = FormDef()
tests/backoffice_pages/test_statistics.py
38 38
    create_user(pub)
39 39
    create_environment(pub)
40 40
    FormDef.wipe()
41
    if pub.is_using_postgresql():
42
        from wcs.sql import drop_global_views, get_connection_and_cursor
41
    from wcs.sql import drop_global_views, get_connection_and_cursor
43 42

  
44
        conn, cur = get_connection_and_cursor()
45
        drop_global_views(conn, cur)
46
        conn.commit()
47
        cur.close()
43
    conn, cur = get_connection_and_cursor()
44
    drop_global_views(conn, cur)
45
    conn.commit()
46
    cur.close()
48 47

  
49 48
    app = login(get_app(pub))
50 49
    resp = app.get('/backoffice/management/statistics')
......
72 71
    assert 'Total number of records: 17' in resp.text
73 72
    assert '<h2>Filters</h2>' in resp.text
74 73
    assert 'Status: Open' in resp.text
75
    if pub.is_using_postgresql():
76
        resp.forms['listing-settings']['filter'].value = 'waiting'
77
        resp = resp.forms['listing-settings'].submit()
78
        assert 'Total number of records: 17' in resp.text
79
        assert '<h2>Filters</h2>' in resp.text
80
        assert 'Status: Waiting for an action' in resp.text
81
    else:
82
        assert 'waiting' not in [x[0] for x in resp.forms['listing-settings']['filter'].options]
74
    resp.forms['listing-settings']['filter'].value = 'waiting'
75
    resp = resp.forms['listing-settings'].submit()
76
    assert 'Total number of records: 17' in resp.text
77
    assert '<h2>Filters</h2>' in resp.text
78
    assert 'Status: Waiting for an action' in resp.text
83 79

  
84 80
    resp.forms['listing-settings']['filter'].value = 'done'
85 81
    resp = resp.forms['listing-settings'].submit()
tests/form_pages/test_all.py
1521 1521
    user.store()
1522 1522
    resp = resp.form.submit('submit')
1523 1523
    resp = resp.follow()
1524
    if pub.is_using_postgresql():
1525
        assert 'Sorry, your session have been lost.' in resp
1526
    else:
1527
        assert 'The form has been recorded' in resp
1528
        assert formdef.data_class().count() == 1
1529
        assert formdef.data_class().select()[0].user_id is None
1524
    assert 'Sorry, your session have been lost.' in resp
1530 1525

  
1531 1526

  
1532 1527
def test_form_titles(pub):
......
2836 2831
    assert formdef.data_class().get(data_id).evolution[-1].status == 'wf-%s' % st2.id
2837 2832

  
2838 2833
    # jump to a nonexistent status == do not jump, but add a LoggedError
2839
    if pub.is_using_postgresql():
2840
        pub.loggederror_class.wipe()
2841
        assert pub.loggederror_class.count() == 0
2834
    pub.loggederror_class.wipe()
2835
    assert pub.loggederror_class.count() == 0
2842 2836
    editable.status = 'deleted_status_id'
2843 2837
    workflow.store()
2844 2838
    # go back to st1
......
2854 2848
    resp = resp.forms[0].submit('submit')
2855 2849
    resp = resp.follow()
2856 2850
    assert formdef.data_class().get(data_id).status == 'wf-%s' % st1.id  # stay on st1
2857
    if pub.is_using_postgresql():
2858
        assert pub.loggederror_class.count() == 1
2859
        logged_error = pub.loggederror_class.select()[0]
2860
        assert logged_error.formdata_id == str(formdata.id)
2861
        assert logged_error.formdef_id == formdef.id
2862
        assert logged_error.workflow_id == workflow.id
2863
        assert logged_error.status_id == st1.id
2864
        assert logged_error.status_item_id == editable.id
2865
        assert logged_error.occurences_count == 1
2851
    assert pub.loggederror_class.count() == 1
2852
    logged_error = pub.loggederror_class.select()[0]
2853
    assert logged_error.formdata_id == str(formdata.id)
2854
    assert logged_error.formdef_id == formdef.id
2855
    assert logged_error.workflow_id == workflow.id
2856
    assert logged_error.status_id == st1.id
2857
    assert logged_error.status_item_id == editable.id
2858
    assert logged_error.occurences_count == 1
2866 2859

  
2867 2860
    # do it again: increment logged_error.occurences_count
2868 2861
    page = login(get_app(pub), username='foo', password='foo').get('/test/%s/' % data_id)
......
2873 2866
    resp = resp.forms[0].submit('submit')
2874 2867
    resp = resp.follow()
2875 2868
    assert formdef.data_class().get(data_id).status == 'wf-%s' % st1.id  # stay on st1
2876
    if pub.is_using_postgresql():
2877
        assert pub.loggederror_class.count() == 1
2878
        logged_error = pub.loggederror_class.select()[0]
2879
        assert logged_error.occurences_count == 2
2869
    assert pub.loggederror_class.count() == 1
2870
    logged_error = pub.loggederror_class.select()[0]
2871
    assert logged_error.occurences_count == 2
2880 2872

  
2881 2873

  
2882 2874
def test_form_edit_autocomplete_list(pub):
......
3765 3757
            assert not resp.form['f0$elementbar'].checked
3766 3758
            assert not resp.form['f0$elementbaz'].checked
3767 3759

  
3768
            if pub.is_using_postgresql():
3769
                assert pub.loggederror_class.count() == 1
3770
                logged_error = pub.loggederror_class.select()[0]
3771
                assert logged_error.summary == 'Invalid value for items prefill on field "items"'
3772
                pub.loggederror_class.wipe()
3760
            assert pub.loggederror_class.count() == 1
3761
            logged_error = pub.loggederror_class.select()[0]
3762
            assert logged_error.summary == 'Invalid value for items prefill on field "items"'
3763
            pub.loggederror_class.wipe()
3773 3764

  
3774 3765

  
3775 3766
def test_form_page_changing_prefill(pub):
......
5006 4997
    autosave_data['_ajax_form_token'] = resp.form['_form_id'].value
5007 4998
    resp_autosave = app.post('/test/autosave', params=autosave_data)
5008 4999
    formdata.refresh_from_storage()
5009
    if pub.is_using_postgresql():
5010
        assert resp_autosave.json != {'result': 'success'}
5011
        assert formdata.data['3'] == '1'
5012
    else:
5013
        # with pickle invalid data has been saved
5014
        assert resp_autosave.json == {'result': 'success'}
5015
        assert formdata.data['3'] == 'tmp'
5000
    assert resp_autosave.json != {'result': 'success'}
5001
    assert formdata.data['3'] == '1'
5016 5002
    # validate
5017 5003
    resp = resp.form.submit('submit')  # -> submit
5018 5004

  
......
5546 5532
    resp = resp.follow()
5547 5533
    assert 'Error rendering message.' in resp.text
5548 5534

  
5549
    if pub.is_using_postgresql():
5550
        assert pub.loggederror_class.count() == 1
5551
        logged_error = pub.loggederror_class.select()[0]
5552
        assert logged_error.summary == "Error in template of workflow message ('int' object is not iterable)"
5535
    assert pub.loggederror_class.count() == 1
5536
    logged_error = pub.loggederror_class.select()[0]
5537
    assert logged_error.summary == "Error in template of workflow message ('int' object is not iterable)"
5553 5538

  
5554 5539

  
5555 5540
def test_session_cookie_flags(pub):
......
6030 6015
    app = login(get_app(pub), username='foo', password='foo')
6031 6016

  
6032 6017
    resp = app.get('/backoffice/data/items/')
6033
    if pub.is_using_postgresql():
6034
        assert resp.text.count('<tr') == 21  # thead + 20 items (max per page)
6035
    else:
6036
        assert resp.text.count('<tr') == 31  # thead + all items
6018
    assert resp.text.count('<tr') == 21  # thead + 20 items (max per page)
6037 6019
    resp.forms['listing-settings']['filter-0'].checked = True
6038 6020
    resp = resp.forms['listing-settings'].submit()
6039 6021

  
......
6524 6506
        resp2 = app.get(select2_url + '?q=hell')
6525 6507
        assert emails.count() == 1
6526 6508
        assert emails.get_latest('subject') == '[ERROR] [DATASOURCE] Error loading JSON data source (...)'
6527
        if pub.is_using_postgresql():
6528
            assert pub.loggederror_class.count() == 1
6529
            logged_error = pub.loggederror_class.select()[0]
6530
            assert logged_error.workflow_id is None
6531
            assert logged_error.summary == '[DATASOURCE] Error loading JSON data source (...)'
6509
        assert pub.loggederror_class.count() == 1
6510
        logged_error = pub.loggederror_class.select()[0]
6511
        assert logged_error.workflow_id is None
6512
        assert logged_error.summary == '[DATASOURCE] Error loading JSON data source (...)'
6532 6513

  
6533 6514
        data_source.notify_on_errors = False
6534 6515
        data_source.store()
......
6891 6872

  
6892 6873

  
6893 6874
def test_logged_errors(pub):
6894
    if not pub.is_using_postgresql():
6895
        pytest.skip('this requires SQL')
6896
        return
6897

  
6898 6875
    Workflow.wipe()
6899 6876
    workflow = Workflow.get_default_workflow()
6900 6877
    workflow.id = '12'
......
8896 8873
        resp = resp.form.submit('submit')  # -> submission
8897 8874
        resp = resp.follow()
8898 8875
        assert create_formdata['target_formdef'].data_class().count() == 0
8899
        if pub.is_using_postgresql():
8900
            assert pub.loggederror_class.count() == 0
8876
        assert pub.loggederror_class.count() == 0
8901 8877
        resp = resp.form.submit('button_resubmit')
8902
        if pub.is_using_postgresql():
8903
            assert pub.loggederror_class.count() == 0
8878
        assert pub.loggederror_class.count() == 0
8904 8879

  
8905 8880

  
8906 8881
def test_create_formdata_locked_prefill_parent(create_formdata):
tests/form_pages/test_block.py
1808 1808
    resp = get_app(pub).get(formdef.get_url(), status=500)
1809 1809
    assert 'A fatal error happened.' in resp.text
1810 1810

  
1811
    if pub.is_using_postgresql():
1812
        assert pub.loggederror_class.count() == 1
1813
        logged_error = pub.loggederror_class.select()[0]
1814
        assert '(id:%s)' % logged_error.id in resp.text
1815
        resp = get_app(pub).get(formdef.get_url(), status=500)
1816
        assert '(id:%s)' % logged_error.id in resp.text
1817
        logged_error = pub.loggederror_class.select()[0]
1818
        assert logged_error.occurences_count == 2
1811
    assert pub.loggederror_class.count() == 1
1812
    logged_error = pub.loggederror_class.select()[0]
1813
    assert '(id:%s)' % logged_error.id in resp.text
1814
    resp = get_app(pub).get(formdef.get_url(), status=500)
1815
    assert '(id:%s)' % logged_error.id in resp.text
1816
    logged_error = pub.loggederror_class.select()[0]
1817
    assert logged_error.occurences_count == 2
1819 1818

  
1820 1819

  
1821 1820
def test_block_with_static_condition(pub):
tests/form_pages/test_computed_field.py
631 631

  
632 632

  
633 633
def test_computed_field_with_bad_objects_filter_in_prefill(pub):
634
    if pub.is_using_postgresql():
635
        pub.loggederror_class.wipe()
634
    pub.loggederror_class.wipe()
636 635
    CardDef.wipe()
637 636
    FormDef.wipe()
638 637

  
......
676 675
    formdef.store()
677 676
    resp = get_app(pub).get('/test/')
678 677
    assert 'XY' in resp.text
679
    if pub.is_using_postgresql():
680
        assert pub.loggederror_class.count() == 2
681
        logged_error = pub.loggederror_class.select(order_by='id')[0]
682
        assert logged_error.summary == 'wcs.carddef.CardDefDoesNotExist: unknown'
683
        assert logged_error.formdef_id == formdef.id
684
        logged_error = pub.loggederror_class.select(order_by='id')[1]
685
        assert (
686
            logged_error.summary
687
            == 'Invalid value "{{ cards|objects:"unknown"|first|get:"form_number_raw"|default:"" }}" for field "computed"'
688
        )
689
        assert logged_error.formdef_id == formdef.id
678
    assert pub.loggederror_class.count() == 2
679
    logged_error = pub.loggederror_class.select(order_by='id')[0]
680
    assert logged_error.summary == 'wcs.carddef.CardDefDoesNotExist: unknown'
681
    assert logged_error.formdef_id == formdef.id
682
    logged_error = pub.loggederror_class.select(order_by='id')[1]
683
    assert (
684
        logged_error.summary
685
        == 'Invalid value "{{ cards|objects:"unknown"|first|get:"form_number_raw"|default:"" }}" for field "computed"'
686
    )
687
    assert logged_error.formdef_id == formdef.id
690 688

  
691 689

  
692 690
def test_computed_field_with_bad_value_type_in_prefill(pub):
693
    if pub.is_using_postgresql():
694
        pub.loggederror_class.wipe()
691
    pub.loggederror_class.wipe()
695 692
    CardDef.wipe()
696 693
    FormDef.wipe()
697 694

  
......
740 737
    formdef.store()
741 738
    resp = get_app(pub).get('/test/')
742 739
    assert 'XY' in resp.text
743
    if pub.is_using_postgresql():
744
        assert pub.loggederror_class.count() == 1
745
        logged_error = pub.loggederror_class.select()[0]
746
        assert logged_error.summary == 'Invalid value "foo" for field "computed"'
747
        assert logged_error.formdef_id == formdef.id
740
    assert pub.loggederror_class.count() == 1
741
    logged_error = pub.loggederror_class.select()[0]
742
    assert logged_error.summary == 'Invalid value "foo" for field "computed"'
743
    assert logged_error.formdef_id == formdef.id
748 744

  
749 745
    formdef.fields[0].value_template = (
750 746
        '{{ cards|objects:"%s"|first|get:"form_var_bool"|default:"" }}' % carddef.url_name
......
752 748
    formdef.store()
753 749
    resp = get_app(pub).get('/test/')
754 750
    assert 'XY' in resp.text
755
    if pub.is_using_postgresql():
756
        assert pub.loggederror_class.count() == 2
757
        logged_error = pub.loggederror_class.select(order_by='id')[1]
758
        assert logged_error.summary == 'Invalid value "True" for field "computed"'
759
        assert logged_error.formdef_id == formdef.id
751
    assert pub.loggederror_class.count() == 2
752
    logged_error = pub.loggederror_class.select(order_by='id')[1]
753
    assert logged_error.summary == 'Invalid value "True" for field "computed"'
754
    assert logged_error.formdef_id == formdef.id
760 755

  
761 756
    for value_template in [
762 757
        '{{ cards|objects:"%s"|get:42|get:"form_number_raw" }}' % carddef.url_name,
......
766 761
        formdef.store()
767 762
        resp = get_app(pub).get('/test/')
768 763
        assert 'XY' in resp.text
769
        if pub.is_using_postgresql():
770
            assert pub.loggederror_class.count() == 2
764
        assert pub.loggederror_class.count() == 2
tests/form_pages/test_file_field.py
392 392
    formdef.store()
393 393

  
394 394
    get_app(pub).get('/test/')
395
    if pub.is_using_postgresql():
396
        assert pub.loggederror_class.count() == 1
397
        logged_error = pub.loggederror_class.select()[0]
398
        assert logged_error.formdef_id == formdef.id
399
        assert logged_error.summary == 'Failed to set value on field "file"'
400
        assert logged_error.exception_class == 'AttributeError'
401
        assert logged_error.exception_message == "'str' object has no attribute 'time'"
395
    assert pub.loggederror_class.count() == 1
396
    logged_error = pub.loggederror_class.select()[0]
397
    assert logged_error.formdef_id == formdef.id
398
    assert logged_error.summary == 'Failed to set value on field "file"'
399
    assert logged_error.exception_class == 'AttributeError'
400
    assert logged_error.exception_message == "'str' object has no attribute 'time'"
tests/form_pages/test_formdata.py
780 780
        http_post_request.return_value = None, 400, '{"code": "document-exists"}', None  # fail
781 781
        resp = resp.form.submit('button_export_to')
782 782
        assert http_post_request.call_count == 1
783
        if pub.is_using_postgresql():
784
            error = pub.loggederror_class.select()[0]
785
            assert error.summary.startswith("file 'template.pdf' failed to be pushed to portfolio of 'Foo")
786
            assert 'status: 400' in error.summary
787
            assert "payload: {'code': 'document-exists'}" in error.summary
783
        error = pub.loggederror_class.select()[0]
784
        assert error.summary.startswith("file 'template.pdf' failed to be pushed to portfolio of 'Foo")
785
        assert 'status: 400' in error.summary
786
        assert "payload: {'code': 'document-exists'}" in error.summary
788 787

  
789 788
    # failed to push to portfolio, but document is here
790 789
    resp = resp.follow()  # $form/$id/create_doc
tests/form_pages/test_live.py
1320 1320

  
1321 1321
@pytest.mark.parametrize('field_type', ['item', 'string', 'email'])
1322 1322
def test_dynamic_item_field_from_custom_view_on_cards(pub, field_type):
1323
    if not pub.is_using_postgresql():
1324
        pytest.skip('this requires SQL')
1325
        return
1326

  
1327 1323
    pub.role_class.wipe()
1328 1324
    pub.custom_view_class.wipe()
1329 1325

  
......
1461 1457
    assert formdef.data_class().select()[0].data['1_structured']['item'] == 'baz'
1462 1458

  
1463 1459
    # delete custom view
1464
    if pub.is_using_postgresql():
1465
        pub.loggederror_class.wipe()
1460
    pub.loggederror_class.wipe()
1466 1461
    custom_view.remove_self()
1467 1462
    resp = get_app(pub).get('/test/')
1468 1463
    assert resp.form['f1'].options == []
1469
    if pub.is_using_postgresql():
1470
        assert pub.loggederror_class.count() == 1
1471
        logged_error = pub.loggederror_class.select()[0]
1472
        assert logged_error.formdef_id == formdef.id
1473
        assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
1464
    assert pub.loggederror_class.count() == 1
1465
    logged_error = pub.loggederror_class.select()[0]
1466
    assert logged_error.formdef_id == formdef.id
1467
    assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
1474 1468

  
1475 1469

  
1476 1470
def test_dynamic_items_field_from_custom_view_on_cards(pub):
1477
    if not pub.is_using_postgresql():
1478
        pytest.skip('this requires SQL')
1479
        return
1480

  
1481 1471
    pub.role_class.wipe()
1482 1472
    pub.custom_view_class.wipe()
1483 1473

  
......
1606 1596
    assert formdef.data_class().select()[0].data['1_structured']['text'] == 'attr1 - foo,bar'
1607 1597

  
1608 1598
    # delete custom view
1609
    if pub.is_using_postgresql():
1610
        pub.loggederror_class.wipe()
1599
    pub.loggederror_class.wipe()
1611 1600
    custom_view.remove_self()
1612 1601
    resp = get_app(pub).get('/test/')
1613 1602
    assert resp.form['f1'].options == []
1614
    if pub.is_using_postgresql():
1615
        assert pub.loggederror_class.count() == 1
1616
        logged_error = pub.loggederror_class.select()[0]
1617
        assert logged_error.formdef_id == formdef.id
1618
        assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
1603
    assert pub.loggederror_class.count() == 1
1604
    logged_error = pub.loggederror_class.select()[0]
1605
    assert logged_error.formdef_id == formdef.id
1606
    assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
1619 1607

  
1620 1608

  
1621 1609
def test_dynamic_internal_id_from_custom_view_on_cards(pub):
1622
    if not pub.is_using_postgresql():
1623
        pytest.skip('this requires SQL')
1624
        return
1625

  
1626 1610
    pub.role_class.wipe()
1627 1611
    pub.custom_view_class.wipe()
1628 1612

  
tests/test_carddef.py
453 453

  
454 454
    assert [i['text'] for i in CardDef.get_data_source_items('carddef:foo')] == ['Hello']
455 455
    assert [i['text'] for i in CardDef.get_data_source_items('carddef:foo:view')] == []
456
    if pub.is_using_postgresql():
457
        assert pub.loggederror_class.count() == 2
458
        logged_error = pub.loggederror_class.select(order_by='id')[0]
459
        assert logged_error.summary == 'Invalid filter "42"'
460
        assert logged_error.formdef_id == str(carddef.id)
461
        logged_error = pub.loggederror_class.select(order_by='id')[1]
462
        assert logged_error.summary == 'Invalid filter "foobar"'
463
        assert logged_error.formdef_id == str(carddef.id)
456
    assert pub.loggederror_class.count() == 2
457
    logged_error = pub.loggederror_class.select(order_by='id')[0]
458
    assert logged_error.summary == 'Invalid filter "42"'
459
    assert logged_error.formdef_id == str(carddef.id)
460
    logged_error = pub.loggederror_class.select(order_by='id')[1]
461
    assert logged_error.summary == 'Invalid filter "foobar"'
462
    assert logged_error.formdef_id == str(carddef.id)
464 463

  
465 464

  
466 465
def test_data_source_anonymised_cards(pub):
......
600 599
    carddef.store()
601 600
    assert [i['text'] for i in CardDef.get_data_source_items('carddef:foo')] == ['', '']
602 601
    assert [i['text'] for i in CardDef.get_data_source_items('carddef:foo:view')] == ['', '']
603
    if pub.is_using_postgresql():
604
        assert pub.loggederror_class.count() == 2
605
        logged_error = pub.loggederror_class.select(order_by='id')[0]
606
        assert logged_error.summary == 'Digest (default) not defined'
607
        assert logged_error.formdata_id in (str(carddata.id), str(carddata2.id))
608
        logged_error = pub.loggederror_class.select(order_by='id')[1]
609
        assert logged_error.summary == 'Digest (custom view "view") not defined'
610
        assert logged_error.formdata_id in (str(carddata.id), str(carddata2.id))
602
    assert pub.loggederror_class.count() == 2
603
    logged_error = pub.loggederror_class.select(order_by='id')[0]
604
    assert logged_error.summary == 'Digest (default) not defined'
605
    assert logged_error.formdata_id in (str(carddata.id), str(carddata2.id))
606
    logged_error = pub.loggederror_class.select(order_by='id')[1]
607
    assert logged_error.summary == 'Digest (custom view "view") not defined'
608
    assert logged_error.formdata_id in (str(carddata.id), str(carddata2.id))
611 609
    assert CardDef.get_data_source_items('carddef:foo', get_by_text='') == []
612 610
    assert CardDef.get_data_source_items('carddef:foo:view', get_by_text='') == []
613 611

  
tests/test_datasource.py
139 139
    datasource = {'type': 'formula', 'value': 'foobar', 'notify_on_errors': True, 'record_on_errors': True}
140 140
    assert data_sources.get_items(datasource) == []
141 141
    assert 'Failed to eval() Python data source' in emails.get_latest('subject')
142
    if pub.is_using_postgresql():
143
        assert pub.loggederror_class.count() == 1
144
        logged_error = pub.loggederror_class.select()[0]
145
        assert logged_error.workflow_id is None
146
        assert logged_error.summary == "[DATASOURCE] Failed to eval() Python data source ('foobar')"
142
    assert pub.loggederror_class.count() == 1
143
    logged_error = pub.loggederror_class.select()[0]
144
    assert logged_error.workflow_id is None
145
    assert logged_error.summary == "[DATASOURCE] Failed to eval() Python data source ('foobar')"
147 146

  
148 147
    # expression not iterable
149 148
    datasource = {'type': 'formula', 'value': '2', 'notify_on_errors': True, 'record_on_errors': True}
150 149
    assert data_sources.get_items(datasource) == []
151 150
    assert 'gave a non-iterable result' in emails.get_latest('subject')
152
    if pub.is_using_postgresql():
153
        assert pub.loggederror_class.count() == 2
154
        logged_error = pub.loggederror_class.select(order_by='id')[1]
155
        assert logged_error.workflow_id is None
156
        assert logged_error.summary == "[DATASOURCE] Python data source ('2') gave a non-iterable result"
151
    assert pub.loggederror_class.count() == 2
152
    logged_error = pub.loggederror_class.select(order_by='id')[1]
153
    assert logged_error.workflow_id is None
154
    assert logged_error.summary == "[DATASOURCE] Python data source ('2') gave a non-iterable result"
157 155

  
158 156
    datasource = {
159 157
        'type': 'formula',
......
161 159
        'record_on_errors': True,
162 160
    }
163 161
    assert data_sources.get_items(datasource) == []
164
    if pub.is_using_postgresql():
165
        assert pub.loggederror_class.count() == 3
166
        logged_error = pub.loggederror_class.select(order_by='id')[2]
167
        assert logged_error.workflow_id is None
168
        assert logged_error.summary == (
169
            '[DATASOURCE] Python data source (\'[{"mairie-a-rdv", "Mairie A"}, {"mairie-b-rdv", "Mairie B"}]\') gave a non usable result'
170
        )
162
    assert pub.loggederror_class.count() == 3
163
    logged_error = pub.loggederror_class.select(order_by='id')[2]
164
    assert logged_error.workflow_id is None
165
    assert logged_error.summary == (
166
        '[DATASOURCE] Python data source (\'[{"mairie-a-rdv", "Mairie A"}, {"mairie-b-rdv", "Mairie B"}]\') gave a non usable result'
167
    )
171 168

  
172 169
    # list of dictionaries but some are missing a text key
173 170
    datasource = {
......
176 173
        'record_on_errors': True,
177 174
    }
178 175
    assert data_sources.get_items(datasource) == []
179
    if pub.is_using_postgresql():
180
        assert pub.loggederror_class.count() == 4
181
        logged_error = pub.loggederror_class.select(order_by='id')[2]
182
        assert logged_error.workflow_id is None
183
        assert logged_error.summary == (
184
            '[DATASOURCE] Python data source (\'[{"mairie-a-rdv", "Mairie A"}, {"mairie-b-rdv", "Mairie B"}]\') gave a non usable result'
185
        )
176
    assert pub.loggederror_class.count() == 4
177
    logged_error = pub.loggederror_class.select(order_by='id')[2]
178
    assert logged_error.workflow_id is None
179
    assert logged_error.summary == (
180
        '[DATASOURCE] Python data source (\'[{"mairie-a-rdv", "Mairie A"}, {"mairie-b-rdv", "Mairie B"}]\') gave a non usable result'
181
    )
186 182

  
187 183
    if not pub.site_options.has_section('options'):
188 184
        pub.site_options.add_section('options')
......
191 187
        pub.site_options.write(fd)
192 188

  
193 189
    # running with disabled python expressions
194
    if pub.is_using_postgresql():
195
        pub.loggederror_class.wipe()
190
    pub.loggederror_class.wipe()
196 191
    datasource = {
197 192
        'type': 'formula',
198 193
        'value': repr(['foo', 'bar']),
......
203 198
    assert data_sources.get_items(datasource) == []
204 199
    assert emails.count() == 1  # notified even with notify_on_errors set to False
205 200
    assert 'Unauthorized Python Usage' in emails.get_latest('subject')
206
    if pub.is_using_postgresql():
207
        assert pub.loggederror_class.count() == 1
208
        logged_error = pub.loggederror_class.select(order_by='latest_occurence_timestamp')[-1]
209
        assert logged_error.workflow_id is None
210
        assert logged_error.summary == 'Unauthorized Python Usage'
201
    assert pub.loggederror_class.count() == 1
202
    logged_error = pub.loggederror_class.select(order_by='latest_occurence_timestamp')[-1]
203
    assert logged_error.workflow_id is None
204
    assert logged_error.summary == 'Unauthorized Python Usage'
211 205

  
212 206

  
213 207
def test_python_datasource_with_evalutils(pub):
......
450 444
    assert 'error in HTTP request to http://remote.example.net/404 (status: 404)' in emails.get_latest(
451 445
        'subject'
452 446
    )
453
    if pub.is_using_postgresql():
454
        assert pub.loggederror_class.count() == 1
455
        logged_error = pub.loggederror_class.select()[0]
456
        assert logged_error.workflow_id is None
457
        assert (
458
            logged_error.summary
459
            == "[DATASOURCE] Error loading JSON data source (error in HTTP request to http://remote.example.net/404 (status: 404))"
460
        )
447
    assert pub.loggederror_class.count() == 1
448
    logged_error = pub.loggederror_class.select()[0]
449
    assert logged_error.workflow_id is None
450
    assert (
451
        logged_error.summary
452
        == "[DATASOURCE] Error loading JSON data source (error in HTTP request to http://remote.example.net/404 (status: 404))"
453
    )
461 454

  
462 455
    datasource = {
463 456
        'type': 'json',
......
468 461
    assert data_sources.get_items(datasource) == []
469 462
    assert emails.count() == 2
470 463
    assert 'Error reading JSON data source' in emails.get_latest('subject')
471
    if pub.is_using_postgresql():
472
        assert pub.loggederror_class.count() == 2
473
        logged_error = pub.loggederror_class.select(order_by='id')[1]
474
        assert logged_error.workflow_id is None
475
        assert (
476
            logged_error.summary
477
            == "[DATASOURCE] Error reading JSON data source output (Expecting value: line 1 column 1 (char 0))"
478
        )
464
    assert pub.loggederror_class.count() == 2
465
    logged_error = pub.loggederror_class.select(order_by='id')[1]
466
    assert logged_error.workflow_id is None
467
    assert (
468
        logged_error.summary
469
        == "[DATASOURCE] Error reading JSON data source output (Expecting value: line 1 column 1 (char 0))"
470
    )
479 471

  
480 472
    datasource = {
481 473
        'type': 'json',
......
485 477
    }
486 478
    assert data_sources.get_items(datasource) == []
487 479
    assert 'Error loading JSON data source' in emails.get_latest('subject')
488
    if pub.is_using_postgresql():
489
        assert pub.loggederror_class.count() == 3
490
        logged_error = pub.loggederror_class.select(order_by='id')[2]
491
        assert logged_error.workflow_id is None
492
        assert logged_error.summary == "[DATASOURCE] Error loading JSON data source (error)"
480
    assert pub.loggederror_class.count() == 3
481
    logged_error = pub.loggederror_class.select(order_by='id')[2]
482
    assert logged_error.workflow_id is None
483
    assert logged_error.summary == "[DATASOURCE] Error loading JSON data source (error)"
493 484

  
494 485
    datasource = {
495 486
        'type': 'json',
......
499 490
    }
500 491
    assert data_sources.get_items(datasource) == []
501 492
    assert 'Error reading JSON data source output (err 1)' in emails.get_latest('subject')
502
    if pub.is_using_postgresql():
503
        assert pub.loggederror_class.count() == 4
504
        logged_error = pub.loggederror_class.select(order_by='id')[3]
505
        assert logged_error.workflow_id is None
506
        assert logged_error.summary == "[DATASOURCE] Error reading JSON data source output (err 1)"
493
    assert pub.loggederror_class.count() == 4
494
    logged_error = pub.loggederror_class.select(order_by='id')[3]
495
    assert logged_error.workflow_id is None
496
    assert logged_error.summary == "[DATASOURCE] Error reading JSON data source output (err 1)"
507 497

  
508 498

  
509 499
def test_json_datasource_bad_url_scheme(pub, error_email, emails):
510 500
    datasource = {'type': 'json', 'value': '', 'notify_on_errors': True, 'record_on_errors': True}
511 501
    assert data_sources.get_items(datasource) == []
512 502
    assert emails.count() == 0
513
    if pub.is_using_postgresql():
514
        assert pub.loggederror_class.count() == 0
503
    assert pub.loggederror_class.count() == 0
515 504

  
516 505
    datasource = {'type': 'json', 'value': 'foo://bar', 'notify_on_errors': True, 'record_on_errors': True}
517 506
    assert data_sources.get_items(datasource) == []
518 507
    assert 'Error loading JSON data source' in emails.get_latest('subject')
519 508
    assert 'invalid scheme in URL' in emails.get_latest('subject')
520
    if pub.is_using_postgresql():
521
        assert pub.loggederror_class.count() == 1
522
        logged_error = pub.loggederror_class.select()[0]
523
        assert logged_error.workflow_id is None
524
        assert (
525
            logged_error.summary
526
            == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL foo://bar)"
527
        )
509
    assert pub.loggederror_class.count() == 1
510
    logged_error = pub.loggederror_class.select()[0]
511
    assert logged_error.workflow_id is None
512
    assert (
513
        logged_error.summary
514
        == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL foo://bar)"
515
    )
528 516

  
529 517
    datasource = {'type': 'json', 'value': '/bla/blo', 'notify_on_errors': True, 'record_on_errors': True}
530 518
    assert data_sources.get_items(datasource) == []
531 519
    assert 'Error loading JSON data source' in emails.get_latest('subject')
532 520
    assert 'invalid scheme in URL' in emails.get_latest('subject')
533
    if pub.is_using_postgresql():
534
        assert pub.loggederror_class.count() == 2
535
        logged_error = pub.loggederror_class.select(order_by='id')[1]
536
        assert logged_error.workflow_id is None
537
        assert (
538
            logged_error.summary
539
            == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL /bla/blo)"
540
        )
521
    assert pub.loggederror_class.count() == 2
522
    logged_error = pub.loggederror_class.select(order_by='id')[1]
523
    assert logged_error.workflow_id is None
524
    assert (
525
        logged_error.summary == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL /bla/blo)"
526
    )
541 527

  
542 528

  
543 529
@pytest.mark.parametrize('notify', [True, False])
......
561 547
        assert message in emails.get_latest('subject')
562 548
    else:
563 549
        assert emails.count() == 0
564
    if pub.is_using_postgresql():
565
        if record:
566
            assert pub.loggederror_class.count() == 1
567
            logged_error = pub.loggederror_class.select(order_by='id')[0]
568
            assert logged_error.summary == message
569
        else:
570
            assert pub.loggederror_class.count() == 0
550
    if record:
551
        assert pub.loggederror_class.count() == 1
552
        logged_error = pub.loggederror_class.select(order_by='id')[0]
553
        assert logged_error.summary == message
554
    else:
555
        assert pub.loggederror_class.count() == 0
571 556

  
572 557

  
573 558
def test_geojson_datasource(pub, requests_pub, http_requests):
......
896 881
    assert data_sources.get_items(datasource) == []
897 882
    assert 'Error loading JSON data source' in emails.get_latest('subject')
898 883
    assert 'status: 404' in emails.get_latest('subject')
899
    if pub.is_using_postgresql():
900
        assert pub.loggederror_class.count() == 1
901
        logged_error = pub.loggederror_class.select()[0]
902
        assert logged_error.workflow_id is None
903
        assert (
904
            logged_error.summary
905
            == "[DATASOURCE] Error loading JSON data source (error in HTTP request to http://remote.example.net/404 (status: 404))"
906
        )
884
    assert pub.loggederror_class.count() == 1
885
    logged_error = pub.loggederror_class.select()[0]
886
    assert logged_error.workflow_id is None
887
    assert (
888
        logged_error.summary
889
        == "[DATASOURCE] Error loading JSON data source (error in HTTP request to http://remote.example.net/404 (status: 404))"
890
    )
907 891

  
908 892
    datasource = {
909 893
        'type': 'geojson',
......
914 898
    assert data_sources.get_items(datasource) == []
915 899
    assert 'Error reading JSON data source output' in emails.get_latest('subject')
916 900
    assert 'Expecting value:' in emails.get_latest('subject')
917
    if pub.is_using_postgresql():
918
        assert pub.loggederror_class.count() == 2
919
        logged_error = pub.loggederror_class.select(order_by='id')[1]
920
        assert logged_error.workflow_id is None
921
        assert (
922
            logged_error.summary
923
            == "[DATASOURCE] Error reading JSON data source output (Expecting value: line 1 column 1 (char 0))"
924
        )
901
    assert pub.loggederror_class.count() == 2
902
    logged_error = pub.loggederror_class.select(order_by='id')[1]
903
    assert logged_error.workflow_id is None
904
    assert (
905
        logged_error.summary
906
        == "[DATASOURCE] Error reading JSON data source output (Expecting value: line 1 column 1 (char 0))"
907
    )
925 908

  
926 909
    datasource = {
927 910
        'type': 'geojson',
......
932 915
    assert data_sources.get_items(datasource) == []
933 916
    assert 'Error loading JSON data source' in emails.get_latest('subject')
934 917
    assert 'error' in emails.get_latest('subject')
935
    if pub.is_using_postgresql():
936
        assert pub.loggederror_class.count() == 3
937
        logged_error = pub.loggederror_class.select(order_by='id')[2]
938
        assert logged_error.workflow_id is None
939
        assert logged_error.summary == "[DATASOURCE] Error loading JSON data source (error)"
918
    assert pub.loggederror_class.count() == 3
919
    logged_error = pub.loggederror_class.select(order_by='id')[2]
920
    assert logged_error.workflow_id is None
921
    assert logged_error.summary == "[DATASOURCE] Error loading JSON data source (error)"
940 922

  
941 923
    datasource = {
942 924
        'type': 'geojson',
......
946 928
    }
947 929
    assert data_sources.get_items(datasource) == []
948 930
    assert 'Error reading JSON data source output (err 1)' in emails.get_latest('subject')
949
    if pub.is_using_postgresql():
950
        assert pub.loggederror_class.count() == 4
951
        logged_error = pub.loggederror_class.select(order_by='id')[3]
952
        assert logged_error.workflow_id is None
953
        assert logged_error.summary == "[DATASOURCE] Error reading JSON data source output (err 1)"
931
    assert pub.loggederror_class.count() == 4
932
    logged_error = pub.loggederror_class.select(order_by='id')[3]
933
    assert logged_error.workflow_id is None
934
    assert logged_error.summary == "[DATASOURCE] Error reading JSON data source output (err 1)"
954 935

  
955 936

  
956 937
def test_geojson_datasource_bad_url_scheme(pub, error_email, emails):
......
962 943
    assert data_sources.get_items(datasource) == []
963 944
    assert 'Error loading JSON data source' in emails.get_latest('subject')
964 945
    assert 'invalid scheme in URL' in emails.get_latest('subject')
965
    if pub.is_using_postgresql():
966
        assert pub.loggederror_class.count() == 1
967
        logged_error = pub.loggederror_class.select()[0]
968
        assert logged_error.workflow_id is None
969
        assert (
970
            logged_error.summary
971
            == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL foo://bar)"
972
        )
946
    assert pub.loggederror_class.count() == 1
947
    logged_error = pub.loggederror_class.select()[0]
948
    assert logged_error.workflow_id is None
949
    assert (
950
        logged_error.summary
951
        == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL foo://bar)"
952
    )
973 953

  
974 954
    datasource = {'type': 'geojson', 'value': '/bla/blo', 'notify_on_errors': True, 'record_on_errors': True}
975 955
    assert data_sources.get_items(datasource) == []
976 956
    assert 'Error loading JSON data source' in emails.get_latest('subject')
977 957
    assert 'invalid scheme in URL' in emails.get_latest('subject')
978
    if pub.is_using_postgresql():
979
        assert pub.loggederror_class.count() == 2
980
        logged_error = pub.loggederror_class.select(order_by='id')[1]
981
        assert logged_error.workflow_id is None
982
        assert (
983
            logged_error.summary
984
            == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL /bla/blo)"
985
        )
958
    assert pub.loggederror_class.count() == 2
959
    logged_error = pub.loggederror_class.select(order_by='id')[1]
960
    assert logged_error.workflow_id is None
961
    assert (
962
        logged_error.summary == "[DATASOURCE] Error loading JSON data source (invalid scheme in URL /bla/blo)"
963
    )
986 964

  
987 965

  
988 966
def test_item_field_named_python_datasource(requests_pub):
tests/test_fc_auth.py
193 193
            }
194 194
        )
195 195
    )
196
    if pub.is_using_postgresql():
197
        assert 'user did not authorize login' in pub.loggederror_class.select(order_by='id')[-1].summary
196
    assert 'user did not authorize login' in pub.loggederror_class.select(order_by='id')[-1].summary
198 197
    resp = app.get(
199 198
        '/ident/fc/callback?%s'
200 199
        % urllib.parse.urlencode(
......
204 203
            }
205 204
        )
206 205
    )
207
    if pub.is_using_postgresql():
208
        assert 'whatever' in pub.loggederror_class.select(order_by='id')[-1].summary
206
    assert 'whatever' in pub.loggederror_class.select(order_by='id')[-1].summary
209 207

  
210 208
    # Login existing user
211 209
    def logme(login_url):
tests/test_formdata.py
1250 1250
    assert queryset.count == 4
1251 1251
    queryset = lazy_formdata.objects.filter_by('foo_foo').apply_filter_value('X')
1252 1252
    assert queryset.count == 0
1253
    if pub.is_using_postgresql():
1254
        pub.loggederror_class.wipe()
1253
    pub.loggederror_class.wipe()
1255 1254
    queryset = lazy_formdata.objects.filter_by('unknown').apply_filter_value('X')
1256 1255
    assert queryset.count == 0
1257
    if pub.is_using_postgresql():
1258
        assert pub.loggederror_class.count() == 1
1259
        logged_error = pub.loggederror_class.select()[0]
1260
        assert logged_error.summary == 'Invalid filter "unknown"'
1256
    assert pub.loggederror_class.count() == 1
1257
    logged_error = pub.loggederror_class.select()[0]
1258
    assert logged_error.summary == 'Invalid filter "unknown"'
1261 1259

  
1262 1260
    queryset = lazy_formdata.objects.filter_by('datefield').apply_filter_value(
1263 1261
        datetime.date(2018, 7, 31).timetuple()
......
1273 1271
    assert queryset.count == 5
1274 1272
    queryset = lazy_formdata.objects.filter_by('datefield').apply_filter_value('not a date')
1275 1273
    assert queryset.count == 0
1276
    if pub.is_using_postgresql():
1277
        assert pub.loggederror_class.count() == 2
1278
        logged_error = pub.loggederror_class.select(order_by='id')[1]
1279
        assert logged_error.summary == 'Invalid value "not a date" for filter "datefield"'
1280

  
1281
    if pub.is_using_postgresql():
1282
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1283
            datetime.date(2018, 7, 31).timetuple()
1284
        )
1285
        assert queryset.count == 6  # 1 + 5 null
1286
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1287
            datetime.date(2018, 7, 31)
1288
        )
1289
        assert queryset.count == 6
1290
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1291
            datetime.datetime(2018, 7, 31)
1292
        )
1293
        assert queryset.count == 6
1294
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('2018-07-31')
1295
        assert queryset.count == 6
1296
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(None)
1297
        assert queryset.count == 6
1298
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('still not a date')
1299
        assert queryset.count == 0
1300
        assert pub.loggederror_class.count() == 3
1301
        logged_error = pub.loggederror_class.select(order_by='id')[2]
1302
        assert logged_error.summary == 'Invalid value "still not a date" for filter "datefield"'
1274
    assert pub.loggederror_class.count() == 2
1275
    logged_error = pub.loggederror_class.select(order_by='id')[1]
1276
    assert logged_error.summary == 'Invalid value "not a date" for filter "datefield"'
1277

  
1278
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1279
        datetime.date(2018, 7, 31).timetuple()
1280
    )
1281
    assert queryset.count == 6  # 1 + 5 null
1282
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(datetime.date(2018, 7, 31))
1283
    assert queryset.count == 6
1284
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1285
        datetime.datetime(2018, 7, 31)
1286
    )
1287
    assert queryset.count == 6
1288
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('2018-07-31')
1289
    assert queryset.count == 6
1290
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(None)
1291
    assert queryset.count == 6
1292
    queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('still not a date')
1293
    assert queryset.count == 0
1294
    assert pub.loggederror_class.count() == 3
1295
    logged_error = pub.loggederror_class.select(order_by='id')[2]
1296
    assert logged_error.summary == 'Invalid value "still not a date" for filter "datefield"'
1303 1297

  
1304 1298
    queryset = lazy_formdata.objects.filter_by('boolfield').apply_filter_value(True)
1305 1299
    assert queryset.count == 6
......
1311 1305
    assert queryset.count == 5
1312 1306
    queryset = lazy_formdata.objects.filter_by('boolfield').apply_filter_value(0)
1313 1307
    assert queryset.count == 5
1314
    if pub.is_using_postgresql():
1315
        queryset = lazy_formdata.objects.filter_by('boolfield').apply_exclude_value(0)
1316
        assert queryset.count == 6
1308
    queryset = lazy_formdata.objects.filter_by('boolfield').apply_exclude_value(0)
1309
    assert queryset.count == 6
1317 1310

  
1318 1311
    queryset = lazy_formdata.objects.filter_by('term1').apply_filter_value('3')
1319 1312
    assert queryset.count == 7
......
1321 1314
    assert queryset.count == 7
1322 1315
    queryset = lazy_formdata.objects.filter_by('term1').apply_filter_value('foobar')
1323 1316
    assert queryset.count == 0
1324
    if pub.is_using_postgresql():
1325
        queryset = lazy_formdata.objects.filter_by('term1').apply_exclude_value('3')
1326
        assert queryset.count == 4
1327
        queryset = lazy_formdata.objects.filter_by('term1').apply_exclude_value('foobar')
1328
        assert queryset.count == 11
1317
    queryset = lazy_formdata.objects.filter_by('term1').apply_exclude_value('3')
1318
    assert queryset.count == 4
1319
    queryset = lazy_formdata.objects.filter_by('term1').apply_exclude_value('foobar')
1320
    assert queryset.count == 11
1329 1321

  
1330 1322
    queryset = lazy_formdata.objects.filter_by('email').apply_filter_value('bar')
1331 1323
    assert queryset.count == 0
......
1382 1374
    assert tmpl.render(context) == '7'
1383 1375
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:"bar"|length}}')
1384 1376
    assert tmpl.render(context) == '7'
1385
    if pub.is_using_postgresql():
1386
        tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|count}}')
1387
        assert tmpl.render(context) == '4'
1388
        tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|length}}')
1389
        assert tmpl.render(context) == '4'
1377
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|count}}')
1378
    assert tmpl.render(context) == '4'
1379
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|length}}')
1380
    assert tmpl.render(context) == '4'
1390 1381

  
1391 1382
    pub.substitutions.feed(formdata)
1392 1383
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:form_var_foo_foo|count}}')
......
1397 1388
    assert tmpl.render(context) == '5'
1398 1389
    tmpl = Template('{{form_objects|filter_by:"term1"|filter_value:form_var_term1|count}}')
1399 1390
    assert tmpl.render(context) == '7'
1400
    if pub.is_using_postgresql():
1401
        tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:form_var_foo_foo|count}}')
1402
        assert tmpl.render(context) == '4'
1403
        tmpl = Template('{{form_objects|filter_by:"datefield"|exclude_value:form_var_datefield|count}}')
1404
        assert tmpl.render(context) == '6'
1405
        tmpl = Template('{{form_objects|filter_by:"boolfield"|exclude_value:form_var_boolfield|count}}')
1406
        assert tmpl.render(context) == '6'
1407
        tmpl = Template('{{form_objects|filter_by:"term1"|exclude_value:form_var_term1|count}}')
1408
        assert tmpl.render(context) == '4'
1391
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:form_var_foo_foo|count}}')
1392
    assert tmpl.render(context) == '4'
1393
    tmpl = Template('{{form_objects|filter_by:"datefield"|exclude_value:form_var_datefield|count}}')
1394
    assert tmpl.render(context) == '6'
1395
    tmpl = Template('{{form_objects|filter_by:"boolfield"|exclude_value:form_var_boolfield|count}}')
1396
    assert tmpl.render(context) == '6'
1397
    tmpl = Template('{{form_objects|filter_by:"term1"|exclude_value:form_var_term1|count}}')
1398
    assert tmpl.render(context) == '4'
1409 1399

  
1410 1400
    tmpl = Template('{{form.objects|exclude_self|filter_by:"foo_foo"|filter_value:form_var_foo_foo|count}}')
1411 1401
    assert tmpl.render(context) == '6'
......
1484 1474
    assert tmpl.render(context) == '0'
1485 1475
    tmpl = Template('{{form_objects|filter_by_internal_id:"%s"|count}}' % 'invalid value')
1486 1476
    assert tmpl.render(context) == '0'
1487
    if pub.is_using_postgresql():
1488
        assert pub.loggederror_class.count() == 4
1489
        logged_error = pub.loggederror_class.select(order_by='id')[3]
1490
        assert logged_error.summary == 'Invalid value "invalid value" for "filter_by_internal_id"'
1477
    assert pub.loggederror_class.count() == 4
1478
    logged_error = pub.loggederror_class.select(order_by='id')[3]
1479
    assert logged_error.summary == 'Invalid value "invalid value" for "filter_by_internal_id"'
1491 1480

  
1492 1481
    # test |filter_by_number
1493 1482
    context = pub.substitutions.get_context_variables(mode='lazy')
......
1665 1654

  
1666 1655

  
1667 1656
def test_lazy_formdata_queryset_order_by(pub, variable_test_data):
1668
    if not pub.is_using_postgresql():
1669
        pytest.skip('this requires SQL')
1670

  
1671 1657
    lazy_formdata = variable_test_data
1672 1658
    data_class = lazy_formdata._formdef.data_class()
1673 1659
    for i in range(6):
......
1818 1804
    custom_view4.store()
1819 1805
    tmpl = Template('{{forms|objects:"foobarlazy"|with_custom_view:"unknown-filter"|count}}')
1820 1806
    assert tmpl.render(context) == '0'
1821
    if pub.is_using_postgresql():
1822
        assert pub.loggederror_class.count() == 2
1823
        logged_error = pub.loggederror_class.select(order_by='id')[0]
1824
        assert logged_error.summary == 'Invalid filter "42"'
1825
        assert logged_error.formdef_id == str(formdef.id)
1826
        logged_error = pub.loggederror_class.select(order_by='id')[1]
1827
        assert logged_error.summary == 'Invalid filter "foobar"'
1828
        assert logged_error.formdef_id == str(formdef.id)
1807
    assert pub.loggederror_class.count() == 2
1808
    logged_error = pub.loggederror_class.select(order_by='id')[0]
1809
    assert logged_error.summary == 'Invalid filter "42"'
1810
    assert logged_error.formdef_id == str(formdef.id)
1811
    logged_error = pub.loggederror_class.select(order_by='id')[1]
1812
    assert logged_error.summary == 'Invalid filter "foobar"'
1813
    assert logged_error.formdef_id == str(formdef.id)
1829 1814

  
1830 1815

  
1831 1816
def test_lazy_variables(pub, variable_test_data):
......
2664 2649
    formdata.store()
2665 2650
    assert formdef.data_class().get(formdata.id).digests['default'] == 'ERROR'
2666 2651

  
2667
    if pub.is_using_postgresql():
2668
        assert pub.loggederror_class.count() == 1
2669
        logged_error = pub.loggederror_class.select()[0]
2670
        assert logged_error.summary == 'Could not render digest (default)'
2671
        assert logged_error.formdata_id == str(formdata.id)
2652
    assert pub.loggederror_class.count() == 1
2653
    logged_error = pub.loggederror_class.select()[0]
2654
    assert logged_error.summary == 'Could not render digest (default)'
2655
    assert logged_error.formdata_id == str(formdata.id)
2672 2656

  
2673 2657
    formdef.digest_templates = {
2674 2658
        'default': 'plop plop',
......
2680 2664
    formdata.store()
2681 2665
    assert formdef.data_class().get(formdata.id).digests['custom-view:foobar'] == 'ERROR'
2682 2666

  
2683
    if pub.is_using_postgresql():
2684
        assert pub.loggederror_class.count() == 2
2685
        logged_error = pub.loggederror_class.select(order_by='id')[1]
2686
        assert logged_error.summary == 'Could not render digest (custom view "foobar")'
2687
        assert logged_error.formdata_id == str(formdata.id)
2667
    assert pub.loggederror_class.count() == 2
2668
    logged_error = pub.loggederror_class.select(order_by='id')[1]
2669
    assert logged_error.summary == 'Could not render digest (custom view "foobar")'
2670
    assert logged_error.formdata_id == str(formdata.id)
2688 2671

  
2689 2672

  
2690 2673
def test_lazy_formdata_decimal_filter(pub):
tests/test_formdef.py
121 121
    assert FormDef.get(formdef.id).url_name == 'foo'
122 122
    assert FormDef.get(formdef.id).internal_identifier == 'bar'
123 123

  
124
    if not pub.is_using_postgresql():
125
        # makes sure the internal_name doesn't change if there are submitted forms
126
        formdef.data_class()().store()
127
        formdef.name = 'baz'
128
        formdef.store()
129
        assert FormDef.get(formdef.id).name == 'baz'
130
        assert FormDef.get(formdef.id).internal_identifier == 'bar'  # didn't change
124
    # makes sure the internal_name doesn't change if there are submitted forms
125
    formdef.data_class()().store()
126
    formdef.name = 'baz'
127
    formdef.store()
128
    assert FormDef.get(formdef.id).name == 'baz'
129
    assert FormDef.get(formdef.id).internal_identifier == 'bar'  # didn't change
131 130

  
132 131

  
133 132
def test_overlong_slug(pub):
tests/test_sessions.py
224 224

  
225 225

  
226 226
def test_transient_data_removal(pub, app):
227
    if not pub.is_using_postgresql():
228
        pytest.skip('this requires SQL')
229
        return
230

  
231 227
    pub.session_manager.session_class.wipe()
232 228
    sql.TransientData.wipe()
233 229
    resp = app.get('/')
......
251 247

  
252 248

  
253 249
def test_magictoken_migration(pub, app):
254
    if not pub.is_using_postgresql():
255
        pytest.skip('this requires SQL')
256
        return
257

  
258 250
    pub.session_manager.session_class.wipe()
259 251
    sql.TransientData.wipe()
260 252
    resp = app.get('/')
tests/utilities.py
85 85
        pub.custom_view_class = sql.CustomView
86 86
        pub.snapshot_class = sql.Snapshot
87 87
        pub.loggederror_class = sql.LoggedError
88
        pub.is_using_postgresql = lambda: True
89 88
    else:
90 89
        pub.user_class = User
91 90
        pub.role_class = Role
......
93 92
        pub.tracking_code_class = TrackingCode
94 93
        pub.session_class = sessions.BasicSession
95 94
        pub.custom_view_class = custom_views.CustomView
96
        pub.is_using_postgresql = lambda: False
97 95

  
98 96
    pub.session_manager_class = sessions.StorageSessionManager
99 97
    pub.session_manager = pub.session_manager_class(session_class=pub.session_class)
tests/workflow/test_all.py
373 373

  
374 374

  
375 375
def test_jump_bad_python_condition(two_pubs):
376
    if not two_pubs.is_using_postgresql():
377
        pytest.skip('this requires SQL')
378
        return
379

  
380 376
    FormDef.wipe()
381 377
    formdef = FormDef()
382 378
    formdef.name = 'foobar'
......
433 429
    item.condition = {'type': 'django', 'value': 'form_var_foo|first|upper == "X"'}
434 430
    assert item.check_condition(formdata) is False
435 431

  
436
    if two_pubs.is_using_postgresql():
437
        assert two_pubs.loggederror_class.count() == 0
432
    assert two_pubs.loggederror_class.count() == 0
438 433

  
439 434
    item.condition = {'type': 'django', 'value': '~ invalid ~'}
440 435
    assert item.check_condition(formdata) is False
441
    if two_pubs.is_using_postgresql():
442
        assert two_pubs.loggederror_class.count() == 1
443
        logged_error = two_pubs.loggederror_class.select()[0]
444
        assert logged_error.summary == 'Failed to evaluate condition'
445
        assert logged_error.exception_class == 'TemplateSyntaxError'
446
        assert logged_error.exception_message == "Could not parse the remainder: '~' from '~'"
447
        assert logged_error.expression == '~ invalid ~'
448
        assert logged_error.expression_type == 'django'
436
    assert two_pubs.loggederror_class.count() == 1
437
    logged_error = two_pubs.loggederror_class.select()[0]
438
    assert logged_error.summary == 'Failed to evaluate condition'
439
    assert logged_error.exception_class == 'TemplateSyntaxError'
440
    assert logged_error.exception_message == "Could not parse the remainder: '~' from '~'"
441
    assert logged_error.expression == '~ invalid ~'
442
    assert logged_error.expression_type == 'django'
449 443

  
450 444

  
451 445
def test_check_auth(pub):
......
580 574

  
581 575

  
582 576
def test_dispatch_auto(two_pubs):
583
    if not two_pubs.is_using_postgresql():
584
        pytest.skip('this requires sql')
585
        return
586

  
587 577
    formdef = FormDef()
588 578
    formdef.name = 'baz'
589 579
    formdef.fields = [
......
671 661

  
672 662

  
673 663
def test_dispatch_computed(two_pubs):
674
    if not two_pubs.is_using_postgresql():
675
        pytest.skip('this requires sql')
676
        return
677

  
678 664
    formdef = FormDef()
679 665
    formdef.name = 'baz'
680 666
    formdef.store()
......
1275 1261
    two_pubs.substitutions.feed(formdata)
1276 1262
    item.perform(formdata)
1277 1263
    url1 = formdata.evolution[-1].parts[-1].content
1278
    if two_pubs.is_using_postgresql():
1279
        assert two_pubs.loggederror_class.count() == 1
1280
        error = two_pubs.loggederror_class.select()[0]
1281
        assert error.kind == 'deprecated_usage'
1282
        assert error.occurences_count == 1
1264
    assert two_pubs.loggederror_class.count() == 1
1265
    error = two_pubs.loggederror_class.select()[0]
1266
    assert error.kind == 'deprecated_usage'
1267
    assert error.occurences_count == 1
1283 1268

  
1284 1269
    two_pubs.substitutions.feed(formdata)
1285 1270
    item.comment = '{{ form_attachments.testfile.url }}'
1286 1271
    item.perform(formdata)
1287 1272
    url2 = formdata.evolution[-1].parts[-1].content
1288
    if two_pubs.is_using_postgresql():
1289
        assert two_pubs.loggederror_class.count() == 1
1290
        error = two_pubs.loggederror_class.select()[0]
1291
        assert error.kind == 'deprecated_usage'
1292
        assert error.occurences_count == 1
1273
    assert two_pubs.loggederror_class.count() == 1
1274
    error = two_pubs.loggederror_class.select()[0]
1275
    assert error.kind == 'deprecated_usage'
1276
    assert error.occurences_count == 1
1293 1277

  
1294 1278
    assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments'))) == 1
1295 1279
    for subdir in os.listdir(os.path.join(get_publisher().app_dir, 'attachments')):
......
1316 1300
    item.comment = '[attachments.testfile.url]'
1317 1301
    item.perform(formdata)
1318 1302
    url3 = formdata.evolution[-1].parts[-1].content
1319
    if two_pubs.is_using_postgresql():
1320
        assert two_pubs.loggederror_class.count() == 1
1321
        error = two_pubs.loggederror_class.select()[0]
1322
        assert error.kind == 'deprecated_usage'
1323
        assert error.occurences_count == 2
1303
    assert two_pubs.loggederror_class.count() == 1
1304
    error = two_pubs.loggederror_class.select()[0]
1305
    assert error.kind == 'deprecated_usage'
1306
    assert error.occurences_count == 2
1324 1307
    two_pubs.substitutions.feed(formdata)
1325 1308
    item.comment = '[form_attachments.testfile.url]'
1326 1309
    item.perform(formdata)
1327 1310
    url4 = formdata.evolution[-1].parts[-1].content
1328 1311
    assert url3 == url4
1329
    if two_pubs.is_using_postgresql():
1330
        assert two_pubs.loggederror_class.count() == 1
1331
        error = two_pubs.loggederror_class.select()[0]
1332
        assert error.kind == 'deprecated_usage'
1333
        assert error.occurences_count == 2
1312
    assert two_pubs.loggederror_class.count() == 1
1313
    error = two_pubs.loggederror_class.select()[0]
1314
    assert error.kind == 'deprecated_usage'
1315
    assert error.occurences_count == 2
1334 1316

  
1335 1317

  
1336 1318
def test_register_comment_with_attachment_file(pub):
......
1808 1790
        item.perform(formdata)
1809 1791
    assert formdata.status == 'wf-sterr'
1810 1792

  
1811
    if pub.is_using_postgresql():
1812
        pub.loggederror_class.wipe()
1793
    pub.loggederror_class.wipe()
1813 1794
    item.action_on_5xx = 'stdeleted'  # removed status
1814 1795
    formdata.status = 'wf-st1'
1815 1796
    formdata.store()
1816 1797
    with pytest.raises(AbortActionException):
1817 1798
        item.perform(formdata)
1818 1799
    assert formdata.status == 'wf-st1'  # unknown status acts like :stop
1819
    if pub.is_using_postgresql():
1820
        assert pub.loggederror_class.count() == 1
1821
        error = pub.loggederror_class.select()[0]
1822
        assert 'reference-to-invalid-status-stdeleted-in-workflow' in error.tech_id
1823
        assert error.occurences_count == 1
1800
    assert pub.loggederror_class.count() == 1
1801
    error = pub.loggederror_class.select()[0]
1802
    assert 'reference-to-invalid-status-stdeleted-in-workflow' in error.tech_id
1803
    assert error.occurences_count == 1
1824 1804

  
1825 1805
    item = WebserviceCallStatusItem()
1826 1806
    item.url = 'http://remote.example.net/xml'
......
2451 2431

  
2452 2432
    assert formdef.data_class().get(formdata_id).status == 'wf-st2'
2453 2433

  
2454
    if two_pubs.is_using_postgresql():
2455
        formdata = formdef.data_class()()
2456
        formdata.just_created()
2434
    formdata = formdef.data_class()()
2435
    formdata.just_created()
2436
    formdata.store()
2437
    formdata_id = formdata.id
2438
    with mock.patch('wcs.wf.jump.JumpWorkflowStatusItem.check_condition') as must_jump:
2439
        must_jump.return_value = False
2440
        _apply_timeouts(two_pubs)
2441
        assert must_jump.call_count == 0  # not enough time has passed
2442

  
2443
        # check a lower than minimal delay is not considered
2444
        jump.timeout = 5 * 50  # 5 minutes
2445
        workflow.store()
2446
        rewind(formdata, seconds=10 * 60)
2447
        formdata.store()
2448
        _apply_timeouts(two_pubs)
2449
        assert must_jump.call_count == 0
2450

  
2451
        # but is executed once delay is reached
2452
        rewind(formdata, seconds=10 * 60)
2457 2453
        formdata.store()
2458
        formdata_id = formdata.id
2459
        with mock.patch('wcs.wf.jump.JumpWorkflowStatusItem.check_condition') as must_jump:
2460
            must_jump.return_value = False
2461
            _apply_timeouts(two_pubs)
2462
            assert must_jump.call_count == 0  # not enough time has passed
2463

  
2464
            # check a lower than minimal delay is not considered
2465
            jump.timeout = 5 * 50  # 5 minutes
2466
            workflow.store()
2467
            rewind(formdata, seconds=10 * 60)
2468
            formdata.store()
2469
            _apply_timeouts(two_pubs)
2470
            assert must_jump.call_count == 0
2471

  
2472
            # but is executed once delay is reached
2473
            rewind(formdata, seconds=10 * 60)
2474
            formdata.store()
2475
            _apply_timeouts(two_pubs)
2476
            assert must_jump.call_count == 1
2477

  
2478
            # check a templated timeout is considered as minimal delay for explicit evaluation
2479
            jump.timeout = '{{ "0" }}'
2480
            workflow.store()
2481
            _apply_timeouts(two_pubs)
2482
            assert must_jump.call_count == 2
2454
        _apply_timeouts(two_pubs)
2455
        assert must_jump.call_count == 1
2456

  
2457
        # check a templated timeout is considered as minimal delay for explicit evaluation
2458
        jump.timeout = '{{ "0" }}'
2459
        workflow.store()
2460
        _apply_timeouts(two_pubs)
2461
        assert must_jump.call_count == 2
2483 2462

  
2484 2463
    # check there's no crash on workflow without jumps
2485 2464
    formdef = FormDef()
......
2530 2509
    formdata.store()
2531 2510
    formdata_id = formdata.id
2532 2511

  
2533
    if two_pubs.is_using_postgresql():
2534
        two_pubs.loggederror_class.wipe()
2512
    two_pubs.loggederror_class.wipe()
2535 2513

  
2536 2514
    rewind(formdata, seconds=40 * 60)
2537 2515
    formdata.store()
2538 2516
    _apply_timeouts(two_pubs)
2539 2517
    assert formdef.data_class().get(formdata_id).status == 'wf-st1'  # no change
2540 2518

  
2541
    if two_pubs.is_using_postgresql():
2542
        assert two_pubs.loggederror_class.count() == 1
2543
        logged_error = two_pubs.loggederror_class.select()[0]
2544
        assert logged_error.summary == "Error in timeout value '30 plop' (computed from '{{ 30 }} plop')"
2519
    assert two_pubs.loggederror_class.count() == 1
2520
    logged_error = two_pubs.loggederror_class.select()[0]
2521
    assert logged_error.summary == "Error in timeout value '30 plop' (computed from '{{ 30 }} plop')"
2545 2522

  
2546 2523
    # template timeout value returning nothing
2547 2524
    jump.timeout = '{% if 1 %}{% endif %}'
......
2553 2530
    formdata.store()
2554 2531
    formdata_id = formdata.id
2555 2532

  
2556
    if two_pubs.is_using_postgresql():
2557
        two_pubs.loggederror_class.wipe()
2533
    two_pubs.loggederror_class.wipe()
2558 2534

  
2559 2535
    rewind(formdata, seconds=40 * 60)
2560 2536
    formdata.store()
2561 2537
    _apply_timeouts(two_pubs)
2562 2538
    assert formdef.data_class().get(formdata_id).status == 'wf-st1'  # no change
2563 2539

  
2564
    if two_pubs.is_using_postgresql():
2565
        assert two_pubs.loggederror_class.count() == 1
2566
        logged_error = two_pubs.loggederror_class.select()[0]
2567
        assert logged_error.summary == "Error in timeout value '' (computed from '{% if 1 %}{% endif %}')"
2540
    assert two_pubs.loggederror_class.count() == 1
2541
    logged_error = two_pubs.loggederror_class.select()[0]
2542
    assert logged_error.summary == "Error in timeout value '' (computed from '{% if 1 %}{% endif %}')"
2568 2543

  
2569 2544

  
2570 2545
def test_legacy_timeout(pub):
......
2663 2638

  
2664 2639

  
2665 2640
def test_jump_missing_previous_mark(two_pubs):
2666
    if not two_pubs.is_using_postgresql():
2667
        pytest.skip('this requires SQL')
2668
        return
2669

  
2670 2641
    FormDef.wipe()
2671 2642
    Workflow.wipe()
2672 2643

  
......
2847 2818
            assert json_payload['to'] == ['1234']
2848 2819
            assert json_payload['from'] == 'Passerelle'
2849 2820

  
2850
    if pub.is_using_postgresql():
2851
        pub.loggederror_class.wipe()
2852
        with mock.patch('wcs.wscalls.get_secret_and_orig') as mocked_secret_and_orig:
2853
            mocked_secret_and_orig.return_value = ('secret', 'localhost')
2854
            with mock.patch('wcs.qommon.misc._http_request') as mocked_http_post:
2855
                mocked_http_post.return_value = (mock.Mock(headers={}), 400, '{"err": 1}', 'headers')
2856
                item.perform(formdata)
2857
                assert pub.loggederror_class.count() == 1
2858
                assert pub.loggederror_class.select()[0].summary == 'Could not send SMS'
2821
    pub.loggederror_class.wipe()
2822
    with mock.patch('wcs.wscalls.get_secret_and_orig') as mocked_secret_and_orig:
2823
        mocked_secret_and_orig.return_value = ('secret', 'localhost')
2824
        with mock.patch('wcs.qommon.misc._http_request') as mocked_http_post:
2825
            mocked_http_post.return_value = (mock.Mock(headers={}), 400, '{"err": 1}', 'headers')
2826
            item.perform(formdata)
2827
            assert pub.loggederror_class.count() == 1
2828
            assert pub.loggederror_class.select()[0].summary == 'Could not send SMS'
2859 2829

  
2860 2830

  
2861 2831
def test_display_form(two_pubs):
......
3340 3310
    formdef.change_workflow(workflow)
3341 3311
    assert formdef.geolocations
3342 3312

  
3343
    if two_pubs.is_using_postgresql():
3344
        conn, cur = sql.get_connection_and_cursor()
3345
        assert column_exists_in_table(cur, formdef.table_name, 'geoloc_base')
3346
        conn.commit()
3347
        cur.close()
3313
    conn, cur = sql.get_connection_and_cursor()
3314
    assert column_exists_in_table(cur, formdef.table_name, 'geoloc_base')
3315
    conn.commit()
3316
    cur.close()
3348 3317

  
3349 3318
    # change to current workflow
3350 3319
    workflow = Workflow(name='wf2')
......
3367 3336
    formdef.refresh_from_storage()
3368 3337
    assert formdef.geolocations
3369 3338

  
3370
    if two_pubs.is_using_postgresql():
3371
        conn, cur = sql.get_connection_and_cursor()
3372
        assert column_exists_in_table(cur, formdef.table_name, 'geoloc_base')
3373
        conn.commit()
3374
        cur.close()
3339
    conn, cur = sql.get_connection_and_cursor()
3340
    assert column_exists_in_table(cur, formdef.table_name, 'geoloc_base')
3341
    conn.commit()
3342
    cur.close()
3375 3343

  
3376 3344

  
3377 3345
def test_geolocate_address(two_pubs):
......
3450 3418
    formdata.geolocations = None
3451 3419
    item.perform(formdata)
3452 3420
    assert formdata.geolocations == {}
3453
    if two_pubs.is_using_postgresql():
3454
        assert two_pubs.loggederror_class.count() == 1
3455
        logged_error = two_pubs.loggederror_class.select()[0]
3456
        assert (
3457
            logged_error.summary
3458
            == 'error in template for address string [syntax error in ezt template: unclosed block at line 1 and column 24]'
3459
        )
3460
        assert logged_error.formdata_id == str(formdata.id)
3461
        assert logged_error.exception_class == 'TemplateError'
3462
        assert (
3463
            logged_error.exception_message
3464
            == 'syntax error in ezt template: unclosed block at line 1 and column 24'
3465
        )
3466
        two_pubs.loggederror_class.wipe()
3421
    assert two_pubs.loggederror_class.count() == 1
3422
    logged_error = two_pubs.loggederror_class.select()[0]
3423
    assert (
3424
        logged_error.summary
3425
        == 'error in template for address string [syntax error in ezt template: unclosed block at line 1 and column 24]'
3426
    )
3427
    assert logged_error.formdata_id == str(formdata.id)
3428
    assert logged_error.exception_class == 'TemplateError'
3429
    assert (
3430
        logged_error.exception_message
3431
        == 'syntax error in ezt template: unclosed block at line 1 and column 24'
3432
    )
3433
    two_pubs.loggederror_class.wipe()
3467 3434

  
3468 3435
    # check for None
3469 3436
    item.address_string = '=None'
......
3492 3459
        http_get_page.side_effect = ConnectionError('some error')
3493 3460
        item.perform(formdata)
3494 3461
        assert formdata.geolocations == {}
3495
    if two_pubs.is_using_postgresql():
3496
        assert two_pubs.loggederror_class.count() == 1
3497
        logged_error = two_pubs.loggederror_class.select()[0]
3498
        assert logged_error.summary == 'error calling geocoding service [some error]'
3499
        assert logged_error.formdata_id == str(formdata.id)
3500
        assert logged_error.exception_class == 'ConnectionError'
3501
        assert logged_error.exception_message == 'some error'
3462
    assert two_pubs.loggederror_class.count() == 1
3463
    logged_error = two_pubs.loggederror_class.select()[0]
3464
    assert logged_error.summary == 'error calling geocoding service [some error]'
3465
    assert logged_error.formdata_id == str(formdata.id)
3466
    assert logged_error.exception_class == 'ConnectionError'
3467
    assert logged_error.exception_message == 'some error'
3502 3468

  
3503 3469

  
3504 3470
def test_geolocate_image(pub):
......
3583 3549
    formdata.geolocations = None
3584 3550
    formdata.data = {'2': '48.8337085'}
3585 3551
    item.map_variable = '=form_var_map'
3586
    if two_pubs.is_using_postgresql():
3587
        assert two_pubs.loggederror_class.count() == 1
3588
        logged_error = two_pubs.loggederror_class.select()[0]
3589
        assert logged_error.summary == 'error geolocating from map variable'
3590
        assert logged_error.formdata_id == str(formdata.id)
3591
        assert logged_error.exception_class == 'ValueError'
3592
        assert logged_error.exception_message == 'not enough values to unpack (expected 2, got 1)'
3552
    assert two_pubs.loggederror_class.count() == 1
3553
    logged_error = two_pubs.loggederror_class.select()[0]
3554
    assert logged_error.summary == 'error geolocating from map variable'
3555
    assert logged_error.formdata_id == str(formdata.id)
3556
    assert logged_error.exception_class == 'ValueError'
3557
    assert logged_error.exception_message == 'not enough values to unpack (expected 2, got 1)'
3593 3558

  
3594 3559

  
3595 3560
def test_geolocate_overwrite(pub):
......
4581 4546
    formdata = formdef.data_class().get(formdata.id)
4582 4547
    assert formdata.data['bo1'] == ''
4583 4548

  
4584
    if two_pubs.is_using_postgresql():
4585
        assert two_pubs.loggederror_class.count() == 0
4549
    assert two_pubs.loggederror_class.count() == 0
4586 4550

  
4587 4551
    item.fields = [{'field_id': 'bo1', 'value': '= ~ invalid python ~'}]
4588 4552
    item.perform(formdata)
4589 4553
    formdata = formdef.data_class().get(formdata.id)
4590
    if two_pubs.is_using_postgresql():
4591
        assert two_pubs.loggederror_class.count() == 1
4592
        logged_error = two_pubs.loggederror_class.select()[0]
4593
        assert logged_error.summary == 'Failed to compute Python expression'
4594
        assert logged_error.formdata_id == str(formdata.id)
4595
        assert logged_error.expression == ' ~ invalid python ~'
4596
        assert logged_error.expression_type == 'python'
4597
        assert logged_error.exception_class == 'SyntaxError'
4598
        assert logged_error.exception_message == 'invalid syntax (<string>, line 1)'
4554
    assert two_pubs.loggederror_class.count() == 1
4555
    logged_error = two_pubs.loggederror_class.select()[0]
4556
    assert logged_error.summary == 'Failed to compute Python expression'
4557
    assert logged_error.formdata_id == str(formdata.id)
4558
    assert logged_error.expression == ' ~ invalid python ~'
4559
    assert logged_error.expression_type == 'python'
4560
    assert logged_error.exception_class == 'SyntaxError'
4561
    assert logged_error.exception_message == 'invalid syntax (<string>, line 1)'
4599 4562

  
4600
    if two_pubs.is_using_postgresql():
4601
        two_pubs.loggederror_class.wipe()
4563
    two_pubs.loggederror_class.wipe()
4602 4564
    item.fields = [{'field_id': 'bo1', 'value': '{% if bad django %}'}]
4603 4565
    item.perform(formdata)
4604 4566
    formdata = formdef.data_class().get(formdata.id)
4605
    if two_pubs.is_using_postgresql():
4606
        assert two_pubs.loggederror_class.count() == 1
4607
        logged_error = two_pubs.loggederror_class.select()[0]
4608
        assert logged_error.summary == 'Failed to compute template'
4609
        assert logged_error.formdata_id == str(formdata.id)
4610
        assert logged_error.expression == '{% if bad django %}'
4611
        assert logged_error.expression_type == 'template'
4612
        assert logged_error.exception_class == 'TemplateError'
4613
        assert logged_error.exception_message.startswith('syntax error in Django template')
4567
    assert two_pubs.loggederror_class.count() == 1
4568
    logged_error = two_pubs.loggederror_class.select()[0]
4569
    assert logged_error.summary == 'Failed to compute template'
4570
    assert logged_error.formdata_id == str(formdata.id)
4571
    assert logged_error.expression == '{% if bad django %}'
4572
    assert logged_error.expression_type == 'template'
4573
    assert logged_error.exception_class == 'TemplateError'
4574
    assert logged_error.exception_message.startswith('syntax error in Django template')
4614 4575

  
4615 4576

  
4616 4577
def test_set_backoffice_field_map(http_requests, two_pubs):
......
4652 4613
    formdata = formdef.data_class().get(formdata.id)
4653 4614
    assert formdata.data.get('bo1') is None
4654 4615

  
4655
    if two_pubs.is_using_postgresql():
4656
        assert two_pubs.loggederror_class.count() == 0
4616
    assert two_pubs.loggederror_class.count() == 0
4657 4617

  
4658 4618
    item.fields = [{'field_id': 'bo1', 'value': 'invalid value'}]
4659 4619
    item.perform(formdata)
4660 4620
    formdata = formdef.data_class().get(formdata.id)
4661
    if two_pubs.is_using_postgresql():
4662
        assert two_pubs.loggederror_class.count() == 1
4663
        logged_error = two_pubs.loggederror_class.select()[0]
4664
        assert (
4665
            logged_error.summary
4666
            == "Failed to set Map field (bo1), error: invalid coordinates 'invalid value' (missing ;)"
4667
        )
4668
        assert logged_error.formdata_id == str(formdata.id)
4669
        assert logged_error.exception_class == 'SetValueError'
4670
        assert logged_error.exception_message == "invalid coordinates 'invalid value' (missing ;)"
4671
        two_pubs.loggederror_class.wipe()
4621
    assert two_pubs.loggederror_class.count() == 1
4622
    logged_error = two_pubs.loggederror_class.select()[0]
4623
    assert (
4624
        logged_error.summary
4625
        == "Failed to set Map field (bo1), error: invalid coordinates 'invalid value' (missing ;)"
4626
    )
4627
    assert logged_error.formdata_id == str(formdata.id)
4628
    assert logged_error.exception_class == 'SetValueError'
4629
    assert logged_error.exception_message == "invalid coordinates 'invalid value' (missing ;)"
4630
    two_pubs.loggederror_class.wipe()
4672 4631

  
4673 4632
    item.fields = [{'field_id': 'bo1', 'value': 'XXX;YYY'}]
4674 4633
    item.perform(formdata)
4675 4634
    formdata = formdef.data_class().get(formdata.id)
4676
    if two_pubs.is_using_postgresql():
4677
        assert two_pubs.loggederror_class.count() == 1
4678
        logged_error = two_pubs.loggederror_class.select()[0]
4679
        assert logged_error.summary == "Failed to set Map field (bo1), error: invalid coordinates 'XXX;YYY'"
4680
        assert logged_error.formdata_id == str(formdata.id)
4681
        assert logged_error.exception_class == 'SetValueError'
4682
        assert logged_error.exception_message == "invalid coordinates 'XXX;YYY'"
4683
        two_pubs.loggederror_class.wipe()
4635
    assert two_pubs.loggederror_class.count() == 1
4636
    logged_error = two_pubs.loggederror_class.select()[0]
4637
    assert logged_error.summary == "Failed to set Map field (bo1), error: invalid coordinates 'XXX;YYY'"
4638
    assert logged_error.formdata_id == str(formdata.id)
4639
    assert logged_error.exception_class == 'SetValueError'
4640
    assert logged_error.exception_message == "invalid coordinates 'XXX;YYY'"
4641
    two_pubs.loggederror_class.wipe()
4684 4642

  
4685 4643

  
4686 4644
def test_set_backoffice_field_decimal(http_requests, two_pubs):
......
4977 4935
        item.parent = st1
4978 4936
        item.fields = [{'field_id': 'bo1', 'value': value}]
4979 4937

  
4980
        if two_pubs.is_using_postgresql():
4981
            two_pubs.loggederror_class.wipe()
4938
        two_pubs.loggederror_class.wipe()
4982 4939
        item.perform(formdata)
4983 4940

  
4984 4941
        formdata = formdef.data_class().get(formdata.id)
4985 4942
        assert formdata.data['bo1'].base_filename == 'hello.txt'
4986 4943
        assert formdata.data['bo1'].get_content() == b'HELLO WORLD'
4987
        if two_pubs.is_using_postgresql():
4988
            assert two_pubs.loggederror_class.count() == 1
4989
            logged_error = two_pubs.loggederror_class.select()[0]
4990
            assert logged_error.summary.startswith('Failed to convert')
4991
            assert logged_error.formdata_id == str(formdata.id)
4992
            assert logged_error.exception_class == 'ValueError'
4944
        assert two_pubs.loggederror_class.count() == 1
4945
        logged_error = two_pubs.loggederror_class.select()[0]
4946
        assert logged_error.summary.startswith('Failed to convert')
4947
        assert logged_error.formdata_id == str(formdata.id)
4948
        assert logged_error.exception_class == 'ValueError'
4993 4949

  
4994 4950
    # check wrong field
4995 4951
    item = SetBackofficeFieldsWorkflowStatusItem()
......
5207 5163
    assert formdata.data['bo1_structured']['attr'] == 'attr1'
5208 5164

  
5209 5165
    # reset, with unknown value
5210
    if two_pubs.is_using_postgresql():
5211
        two_pubs.loggederror_class.wipe()
5166
    two_pubs.loggederror_class.wipe()
5212 5167
    formdata.data = {}
5213 5168
    formdata.store()
5214 5169
    item.fields = [{'field_id': 'bo1', 'value': 'xxx'}]
......
5217 5172
    assert formdata.data.get('bo1') is None  # invalid value is not stored
5218 5173
    assert formdata.data.get('bo1_display') is None
5219 5174
    assert formdata.data.get('bo1_structured') is None
5220
    if two_pubs.is_using_postgresql():
5221
        assert two_pubs.loggederror_class.count() == 1
5222
        logged_error = two_pubs.loggederror_class.select()[0]
5223
        assert logged_error.summary.startswith('Failed to convert')
5175
    assert two_pubs.loggederror_class.count() == 1
5176
    logged_error = two_pubs.loggederror_class.select()[0]
5177
    assert logged_error.summary.startswith('Failed to convert')
5224 5178

  
5225 5179
    # reset, and get empty value
5226 5180
    formdata.data = {}
......
5398 5352
    assert len(formdata.data['bo1_structured']) == 1
5399 5353

  
5400 5354
    # using an invalid value
5401
    if two_pubs.is_using_postgresql():
5402
        formdata.data = {}
5403
        formdata.store()
5404
        two_pubs.loggederror_class.wipe()
5405
        item = SetBackofficeFieldsWorkflowStatusItem()
5406
        item.parent = st1
5407
        item.fields = [{'field_id': 'bo1', 'value': "=Ellipsis"}]
5408
        item.perform(formdata)
5409
        assert two_pubs.loggederror_class.count() == 1
5410
        logged_error = two_pubs.loggederror_class.select()[0]
5411
        assert 'Failed to convert' in logged_error.summary
5355
    formdata.data = {}
5356
    formdata.store()
5357
    two_pubs.loggederror_class.wipe()
5358
    item = SetBackofficeFieldsWorkflowStatusItem()
5359
    item.parent = st1
5360
    item.fields = [{'field_id': 'bo1', 'value': "=Ellipsis"}]
5361
    item.perform(formdata)
5362
    assert two_pubs.loggederror_class.count() == 1
5363
    logged_error = two_pubs.loggederror_class.select()[0]
5364
    assert 'Failed to convert' in logged_error.summary
5412 5365

  
5413 5366
    # using a string with multiple values
5414 5367
    item = SetBackofficeFieldsWorkflowStatusItem()
......
5473 5426
    assert datetime.date(*formdata.data['bo1'][:3]) == datetime.date(2017, 3, 23)
5474 5427

  
5475 5428
    # invalid values => do nothing
5476
    if two_pubs.is_using_postgresql():
5477
        assert two_pubs.loggederror_class.count() == 0
5429
    assert two_pubs.loggederror_class.count() == 0
5478 5430
    for value in ('plop', '={}', '=[]'):
5479 5431
        item = SetBackofficeFieldsWorkflowStatusItem()
5480 5432
        item.parent = st1
5481 5433
        item.fields = [{'field_id': 'bo1', 'value': value}]
5482 5434

  
5483
        if two_pubs.is_using_postgresql():
5484
            two_pubs.loggederror_class.wipe()
5435
        two_pubs.loggederror_class.wipe()
5485 5436
        item.perform(formdata)
5486 5437
        formdata = formdef.data_class().get(formdata.id)
5487 5438
        assert datetime.date(*formdata.data['bo1'][:3]) == datetime.date(2017, 3, 23)
5488
        if two_pubs.is_using_postgresql():
5489
            assert two_pubs.loggederror_class.count() == 1
5490
            assert two_pubs.loggederror_class.select()[0].summary.startswith('Failed to convert')
5439
        assert two_pubs.loggederror_class.count() == 1
5440
        assert two_pubs.loggederror_class.select()[0].summary.startswith('Failed to convert')
5491 5441

  
5492 5442
    # None : empty date
5493 5443
    item = SetBackofficeFieldsWorkflowStatusItem()
......
5986 5936
    assert len(FormDef.get(formdef.id).data_class().get_actionable_ids([role.id])) == 2
5987 5937

  
5988 5938
    # bad condition
5989
    if two_pubs.is_using_postgresql():
5990
        two_pubs.loggederror_class.wipe()
5939
    two_pubs.loggederror_class.wipe()
5991 5940
    choice.condition = {'type': 'python', 'value': 'foobar == barfoo'}
5992 5941
    workflow.store()
5993 5942
    assert len(FormDef.get(formdef.id).data_class().get_actionable_ids([role.id])) == 0
5994
    if two_pubs.is_using_postgresql():
5995
        assert two_pubs.loggederror_class.count() == 1
5996
        logged_error = two_pubs.loggederror_class.select()[0]
5997
        assert logged_error.occurences_count > 1  # should be 2... == 12 with pickle, 4 with sql
5998
        assert logged_error.summary == 'Failed to evaluate condition'
5999
        assert logged_error.exception_class == 'NameError'
6000
        assert logged_error.exception_message == "name 'foobar' is not defined"
6001
        assert logged_error.expression == 'foobar == barfoo'
6002
        assert logged_error.expression_type == 'python'
5943
    assert two_pubs.loggederror_class.count() == 1
5944
    logged_error = two_pubs.loggederror_class.select()[0]
5945
    assert logged_error.occurences_count > 1  # should be 2... == 12 with pickle, 4 with sql
5946
    assert logged_error.summary == 'Failed to evaluate condition'
5947
    assert logged_error.exception_class == 'NameError'
5948
    assert logged_error.exception_message == "name 'foobar' is not defined"
5949
    assert logged_error.expression == 'foobar == barfoo'
5950
    assert logged_error.expression_type == 'python'
6003 5951

  
6004 5952

  
6005 5953
def test_workflow_field_migration(pub):
......
6517 6465

  
6518 6466

  
6519 6467
def test_call_external_workflow_manual_targeting(two_pubs):
6520
    if not two_pubs.is_using_postgresql():
6521
        pytest.skip('this requires SQL')
6522
        return
6523

  
6524 6468
    FormDef.wipe()
6525 6469
    CardDef.wipe()
6526 6470

  
......
6701 6645

  
6702 6646

  
6703 6647
def test_call_external_workflow_manual_queryset_targeting(two_pubs):
6704
    if not two_pubs.is_using_postgresql():
6705
        pytest.skip('this requires SQL')
6706
        return
6707

  
6708 6648
    FormDef.wipe()
6709 6649
    CardDef.wipe()
6710 6650

  
tests/workflow/test_carddata.py
104 104

  
105 105
    assert carddef.data_class().count() == 1
106 106

  
107
    if two_pubs.is_using_postgresql():
108
        errors = two_pubs.loggederror_class.select()
109
        assert len(errors) == 2
110
        assert any('form_var_undefined' in (error.exception_message or '') for error in errors)
111
        assert any('invalid date value' in (error.exception_message or '') for error in errors)
107
    errors = two_pubs.loggederror_class.select()
108
    assert len(errors) == 2
109
    assert any('form_var_undefined' in (error.exception_message or '') for error in errors)
110
    assert any('invalid date value' in (error.exception_message or '') for error in errors)
112 111

  
113 112
    formdata = formdef.data_class()()
114 113
    today = datetime.date.today()
......
384 383
    assert carddef.data_class().count() == 1
385 384
    assert not carddef.data_class().select()[0].data.get('1')
386 385

  
387
    if two_pubs.is_using_postgresql():
388
        errors = two_pubs.loggederror_class.select()
389
        assert len(errors) == 1
390
        assert any('invalid coordinates' in (error.exception_message or '') for error in errors)
386
    errors = two_pubs.loggederror_class.select()
387
    assert len(errors) == 1
388
    assert any('invalid coordinates' in (error.exception_message or '') for error in errors)
391 389

  
392 390
    # value from formdata
393 391
    create.mappings[0].expression = '{{ form_var_map }}'
......
742 740

  
743 741

  
744 742
def test_edit_carddata_manual_targeting(two_pubs):
745
    if not two_pubs.is_using_postgresql():
746
        pytest.skip('this requires SQL')
747
        return
748

  
749 743
    FormDef.wipe()
750 744
    CardDef.wipe()
751 745

  
......
1142 1136

  
1143 1137

  
1144 1138
def test_assign_carddata_manual_targeting(two_pubs):
1145
    if not two_pubs.is_using_postgresql():
1146
        pytest.skip('this requires SQL')
1147
        return
1148

  
1149 1139
    FormDef.wipe()
1150 1140
    CardDef.wipe()
1151 1141
    two_pubs.user_class.wipe()
tests/workflow/test_formdata.py
82 82
    formdata.just_created()
83 83

  
84 84
    assert target_formdef.data_class().count() == 0
85
    if two_pubs.is_using_postgresql():
86
        assert two_pubs.loggederror_class.count() == 0
85
    assert two_pubs.loggederror_class.count() == 0
87 86
    # check unconfigure action do nothing
88 87
    formdata.perform_workflow()
89 88
    assert target_formdef.data_class().count() == 0
......
94 93
    formdata.perform_workflow()
95 94
    assert target_formdef.data_class().count() == 1
96 95

  
97
    if two_pubs.is_using_postgresql():
98
        errors = two_pubs.loggederror_class.select()
99
        assert len(errors) == 2
100
        assert 'form_var_toto_string' in errors[0].exception_message
101
        assert errors[1].summary == 'Missing field: unknown (1), unknown (2)'
102
        assert errors[0].formdata_id == str(target_formdef.data_class().select()[0].id)
103
        assert errors[1].formdata_id == str(target_formdef.data_class().select()[0].id)
104

  
105
    if two_pubs.is_using_postgresql():
106
        # add field labels cache
107
        two_pubs.loggederror_class.wipe()
108
        target_formdef.data_class().wipe()
109
        create.formdef_slug = target_formdef.url_name
110
        create.cached_field_labels = {'0': 'field0', '1': 'field1', '2': 'field2'}
111
        wf.store()
112
        del source_formdef._workflow
113
        formdata.perform_workflow()
114
        assert target_formdef.data_class().count() == 1
115

  
116
        errors = two_pubs.loggederror_class.select()
117
        assert len(errors) == 2
118
        assert errors[1].summary == 'Missing field: field1, field2'
96
    errors = two_pubs.loggederror_class.select()
97
    assert len(errors) == 2
98
    assert 'form_var_toto_string' in errors[0].exception_message
99
    assert errors[1].summary == 'Missing field: unknown (1), unknown (2)'
100
    assert errors[0].formdata_id == str(target_formdef.data_class().select()[0].id)
101
    assert errors[1].formdata_id == str(target_formdef.data_class().select()[0].id)
102

  
103
    # add field labels cache
104
    two_pubs.loggederror_class.wipe()
105
    target_formdef.data_class().wipe()
106
    create.formdef_slug = target_formdef.url_name
107
    create.cached_field_labels = {'0': 'field0', '1': 'field1', '2': 'field2'}
108
    wf.store()
109
    del source_formdef._workflow
110
    formdata.perform_workflow()
111
    assert target_formdef.data_class().count() == 1
112

  
113
    errors = two_pubs.loggederror_class.select()
114
    assert len(errors) == 2
115
    assert errors[1].summary == 'Missing field: field1, field2'
119 116

  
120 117
    # no tracking code has been created
121 118
    created_formdata = target_formdef.data_class().select()[0]
......
274 271

  
275 272

  
276 273
def test_create_formdata_card_item_mapping(two_pubs):
277
    if two_pubs.is_using_postgresql():
278
        two_pubs.loggederror_class.wipe()
274
    two_pubs.loggederror_class.wipe()
279 275
    FormDef.wipe()
280 276
    CardDef.wipe()
281 277

  
......
367 363
    target_formdata = target_formdef.data_class().select()[0]
368 364
    assert target_formdata.data.get('0') is None
369 365
    assert target_formdata.data.get('0_display') is None
370
    if two_pubs.is_using_postgresql():
371
        assert two_pubs.loggederror_class.count() == 1
372
        assert two_pubs.loggederror_class.count() == 1
373
        error = two_pubs.loggederror_class.select()[0]
374
        assert error.exception_message == "unknown card value ('XXX')"
366
    assert two_pubs.loggederror_class.count() == 1
367
    assert two_pubs.loggederror_class.count() == 1
368
    error = two_pubs.loggederror_class.select()[0]
369
    assert error.exception_message == "unknown card value ('XXX')"
wcs/admin/data_sources.py
539 539
                'categories': categories,
540 540
                'user_data_sources': user_data_sources,
541 541
                'has_chrono': has_chrono(get_publisher()),
542
                'has_users': get_publisher().is_using_postgresql(),
542
                'has_users': True,
543 543
                'agenda_data_sources': agenda_data_sources,
544 544
                'generated_data_sources': generated_data_sources,
545 545
            },
wcs/admin/forms.py
16 16

  
17 17
import difflib
18 18
import io
19
import tarfile
20
import time
21 19
import xml.etree.ElementTree as ET
22 20
from collections import defaultdict
23 21

  
......
604 602
        'duplicate',
605 603
        'export',
606 604
        'anonymise',
607
        'archive',
608 605
        'enable',
609 606
        'workflow',
610 607
        'role',
......
932 929
            r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
933 930
            r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
934 931
        r += htmltext('<li><a href="inspect">%s</a></li>') % _('Inspector')
935
        if not get_publisher().is_using_postgresql() and self.formdef_class == FormDef:
936
            r += htmltext('<li><a href="archive">%s</a></li>') % _('Archive')
937 932
        r += htmltext('</ul>')
938 933

  
939 934
        r += htmltext('<ul>')
......
1276 1271
        return redirect('../%s/' % self.formdefui.formdef.id)
1277 1272

  
1278 1273
    def get_check_deletion_message(self):
1279
        if not get_publisher().is_using_postgresql():
1280
            return None
1281 1274
        from wcs import sql
1282 1275

  
1283 1276
        criterias = [
......
1570 1563
            content_type='application/x-wcs-form',
1571 1564
        )
1572 1565

  
1573
    def archive(self):
1574
        if get_publisher().is_using_postgresql():
1575
            raise TraversalError()
1576

  
1577
        if get_request().form.get('download'):
1578
            return self.archive_download()
1579

  
1580
        form = Form(enctype='multipart/form-data')
1581

  
1582
        form.add(DateWidget, 'date', title=_('Archive forms handled before'))
1583
        form.add(CheckboxWidget, 'not-done', title=_('Include forms that have not been handled'), value=False)
1584
        form.add(CheckboxWidget, 'keep', title=_('Do not remove forms'), value=False)
1585
        form.add_submit('submit', _('Submit'))
1586
        form.add_submit('cancel', _('Cancel'))
1587

  
1588
        if form.get_widget('cancel').parse():
1589
            return redirect('.')
1590

  
1591
        if not form.is_submitted() or form.has_errors():
1592
            get_response().breadcrumb.append(('archive', _('Archive')))
1593
            self.html_top(title=_('Archive Forms'))
1594
            r = TemplateIO(html=True)
1595
            r += htmltext('<h2>%s</h2>') % _('Archive Forms')
1596
            r += form.render()
1597
            return r.getvalue()
1598
        else:
1599
            return self.archive_submit(form)
1600

  
1601
    def archive_submit(self, form):
1602
        class Archiver:
1603
            def __init__(self, formdef):
1604
                self.formdef = formdef
1605

  
1606
            def archive(self, job=None):
1607
                all_forms = self.formdef.data_class().select()
1608

  
1609
                if form.get_widget('not-done').parse() is False:
1610
                    not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
1611
                    not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
1612
                    all_forms = [x for x in all_forms if x.status not in not_endpoint_status_ids]
1613

  
1614
                if form.get_widget('date').parse():
1615
                    date = form.get_widget('date').parse()
1616
                    date = time.strptime(date, misc.date_format())
1617
                    all_forms = [x for x in all_forms if x.last_update_time < date]
1618

  
1619
                self.fd = io.BytesIO()
1620
                with tarfile.open('wcs.tar.gz', 'w:gz', fileobj=self.fd) as t:
1621
                    t.add(self.formdef.get_object_filename(), 'formdef')
1622
                    for formdata in all_forms:
1623
                        t.add(
1624
                            formdata.get_object_filename(),
1625
                            '%s/%s' % (self.formdef.url_name, str(formdata.id)),
1626
                        )
1627

  
1628
                if form.get_widget('keep').parse() is False:
1629
                    for f in all_forms:
1630
                        f.remove_self()
1631

  
1632
                if job:
1633
                    job.file_content = self.fd.getvalue()
1634
                    job.store()
1635

  
1636
        count = self.formdef.data_class().count()
1637
        archiver = Archiver(self.formdef)
1638
        if count > 100:  # Arbitrary threshold
1639
            job = get_response().add_after_job(
1640
                _('Archiving forms'),
1641
                archiver.archive,
1642
                done_action_url=self.formdef.get_admin_url() + 'archive?job=%(job_id)s',
1643
                done_action_label=_('Download Archive'),
1644
            )
1645
            job.store()
1646
            return redirect(job.get_processing_url())
1647
        else:
1648
            archiver.archive()
1649

  
1650
            response = get_response()
1651
            response.set_content_type('application/x-wcs-archive')
1652
            response.set_header(
1653
                'content-disposition', 'attachment; filename=%s-archive.wcs' % self.formdef.url_name
1654
            )
1655
            return archiver.fd.getvalue()
1656

  
1657
    def archive_download(self):
1658
        try:
1659
            job = AfterJob.get(get_request().form.get('download'))
1660
        except KeyError:
1661
            return redirect('.')
1662

  
1663
        if not job.status == 'completed':
1664
            raise TraversalError()
1665
        response = get_response()
1666
        response.set_content_type('application/x-wcs-archive')
1667
        response.set_header(
1668
            'content-disposition', 'attachment; filename=%s-archive.wcs' % self.formdef.url_name
1669
        )
1670
        return job.file_content
1671

  
1672 1566
    def enable(self):
1673 1567
        self.formdef.disabled = False
1674 1568
        self.formdef.store(comment=_('Enable'))
wcs/admin/logged_errors.py
221 221
            workflow_id=self.workflow_id,
222 222
        )
223 223
        links = ''
224
        if get_publisher().is_using_postgresql():
225
            links = pagination_links(offset, limit, total_count, load_js=False)
224
        links = pagination_links(offset, limit, total_count, load_js=False)
226 225
        return template.QommonTemplateResponse(
227 226
            templates=['wcs/backoffice/logged-errors.html'],
228 227
            context={
wcs/admin/settings.py
300 300
        self.publisher.cfg['users'] = users_cfg
301 301
        self.publisher.write_cfg()
302 302
        self.publisher._cached_user_fields_formdef = None
303
        if self.publisher.is_using_postgresql():
304
            from wcs import sql
303
        from wcs import sql
305 304

  
306
            sql.do_user_table()
305
        sql.do_user_table()
307 306

  
308 307

  
309 308
class UsersDirectory(Directory):
wcs/api.py
422 422
                raise AccessForbiddenError('user not allowed to ignore roles')
423 423

  
424 424
    def _q_index(self):
425
        if not get_publisher().is_using_postgresql():
426
            raise TraversalError()
427

  
428 425
        self.check_access()
429 426
        get_request()._user = get_user_from_api_query_string() or get_request().user
430 427

  
......
491 488
        return json.dumps({'data': output}, cls=misc.JSONEncoder)
492 489

  
493 490
    def geojson(self):
494
        if not get_publisher().is_using_postgresql():
495
            raise TraversalError()
496 491
        self.check_access()
497 492
        get_request()._user = get_user_from_api_query_string() or get_request().user
498 493
        return ManagementDirectory().geojson()
......
743 738
            if include_count:
744 739
                # we include the count of submitted forms so it's possible to sort
745 740
                # them by "popularity"
746
                if get_publisher().is_using_postgresql():
747
                    from wcs import sql
748

  
749
                    # 4 * number of submitted forms of last 2 days
750
                    # + 2 * number of submitted forms of last 8 days
751
                    # + 1 * number of submitted forms of last 30 days
752
                    # exclude drafts
753
                    criterias = [Equal('formdef_id', formdef.id), StrictNotEqual('status', 'draft')]
754
                    d_now = datetime.datetime.now()
755
                    count = 4 * sql.get_period_total(
756
                        period_start=d_now - datetime.timedelta(days=2),
757
                        include_start=True,
758
                        criterias=criterias,
759
                    )
760
                    count += 2 * sql.get_period_total(
761
                        period_start=d_now - datetime.timedelta(days=8),
762
                        include_start=True,
763
                        period_end=d_now - datetime.timedelta(days=2),
764
                        include_end=False,
765
                        criterias=criterias,
766
                    )
767
                    count += sql.get_period_total(
768
                        period_start=d_now - datetime.timedelta(days=30),
769
                        include_start=True,
770
                        period_end=d_now - datetime.timedelta(days=8),
771
                        include_end=False,
772
                        criterias=criterias,
773
                    )
774
                else:
775
                    # naive count
776
                    count = formdef.data_class().count()
741
                from wcs import sql
742

  
743
                # 4 * number of submitted forms of last 2 days
744
                # + 2 * number of submitted forms of last 8 days
745
                # + 1 * number of submitted forms of last 30 days
746
                # exclude drafts
747
                criterias = [Equal('formdef_id', formdef.id), StrictNotEqual('status', 'draft')]
748
                d_now = datetime.datetime.now()
749
                count = 4 * sql.get_period_total(
750
                    period_start=d_now - datetime.timedelta(days=2),
751
                    include_start=True,
752
                    criterias=criterias,
753
                )
754
                count += 2 * sql.get_period_total(
755
                    period_start=d_now - datetime.timedelta(days=8),
756
                    include_start=True,
757
                    period_end=d_now - datetime.timedelta(days=2),
758
                    include_end=False,
759
                    criterias=criterias,
760
                )
761
                count += sql.get_period_total(
762
                    period_start=d_now - datetime.timedelta(days=30),
763
                    include_start=True,
764
                    period_end=d_now - datetime.timedelta(days=8),
765
                    include_end=False,
766
                    criterias=criterias,
767
                )
777 768
                formdict['count'] = count
778 769

  
779 770
            formdict['functions'] = {}
......
923 914
        if category_slugs:
924 915
            categories = Category.select([Contains('url_name', category_slugs)])
925 916

  
926
        if get_publisher().is_using_postgresql():
927
            from wcs import sql
917
        from wcs import sql
928 918

  
929
            order_by = 'receipt_time'
930
            if get_request().form.get('sort') == 'desc':
931
                order_by = '-receipt_time'
932
            if get_query_flag('include-accessible'):
933
                user_roles = user.get_roles()
934
                criterias = [
919
        order_by = 'receipt_time'
920
        if get_request().form.get('sort') == 'desc':
921
            order_by = '-receipt_time'
922
        if get_query_flag('include-accessible'):
923
            user_roles = user.get_roles()
924
            criterias = [
925
                Or(
926
                    [
927
                        Intersects('concerned_roles_array', user_roles),
928
                        Equal('user_id', str(user.id)),
929
                    ]
930
                )
931
            ]
932
        else:
933
            criterias = [Equal('user_id', str(user.id))]
934
        if category_slugs:
935
            criterias.append(Contains('category_id', [c.id for c in categories]))
936

  
937
        status_criteria = get_request().form.get('status') or 'all'
938
        if status_criteria == 'open':
939
            criterias.append(Equal('is_at_endpoint', False))
940
        elif status_criteria == 'done':
941
            criterias.append(Equal('is_at_endpoint', True))
942
        elif status_criteria == 'all':
943
            pass
944
        else:
945
            return HttpResponseBadRequest('invalid status parameter value')
946

  
947
        if include_drafts:
948
            disabled_formdef_ids = [formdef.id for formdef in FormDef.select() if formdef.is_disabled()]
949
            if disabled_formdef_ids:
950
                criterias.append(
935 951
                    Or(
936 952
                        [
937
                            Intersects('concerned_roles_array', user_roles),
938
                            Equal('user_id', str(user.id)),
953
                            StrictNotEqual('status', 'draft'),
954
                            NotContains('formdef_id', disabled_formdef_ids),
939 955
                        ]
940 956
                    )
941
                ]
942
            else:
943
                criterias = [Equal('user_id', str(user.id))]
944
            if category_slugs:
945
                criterias.append(Contains('category_id', [c.id for c in categories]))
946

  
947
            status_criteria = get_request().form.get('status') or 'all'
948
            if status_criteria == 'open':
949
                criterias.append(Equal('is_at_endpoint', False))
950
            elif status_criteria == 'done':
951
                criterias.append(Equal('is_at_endpoint', True))
952
            elif status_criteria == 'all':
953
                pass
954
            else:
955
                return HttpResponseBadRequest('invalid status parameter value')
956

  
957
            if include_drafts:
958
                disabled_formdef_ids = [formdef.id for formdef in FormDef.select() if formdef.is_disabled()]
959
                if disabled_formdef_ids:
960
                    criterias.append(
961
                        Or(
962
                            [
963
                                StrictNotEqual('status', 'draft'),
964
                                NotContains('formdef_id', disabled_formdef_ids),
965
                            ]
966
                        )
967
                    )
968
            else:
969
                criterias.append(StrictNotEqual('status', 'draft'))
957
                )
958
        else:
959
            criterias.append(StrictNotEqual('status', 'draft'))
970 960

  
971
            if not include_non_drafts:
972
                criterias.append(Equal('status', 'draft'))
961
        if not include_non_drafts:
962
            criterias.append(Equal('status', 'draft'))
973 963

  
974
            user_forms = sql.AnyFormData.select(
975
                criterias,
976
                limit=misc.get_int_or_400(get_request().form.get('limit')),
977
                offset=misc.get_int_or_400(get_request().form.get('offset')),
978
                order_by=order_by,
979
            )
980
            if get_request().form.get('full') == 'on':
981
                # load full objects
982
                formdefs = {x.formdef_id: x.formdef for x in user_forms}
983
                formdef_user_forms = {}
984
                for formdef_id, formdef in formdefs.items():
985
                    formdef_user_forms.update(
986
                        {
987
                            (formdef_id, x.id): x
988
                            for x in formdef.data_class().select(
989
                                [Contains('id', [x.id for x in user_forms if x.formdef_id == formdef_id])]
990
                            )
991
                        }
992
                    )
993
                # and put them back in order
994
                sorted_user_forms_tuples = [(x.formdef_id, x.id) for x in user_forms]
995
                user_forms = [formdef_user_forms.get(x) for x in sorted_user_forms_tuples]
996
            else:
997
                # prefetch evolutions to avoid individual loads when computing
998
                # formdata.get_visible_status().
999
                sql.AnyFormData.load_all_evolutions(user_forms)
964
        user_forms = sql.AnyFormData.select(
965
            criterias,
966
            limit=misc.get_int_or_400(get_request().form.get('limit')),
967
            offset=misc.get_int_or_400(get_request().form.get('offset')),
968
            order_by=order_by,
969
        )
970
        if get_request().form.get('full') == 'on':
971
            # load full objects
972
            formdefs = {x.formdef_id: x.formdef for x in user_forms}
973
            formdef_user_forms = {}
974
            for formdef_id, formdef in formdefs.items():
975
                formdef_user_forms.update(
976
                    {
977
                        (formdef_id, x.id): x
978
                        for x in formdef.data_class().select(
979
                            [Contains('id', [x.id for x in user_forms if x.formdef_id == formdef_id])]
980
                        )
981
                    }
982
                )
983
            # and put them back in order
984
            sorted_user_forms_tuples = [(x.formdef_id, x.id) for x in user_forms]
985
            user_forms = [formdef_user_forms.get(x) for x in sorted_user_forms_tuples]
1000 986
        else:
1001
            if get_query_flag('include-accessible'):
1002
                return HttpResponseBadRequest('not supported')
1003
            formdefs = FormDef.select()
1004
            user_forms = []
1005
            for formdef in formdefs:
1006
                user_forms.extend(formdef.data_class().get_with_indexed_value('user_id', user.id))
1007
            if category_slugs:
1008
                user_forms = [f for f in user_forms if f.formdef.category_id in [c.id for c in categories]]
1009

  
1010
            status_criteria = get_request().form.get('status') or 'all'
1011
            if status_criteria == 'open':
1012
                user_forms = [x for x in user_forms if not x.is_at_endpoint_status()]
1013
            elif status_criteria == 'done':
1014
                user_forms = [x for x in user_forms if x.is_at_endpoint_status()]
1015
            elif status_criteria == 'all':
1016
                pass
1017
            else:
1018
                return HttpResponseBadRequest('invalid status parameter value')
1019

  
1020
            typed_none = time.gmtime(-(10**10))
1021
            user_forms.sort(key=lambda x: x.receipt_time or typed_none)
1022
            if get_request().form.get('sort') == 'desc':
1023
                user_forms.reverse()
987
            # prefetch evolutions to avoid individual loads when computing
988
            # formdata.get_visible_status().
989
            sql.AnyFormData.load_all_evolutions(user_forms)
1024 990
        return user_forms
1025 991

  
1026 992
    def drafts(self):
......
1056 1022
                    raise AccessForbiddenError('user not allowed to query data from others')
1057 1023
                # mark forms that are readable by querying user
1058 1024
                user_roles = set(query_user.get_roles())
1059
                if get_publisher().is_using_postgresql():
1060
                    # use concerned_roles_array attribute that was saved in the
1061
                    # table.
1062
                    for form in forms:
1063
                        form.readable = bool(set(form.concerned_roles_array).intersection(user_roles))
1064
                else:
1065
                    # recomputed concerned roles.
1066
                    for form in forms:
1067
                        concerned_roles_array = [str(x) for x in form.concerned_roles if x]
1068
                        form.readable = bool(set(concerned_roles_array).intersection(user_roles))
1025
                # use concerned_roles_array attribute that was saved in the
1026
                # table.
1027
                for form in forms:
1028
                    form.readable = bool(set(form.concerned_roles_array).intersection(user_roles))
1069 1029
                # ignore confidential forms
1070 1030
                forms = [x for x in forms if x.readable or not x.formdef.skip_from_360_view]
1071 1031

  
......
1132 1092
            for field in formdef.fields:
1133 1093
                if field.type in ('string', 'text', 'email'):
1134 1094
                    criteria_fields.append(st.ILike('f%s' % field.id, query))
1135
            if get_publisher().is_using_postgresql():
1136
                criteria_fields.append(st.FtsMatch(query))
1095
            criteria_fields.append(st.FtsMatch(query))
1137 1096
            criterias.append(st.Or(criteria_fields))
1138 1097

  
1139 1098
        def as_dict(user):
wcs/backoffice/cards.py
213 213
        if self.formdef.is_used():
214 214
            return _('Deletion is not possible as it is still used as datasource.')
215 215

  
216
        if not get_publisher().is_using_postgresql():
217
            return None
218

  
219 216
        criterias = [
220 217
            StrictNotEqual('status', 'draft'),
221 218
            Null('anonymised'),
wcs/backoffice/management.py
182 182
        forms_without_pending_stuff = []
183 183
        forms_with_pending_stuff = []
184 184

  
185
        using_postgresql = get_publisher().is_using_postgresql()
186
        if using_postgresql:
187
            from wcs import sql
185
        from wcs import sql
188 186

  
189
            actionable_counts = sql.get_actionable_counts(user_roles)
190
            total_counts = sql.get_total_counts(user_roles)
187
        actionable_counts = sql.get_actionable_counts(user_roles)
188
        total_counts = sql.get_total_counts(user_roles)
191 189

  
192 190
        def append_form_entry(formdef):
193
            if using_postgresql:
194
                count_forms = total_counts.get(formdef.id) or 0
195
                waiting_forms_count = actionable_counts.get(formdef.id) or 0
196
            else:
197
                formdef_data_class = formdef.data_class()
198
                count_forms = formdef_data_class.count() - len(
199
                    formdef_data_class.get_ids_with_indexed_value('status', 'draft')
200
                )
201
                waiting_forms_count = formdef_data_class.get_actionable_count(user_roles)
191
            count_forms = total_counts.get(formdef.id) or 0
192
            waiting_forms_count = actionable_counts.get(formdef.id) or 0
202 193
            if waiting_forms_count == 0:
203 194
                forms_without_pending_stuff.append((formdef, waiting_forms_count, count_forms))
204 195
            else:
......
211 202

  
212 203
        def top_action_links(r):
213 204
            r += htmltext('<span class="actions">')
214
            if (
215
                get_publisher().is_using_postgresql()
216
                and get_publisher().get_site_option('postgresql_views') != 'false'
217
            ):
218
                r += htmltext('<a href="listing">%s</a>') % _('Global View')
205
            r += htmltext('<a href="listing">%s</a>') % _('Global View')
219 206
            for formdef in formdefs:
220 207
                if formdef.geolocations:
221 208
                    r += htmltext(' <a href="map">%s</a>') % _('Map View')
......
261 248

  
262 249
    def lookup(self):
263 250
        query = get_request().form.get('query', '').strip()
264
        if get_publisher().is_using_postgresql():
265
            from wcs import sql
251
        from wcs import sql
252

  
253
        formdatas = sql.AnyFormData.select([Equal('id_display', query)])
254
        if formdatas:
255
            return redirect(formdatas[0].get_url(backoffice=True))
266 256

  
267
            formdatas = sql.AnyFormData.select([Equal('id_display', query)])
268
            if formdatas:
269
                return redirect(formdatas[0].get_url(backoffice=True))
270 257
        if any(x for x in FormDef.select(lightweight=True) if x.enable_tracking_codes):
271 258
            try:
272 259
                tracking_code = get_publisher().tracking_code_class.get(query)
......
433 420
        period_start = parsed_values.get('period_start')
434 421
        period_end = parsed_values.get('period_end')
435 422

  
436
        if get_publisher().is_using_postgresql():
437
            from wcs import sql
438

  
439
            formdef_totals = sql.get_formdef_totals(period_start, period_end, criterias)
440
            counts = {str(x): y for x, y in formdef_totals}
441
        else:
442
            for formdef in formdefs:
443
                values = formdef.data_class().select(criterias)
444
                counts[formdef.id] = len(values)
423
        from wcs import sql
445 424

  
446
        do_graphs = False
447
        if (
448
            get_publisher().is_using_postgresql()
449
            and get_publisher().get_site_option('postgresql_views') != 'false'
450
        ):
451
            do_graphs = True
425
        formdef_totals = sql.get_formdef_totals(period_start, period_end, criterias)
426
        counts = {str(x): y for x, y in formdef_totals}
452 427

  
453 428
        r += htmltext('<p>%s %s</p>') % (_('Total count:'), sum(counts.values()))
454 429

  
455
        if do_graphs:
456
            r += htmltext('<div class="splitcontent-left">')
430
        r += htmltext('<div class="splitcontent-left">')
457 431
        cats = Category.select()
458 432
        for cat in cats:
459 433
            category_formdefs = [x for x in formdefs if x.category_id == cat.id]
......
462 436
        category_formdefs = [x for x in formdefs if x.category_id is None]
463 437
        r += self.category_global_stats(_('Misc'), category_formdefs, counts)
464 438

  
465
        if do_graphs:
466
            r += htmltext('</div>')
467
            r += htmltext('<div class="splitcontent-right">')
468
            r += do_graphs_section(period_start, period_end, criterias=[StrictNotEqual('status', 'draft')])
469
            r += htmltext('</div>')
439
        r += htmltext('</div>')
440
        r += htmltext('<div class="splitcontent-right">')
441
        r += do_graphs_section(period_start, period_end, criterias=[StrictNotEqual('status', 'draft')])
442
        r += htmltext('</div>')
470 443

  
471 444
        return r.getvalue()
472 445

  
......
597 570
        return r.getvalue()
598 571

  
599 572
    def listing(self):
600
        if not get_publisher().is_using_postgresql():
601
            raise errors.TraversalError()
602

  
603 573
        get_response().add_javascript(['wcs.listing.js'])
604 574
        from wcs import sql
605 575

  
......
731 701
        return rt.getvalue()
732 702

  
733 703
    def count(self):
734
        if not get_publisher().is_using_postgresql():
735
            raise errors.TraversalError()
736 704
        if not (FormDef.exists()):
737 705
            return misc.json_response({'count': 0})
738 706
        from wcs import sql
......
754 722
        return json.dumps(geojson_formdatas(formdatas, fields=fields), cls=misc.JSONEncoder)
755 723

  
756 724
    def map(self):
757
        if not get_publisher().is_using_postgresql():
758
            raise errors.TraversalError()
759 725
        get_response().add_javascript(['wcs.listing.js', 'qommon.map.js'])
760 726
        html_top('management', _('Global Map'))
761 727
        r = TemplateIO(html=True)
......
1051 1017
            'user-id',
1052 1018
            'user-function',
1053 1019
            'submission-agent-id',
1020
            'date',
1054 1021
        ]
1055
        if get_publisher().is_using_postgresql():
1056
            types.append('date')
1057 1022
        return types
1058 1023

  
1059 1024
    def get_filter_sidebar(
......
1200 1165
                    ('pending', C_('formdata|Open'), None),
1201 1166
                    ('done', _('Done'), None),
1202 1167
                ]
1203
                if mode == 'stats' and not get_publisher().is_using_postgresql():
1204
                    filters = [x for x in filters if x[0] != 'waiting']
1205 1168
                for status in waitpoint_status:
1206 1169
                    filters.append((status.id, status.name, status.colour))
1207 1170
                for filter_id, filter_label, filter_colour in filters:
......
1282 1245
            elif filter_field.type in ('item', 'items'):
1283 1246
                filter_field.required = False
1284 1247

  
1285
                if get_publisher().is_using_postgresql():
1286
                    # Get options from existing formdatas.
1287
                    # This allows for options that don't appear anymore in the
1288
                    # data source to be listed (for example because the field
1289
                    # is using a parametrized URL depending on unavailable
1290
                    # variables, or simply returning different results now).
1291
                    display_mode = 'select'
1292
                    if filter_field.type == 'item' and filter_field.get_display_mode() == 'autocomplete':
1293
                        display_mode = 'select2'
1294

  
1295
                    if display_mode == 'select':
1296
                        options = self.get_item_filter_options(
1297
                            filter_field,
1298
                            selected_filter,
1299
                            selected_filter_operator,
1300
                            criterias,
1301
                        )
1302
                        options = [(x[0], x[1], x[0]) for x in options]
1303
                        options.insert(0, (None, '', ''))
1304
                        attrs = {'data-refresh-options': str(filter_field.contextual_id)}
1305
                    else:
1306
                        options = [(filter_field_value, filter_field_value or '', filter_field_value or '')]
1307
                        attrs = {'data-remote-options': str(filter_field.contextual_id)}
1308
                        get_response().add_javascript(
1309
                            ['jquery.js', '../../i18n.js', 'qommon.forms.js', 'select2.js']
1310
                        )
1311
                        get_response().add_css_include('select2.css')
1312
                    if self.view and self.view.visibility == 'datasource':
1313
                        options.append(('{}', _('custom value'), '{}'))
1314
                        if filter_field_value and filter_field_value not in [x[0] for x in options]:
1315
                            options.append((filter_field_value, filter_field_value, filter_field_value))
1316
                        attrs['data-allow-template'] = 'true'
1317

  
1318
                    widget = SingleSelectWidget(
1319
                        filter_field_key,
1320
                        title=filter_field.label,
1321
                        options=options,
1322
                        value=filter_field_value,
1323
                        render_br=False,
1324
                        attrs=attrs,
1248
                # Get options from existing formdatas.
1249
                # This allows for options that don't appear anymore in the
1250
                # data source to be listed (for example because the field
1251
                # is using a parametrized URL depending on unavailable
1252
                # variables, or simply returning different results now).
1253
                display_mode = 'select'
1254
                if filter_field.type == 'item' and filter_field.get_display_mode() == 'autocomplete':
1255
                    display_mode = 'select2'
1256

  
1257
                if display_mode == 'select':
1258
                    options = self.get_item_filter_options(
1259
                        filter_field,
1260
                        selected_filter,
1261
                        selected_filter_operator,
1262
                        criterias,
1325 1263
                    )
1326
                    r += render_widget(widget, operators)
1327

  
1264
                    options = [(x[0], x[1], x[0]) for x in options]
1265
                    options.insert(0, (None, '', ''))
1266
                    attrs = {'data-refresh-options': str(filter_field.contextual_id)}
1328 1267
                else:
1329
                    # In pickle environments, get options from data source
1330
                    options = filter_field.get_options()
1331
                    if options:
1332
                        if len(options[0]) == 2:
1333
                            options = [(x[0], x[1], x[0]) for x in options]
1334
                        options.insert(0, (None, '', ''))
1335
                        widget = SingleSelectWidget(
1336
                            filter_field_key,
1337
                            title=filter_field.label,
1338
                            options=options,
1339
                            value=filter_field_value,
1340
                            render_br=False,
1341
                        )
1342
                        r += render_widget(widget, operators)
1343
                    else:
1344
                        # and fall back on a string widget if there are none.
1345
                        widget = StringWidget(
1346
                            filter_field_key,
1347
                            title=filter_field.label,
1348
                            value=filter_field_value,
1349
                            render_br=False,
1350
                        )
1351
                        r += render_widget(widget, operators)
1268
                    options = [(filter_field_value, filter_field_value or '', filter_field_value or '')]
1269
                    attrs = {'data-remote-options': str(filter_field.contextual_id)}
1270
                    get_response().add_javascript(
1271
                        ['jquery.js', '../../i18n.js', 'qommon.forms.js', 'select2.js']
1272
                    )
1273
                    get_response().add_css_include('select2.css')
1274
                if self.view and self.view.visibility == 'datasource':
1275
                    options.append(('{}', _('custom value'), '{}'))
1276
                    if filter_field_value and filter_field_value not in [x[0] for x in options]:
1277
                        options.append((filter_field_value, filter_field_value, filter_field_value))
1278
                    attrs['data-allow-template'] = 'true'
1279

  
1280
                widget = SingleSelectWidget(
1281
                    filter_field_key,
1282
                    title=filter_field.label,
1283
                    options=options,
1284
                    value=filter_field_value,
1285
                    render_br=False,
1286
                    attrs=attrs,
1287
                )
1288
                r += render_widget(widget, operators)
1352 1289

  
1353 1290
            elif filter_field.type == 'bool':
1354 1291
                options = [(None, '', ''), (True, _('Yes'), 'true'), (False, _('No'), 'false')]
......
1421 1358
        if limit:
1422 1359
            r += htmltext('<input type="hidden" name="limit" value="%s"/>') % limit
1423 1360

  
1424
        if get_publisher().is_using_postgresql():
1425
            if order_by is None:
1426
                order_by = get_publisher().get_site_option('default-sort-order') or '-receipt_time'
1427
            r += htmltext('<input type="hidden" name="order_by" value="%s"/>') % order_by
1361
        if order_by is None:
1362
            order_by = get_publisher().get_site_option('default-sort-order') or '-receipt_time'
1363
        r += htmltext('<input type="hidden" name="order_by" value="%s"/>') % order_by
1428 1364

  
1429
        if get_publisher().is_using_postgresql():
1430
            r += htmltext('<h3>%s</h3>') % self.search_label
1431
            if get_request().form.get('q'):
1432
                q = force_text(get_request().form.get('q'))
1433
                r += htmltext('<input class="inline-input" name="q" value="%s">') % force_str(q)
1434
            else:
1435
                r += htmltext('<input class="inline-input" name="q">')
1436
            r += htmltext('<button class="side-button">%s</button>') % _('Search')
1365
        r += htmltext('<h3>%s</h3>') % self.search_label
1366
        if get_request().form.get('q'):
1367
            q = force_text(get_request().form.get('q'))
1368
            r += htmltext('<input class="inline-input" name="q" value="%s">') % force_str(q)
1369
        else:
1370
            r += htmltext('<input class="inline-input" name="q">')
1371
        r += htmltext('<button class="side-button">%s</button>') % _('Search')
1437 1372

  
1438 1373
        r += self.get_filter_sidebar(
1439 1374
            selected_filter=selected_filter,
......
1664 1599
        yield FakeField('last_update_time', 'last_update_time', _('Last Modified'))
1665 1600

  
1666 1601
        # user fields
1667
        if not get_publisher().is_using_postgresql():
1668
            # full name of user, this will load individual user objects to get it
1669
            yield FakeField('user-label', 'user-label', _('User Label'))
1670
        else:
1671
            # user-label field but as a custom field, to get full name of user
1672
            # using a sql join clause.
1673
            yield UserLabelRelatedField()
1674
            for field in get_publisher().user_class.get_fields():
1675
                if not hasattr(field, 'get_view_value'):
1676
                    continue
1677
                field.has_relations = True
1678
                yield UserRelatedField(field)
1602
        # user-label field but as a custom field, to get full name of user
1603
        # using a sql join clause.
1604
        yield UserLabelRelatedField()
1605
        for field in get_publisher().user_class.get_fields():
1606
            if not hasattr(field, 'get_view_value'):
1607
                continue
1608
            field.has_relations = True
1609
            yield UserRelatedField(field)
1679 1610

  
1680 1611
        for field in self.formdef.iter_fields(include_block_fields=True):
1681 1612
            if getattr(field, 'block_field', None):
......
1683 1614
                    # not yet
1684 1615
                    continue
1685 1616
            yield field
1686
            if not get_publisher().is_using_postgresql():
1687
                continue
1688 1617
            if field.key == 'block':
1689 1618
                continue
1690 1619
            if getattr(field, 'block_field', None):
......
2145 2074
        selected_filter_operator = self.get_filter_operator_from_query()
2146 2075
        criterias = self.get_criterias_from_query()
2147 2076

  
2148
        if get_publisher().is_using_postgresql():
2149
            # only enable pagination in SQL mode, as we do not have sorting in
2150
            # the other case.
2151
            limit = misc.get_int_or_400(
2152
                get_request().form.get('limit', get_publisher().get_site_option('default-page-size') or 20)
2153
            )
2154
        else:
2155
            limit = misc.get_int_or_400(get_request().form.get('limit', 0))
2077
        limit = misc.get_int_or_400(
2078
            get_request().form.get('limit', get_publisher().get_site_option('default-page-size') or 20)
2079
        )
2156 2080
        offset = misc.get_int_or_400(get_request().form.get('offset', 0))
2157 2081
        order_by = misc.get_order_by_or_400(get_request().form.get('order_by'))
2158 2082
        if self.view and not order_by:
......
2251 2175
    def submit_multi(self, action, selected_filter, selected_filter_operator, query, criterias):
2252 2176
        item_ids = get_request().form['select[]']
2253 2177
        if '_all' in item_ids:
2254
            if get_publisher().is_using_postgresql():
2255
                criterias.append(Null('anonymised'))
2178
            criterias.append(Null('anonymised'))
2256 2179
            item_ids = FormDefUI(self.formdef).get_listing_item_ids(
2257 2180
                selected_filter,
2258 2181
                selected_filter_operator,
......
2444 2367
            offset=offset,
2445 2368
            limit=limit,
2446 2369
        )[0]
2447
        if get_publisher().is_using_postgresql():
2448
            self.formdef.data_class().load_all_evolutions(items)
2370
        self.formdef.data_class().load_all_evolutions(items)
2449 2371
        digest_key = 'default'
2450 2372
        if self.view and isinstance(self.formdef, CardDef):
2451 2373
            view_digest_key = 'custom-view:%s' % self.view.get_url_slug()
......
2455 2377
            output = []
2456 2378
            prefetched_users = None
2457 2379
            prefetched_roles = None
2458
            if get_publisher().is_using_postgresql:
2459
                prefetched_users = {
2460
                    str(x.id): x
2461
                    for x in get_publisher().user_class.get_ids(
2462
                        [x.user_id for x in items if x.user_id], ignore_errors=True
2463
                    )
2464
                    if x is not None
2465
                }
2466
                role_ids = set((self.formdef.workflow_roles or {}).values())
2467
                for filled in items:
2468
                    if filled.workflow_roles:
2469
                        for value in filled.workflow_roles.values():
2470
                            if not isinstance(value, list):
2471
                                value = [value]
2472
                            role_ids |= set(value)
2473
                prefetched_roles = {
2474
                    str(x.id): x
2475
                    for x in get_publisher().role_class.get_ids(role_ids, ignore_errors=True)
2476
                    if x is not None
2477
                }
2380
            prefetched_users = {
2381
                str(x.id): x
2382
                for x in get_publisher().user_class.get_ids(
2383
                    [x.user_id for x in items if x.user_id], ignore_errors=True
2384
                )
2385
                if x is not None
2386
            }
2387
            role_ids = set((self.formdef.workflow_roles or {}).values())
2388
            for filled in items:
2389
                if filled.workflow_roles:
2390
                    for value in filled.workflow_roles.values():
2391
                        if not isinstance(value, list):
2392
                            value = [value]
2393
                        role_ids |= set(value)
2394
            prefetched_roles = {
2395
                str(x.id): x
2396
                for x in get_publisher().role_class.get_ids(role_ids, ignore_errors=True)
2397
                if x is not None
2398
            }
2478 2399
            for filled in items:
2479 2400
                data = filled.get_json_export_dict(
2480 2401
                    include_files=False,
......
2717 2638
        get_response().filter['sidebar'] = self.get_formdata_sidebar() + self.get_stats_sidebar(
2718 2639
            selected_filter
2719 2640
        )
2720
        do_graphs = get_publisher().is_using_postgresql()
2721 2641

  
2722 2642
        displayed_criterias = None
2723 2643
        if selected_filter and selected_filter != 'all':
......
2749 2669
            criterias = [StrictNotEqual('status', 'draft')] + displayed_criterias
2750 2670

  
2751 2671
        values = self.formdef.data_class().select(criterias)
2752
        if get_publisher().is_using_postgresql():
2753
            # load all evolutions in a single batch, to avoid as many query as
2754
            # there are formdata when computing resolution times statistics.
2755
            self.formdef.data_class().load_all_evolutions(values)
2672
        # load all evolutions in a single batch, to avoid as many query as
2673
        # there are formdata when computing resolution times statistics.
2674
        self.formdef.data_class().load_all_evolutions(values)
2756 2675

  
2757 2676
        r += htmltext('<div id="statistics">')
2758 2677
        if displayed_criterias:
......
2764 2683
                if criteria_label:
2765 2684
                    r += htmltext('<li>%s</li>') % criteria_label
2766 2685
            r += htmltext('</ul></div>')
2767
        if do_graphs:
2768
            r += htmltext('<div class="splitcontent-left">')
2686
        r += htmltext('<div class="splitcontent-left">')
2769 2687

  
2770 2688
        no_forms = len(values)
2771 2689
        r += htmltext('<div class="bo-block">')
......
2799 2717
            r += stats_times
2800 2718
            r += htmltext('</div>')
2801 2719

  
2802
        if do_graphs:
2803
            r += htmltext('</div>')
2804
            r += htmltext('<div class="splitcontent-right">')
2805
            criterias.append(Equal('formdef_id', int(self.formdef.id)))
2806
            r += do_graphs_section(criterias=criterias)
2807
            r += htmltext('</div>')
2720
        r += htmltext('</div>')
2721
        r += htmltext('<div class="splitcontent-right">')
2722
        criterias.append(Equal('formdef_id', int(self.formdef.id)))
2723
        r += do_graphs_section(criterias=criterias)
2724
        r += htmltext('</div>')
2808 2725

  
2809 2726
        r += htmltext('</div>')  # id="statistics"
2810 2727

  
......
3165 3082
        if formdata.formdef.lateral_template:
3166 3083
            r += htmltext('<div data-async-url="%slateral-block"></div>' % formdata.get_url(backoffice=True))
3167 3084

  
3168
        if (
3169
            not isinstance(formdata.formdef, CardDef)
3170
            and formdata.user_id
3171
            and get_publisher().is_using_postgresql()
3172
        ):
3085
        if not isinstance(formdata.formdef, CardDef) and formdata.user_id:
3173 3086
            r += htmltext(
3174 3087
                '<div data-async-url="%suser-pending-forms"></div>' % formdata.get_url(backoffice=True)
3175 3088
            )
wcs/backoffice/submission.py
202 202
            return
203 203

  
204 204
        data_class = self.formdef.data_class()
205
        if get_publisher().is_using_postgresql():
206
            has = bool(
207
                data_class.count([StrictNotEqual('status', 'draft'), Equal('user_id', formdata.user_id)])
208
            )
209
        else:
210
            has = any(
211
                x for x in data_class.get_with_indexed_value('user_id', formdata.user_id) if not x.is_draft()
212
            )
213
        context['user_has_already_one_such_form'] = has
205
        context['user_has_already_one_such_form'] = bool(
206
            data_class.count([StrictNotEqual('status', 'draft'), Equal('user_id', formdata.user_id)])
207
        )
214 208

  
215 209
    def get_sidebar(self, data):
216 210
        r = TemplateIO(html=True)
wcs/carddef.py
60 60
            # carddef
61 61
            if data_class._formdef is self:
62 62
                return data_class
63
        if (get_publisher().is_using_postgresql() and not mode == 'files') or mode == 'sql':
63
        if (not mode == 'files') or mode == 'sql':
64 64
            from . import sql
65 65

  
66 66
            table_name = sql.get_formdef_table_name(self)
wcs/ctl/delete_tenant.py
51 51
            deletion_date = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
52 52
            os.rename(pub.app_dir, pub.app_dir + '_removed_%s.invalid' % deletion_date)
53 53

  
54
        # do this only if the wcs has a postgresql configuration
55
        if pub.is_using_postgresql():
56
            postgresql_cfg = {}
57
            for k, v in pub.cfg['postgresql'].items():
58
                if v and isinstance(v, str):
59
                    postgresql_cfg[k] = v
60

  
61
            # if there's a createdb-connection-params, we can do a DROP DATABASE with
62
            # the option --force-drop, rename it if not
63
            createdb_cfg = pub.cfg['postgresql'].get('createdb-connection-params', {})
64
            createdb = True
65
            if not createdb_cfg:
66
                createdb_cfg = postgresql_cfg
67
                createdb = False
68
            if 'database' in createdb_cfg:
69
                createdb_cfg['dbname'] = createdb_cfg.pop('database')
70
            try:
71
                pgconn = psycopg2.connect(**createdb_cfg)
72
            except psycopg2.Error as e:
73
                print(
74
                    'failed to connect to postgresql (%s)' % psycopg2.errorcodes.lookup(e.pgcode),
75
                    file=sys.stderr,
76
                )
77
                return
78

  
79
            pgconn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
80
            cur = pgconn.cursor()
81
            dbname = postgresql_cfg.get('dbname') or postgresql_cfg.get('database')
82
            try:
83
                if createdb:
84
                    if options.force_drop:
85
                        cur.execute('DROP DATABASE %s' % dbname)
86
                    else:
87
                        cur.execute(
88
                            'ALTER DATABASE %s RENAME TO removed_%s_%s' % (dbname, deletion_date, dbname)
89
                        )
54
        postgresql_cfg = {}
55
        for k, v in pub.cfg['postgresql'].items():
56
            if v and isinstance(v, str):
57
                postgresql_cfg[k] = v
58

  
59
        # if there's a createdb-connection-params, we can do a DROP DATABASE with
60
        # the option --force-drop, rename it if not
61
        createdb_cfg = pub.cfg['postgresql'].get('createdb-connection-params', {})
62
        createdb = True
63
        if not createdb_cfg:
64
            createdb_cfg = postgresql_cfg
65
            createdb = False
66
        if 'database' in createdb_cfg:
67
            createdb_cfg['dbname'] = createdb_cfg.pop('database')
68
        try:
69
            pgconn = psycopg2.connect(**createdb_cfg)
70
        except psycopg2.Error as e:
71
            print(
72
                'failed to connect to postgresql (%s)' % psycopg2.errorcodes.lookup(e.pgcode),
73
                file=sys.stderr,
74
            )
75
            return
76

  
77
        pgconn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
78
        cur = pgconn.cursor()
79
        dbname = postgresql_cfg.get('dbname') or postgresql_cfg.get('database')
80
        try:
81
            if createdb:
82
                if options.force_drop:
83
                    cur.execute('DROP DATABASE %s' % dbname)
90 84
                else:
91
                    cur.execute(
92
                        """SELECT table_name
93
                                   FROM information_schema.tables
94
                                   WHERE table_schema = 'public'
95
                                   AND table_type = 'BASE TABLE'"""
96
                    )
97

  
98
                    tables_names = [x[0] for x in cur.fetchall()]
99

  
100
                    if options.force_drop:
101
                        for table_name in tables_names:
102
                            cur.execute('DROP TABLE %s CASCADE' % table_name)
103

  
104
                    else:
105
                        schema_name = 'removed_%s_%s' % (deletion_date, dbname)
106
                        cur.execute("CREATE SCHEMA %s" % schema_name[:63])
107
                        for table_name in tables_names:
108
                            cur.execute('ALTER TABLE %s SET SCHEMA %s' % (table_name, schema_name[:63]))
109

  
110
            except psycopg2.Error as e:
111
                print(
112
                    'failed to alter database %s: (%s)' % (dbname, psycopg2.errorcodes.lookup(e.pgcode)),
113
                    file=sys.stderr,
85
                    cur.execute('ALTER DATABASE %s RENAME TO removed_%s_%s' % (dbname, deletion_date, dbname))
86
            else:
87
                cur.execute(
88
                    """SELECT table_name
89
                               FROM information_schema.tables
90
                               WHERE table_schema = 'public'
91
                               AND table_type = 'BASE TABLE'"""
114 92
                )
115
                return
116 93

  
117
            cur.close()
94
                tables_names = [x[0] for x in cur.fetchall()]
95

  
96
                if options.force_drop:
97
                    for table_name in tables_names:
98
                        cur.execute('DROP TABLE %s CASCADE' % table_name)
99

  
100
                else:
101
                    schema_name = 'removed_%s_%s' % (deletion_date, dbname)
102
                    cur.execute("CREATE SCHEMA %s" % schema_name[:63])
103
                    for table_name in tables_names:
104
                        cur.execute('ALTER TABLE %s SET SCHEMA %s' % (table_name, schema_name[:63]))
105

  
106
        except psycopg2.Error as e:
107
            print(
108
                'failed to alter database %s: (%s)' % (dbname, psycopg2.errorcodes.lookup(e.pgcode)),
109
                file=sys.stderr,
110
            )
111
            return
112

  
113
        cur.close()
118 114

  
119 115

  
120 116
CmdDeleteTenant.register()
wcs/ctl/rebuild_indexes.py
28 28
    if destroy:
29 29
        Role.destroy_indexes()
30 30
    Role.rebuild_indexes()
31
    if pub.is_using_postgresql():
32
        return
33
    from wcs.users import User
34

  
35
    if destroy:
36
        User.destroy_indexes()
37
    User.rebuild_indexes()
38
    for formdef in FormDef.select():
39
        formdata = formdef.data_class()
40
        if destroy:
41
            formdata.destroy_indexes()
42
        formdata.rebuild_indexes()
43 31

  
44 32

  
45 33
class CmdRebuildIndexes(Command):
wcs/formdata.py
424 424

  
425 425
    @classmethod
426 426
    def get_actionable_count(cls, user_roles):
427
        if get_publisher().is_using_postgresql():
428
            statuses = ['wf-%s' % x.id for x in cls._formdef.workflow.get_not_endpoint_status()]
429
            criterias = [
430
                Intersects('actions_roles_array', user_roles),
431
                Contains('status', statuses),
432
                Null('anonymised'),
433
            ]
434
            return cls.count(criterias)
435
        else:
436
            return len(cls.get_actionable_ids(user_roles))
427
        statuses = ['wf-%s' % x.id for x in cls._formdef.workflow.get_not_endpoint_status()]
428
        criterias = [
429
            Intersects('actions_roles_array', user_roles),
430
            Contains('status', statuses),
431
            Null('anonymised'),
432
        ]
433
        return cls.count(criterias)
437 434

  
438 435
    @classmethod
439 436
    def get_actionable_ids_criteria(cls, user_roles):
......
442 439

  
443 440
    @classmethod
444 441
    def get_actionable_ids(cls, user_roles):
445
        if get_publisher().is_using_postgresql():
446
            return cls.keys([cls.get_actionable_ids_criteria(user_roles)])
447
        else:
448
            statuses = ['wf-%s' % x.id for x in cls._formdef.workflow.get_not_endpoint_status()]
449
            actions_ids = set()
450
            for role in user_roles:
451
                actions_ids |= set(cls.get_ids_with_indexed_value('actions_roles', str(role)))
452
            open_ids = []
453
            for status_id in statuses:
454
                open_ids.extend(cls.get_ids_with_indexed_value('status', status_id))
455
            return list(actions_ids.intersection(open_ids))
442
        return cls.keys([cls.get_actionable_ids_criteria(user_roles)])
456 443

  
457 444
    @classmethod
458 445
    def get_submission_channels(cls):
wcs/formdef.py
44 44
from .qommon.form import Form, HtmlWidget, UploadedFile
45 45
from .qommon.misc import JSONEncoder, get_as_datetime, is_attachment, is_upload, simplify, xml_node_text
46 46
from .qommon.publisher import get_publisher_class
47
from .qommon.storage import Equal, StorableObject, StrictNotEqual, fix_key
47
from .qommon.storage import Equal, StorableObject, fix_key
48 48
from .qommon.substitution import Substitutions
49 49
from .qommon.template import Template
50 50
from .roles import logged_users_role
......
329 329
    @classmethod
330 330
    def remove_object(cls, id):
331 331
        super().remove_object(id)
332
        if get_publisher().is_using_postgresql() and cls == FormDef:
332
        if cls == FormDef:
333 333
            # recreate global views so they don't reference formdata from
334 334
            # deleted formefs
335 335
            from . import sql
......
352 352
            # formdef
353 353
            if data_class._formdef is self:
354 354
                return data_class
355
        if (get_publisher().is_using_postgresql() and not mode == 'files') or mode == 'sql':
355
        if (not mode == 'files') or mode == 'sql':
356 356
            from . import sql
357 357

  
358 358
            table_name = sql.get_formdef_table_name(self)
......
411 411
    @classmethod
412 412
    def get_new_id(cls, create=False):
413 413
        id = super().get_new_id(create=False)
414
        if get_publisher().is_using_postgresql():
415
            id = cls.get_sql_new_id(id_start=int(id))
414
        id = cls.get_sql_new_id(id_start=int(id))
416 415
        if create:
417 416
            objects_dir = cls.get_objects_dir()
418 417
            object_filename = os.path.join(objects_dir, fix_key(id))
......
443 442
    @classmethod
444 443
    def wipe(cls):
445 444
        super().wipe()
446
        if get_publisher().is_using_postgresql():
447
            cls.sql_wipe()
445
        cls.sql_wipe()
448 446

  
449 447
    @classmethod
450 448
    def sql_wipe(cls):
......
457 455
        if self.url_name is None:
458 456
            # set url name if it's not yet there
459 457
            self.url_name = self.get_new_url_name()
458

  
459
        object_only = kwargs.pop('object_only', False)
460

  
460 461
        new_internal_identifier = self.get_new_internal_identifier()
461 462
        if not self.internal_identifier:
462 463
            self.internal_identifier = new_internal_identifier
......
466 467
            # or if there are not yet any submitted forms (or if site
467 468
            # is using the SQL storage as internal identifier is not used
468 469
            # in that mode.
469
            if self.id is None or get_publisher().is_using_postgresql() or not (self.data_class().exists()):
470
            if self.id is None or not self.data_class().exists():
470 471
                self.internal_identifier = new_internal_identifier
471
        object_only = kwargs.pop('object_only', False)
472 472

  
473 473
        if not object_only:
474 474
            self.update_relations()
......
487 487
            self.store_related_custom_views()
488 488

  
489 489
    def update_storage(self):
490
        if not get_publisher().is_using_postgresql():
491
            return
492

  
493 490
        from . import sql
494 491

  
495 492
        actions = sql.do_formdef_tables(self, rebuild_views=True, rebuild_global_views=True)
......
1919 1916
                status.id in status_mapping for status in old_workflow.possible_status
1920 1917
            ), 'a status was not mapped'
1921 1918

  
1922
            unmapped_status_suffix = '-invalid-%s' % str(self.workflow_id or 'default')
1923 1919
            mapping = {}
1924 1920
            for old_status, new_status in status_mapping.items():
1925 1921
                mapping['wf-%s' % old_status] = 'wf-%s' % new_status
......
1927 1923

  
1928 1924
            if any(x[0] != x[1] for x in mapping.items()):
1929 1925
                # if there are status changes, update all formdatas (except drafts)
1930
                if get_publisher().is_using_postgresql():
1931
                    from . import sql
1932

  
1933
                    sql.formdef_remap_statuses(self, mapping)
1934
                else:
1926
                from . import sql
1935 1927

  
1936
                    def map_status(status):
1937
                        if status is None:
1938
                            return None
1939
                        elif status in mapping:
1940
                            return mapping[status]
1941
                        elif '-invalid-' in status:
1942
                            return status
1943
                        else:
1944
                            return '%s%s' % (status, unmapped_status_suffix)
1945

  
1946
                    for formdata in self.data_class().select([StrictNotEqual('status', 'draft')]):
1947
                        formdata.status = map_status(formdata.status)
1948
                        if formdata.evolution:
1949
                            for evo in formdata.evolution:
1950
                                evo.status = map_status(evo.status)
1951
                        formdata.store()
1928
                sql.formdef_remap_statuses(self, mapping)
1952 1929

  
1953 1930
        self.workflow = new_workflow
1954 1931
        if new_workflow.has_action('geolocate') and not self.geolocations:
wcs/forms/backoffice.py
46 46
    ):
47 47
        # noqa pylint: disable=too-many-arguments
48 48

  
49
        using_postgresql = get_publisher().is_using_postgresql()
50

  
51 49
        if not items:
52 50
            if offset and not limit:
53 51
                limit = int(get_publisher().get_site_option('default-page-size') or 20)
54 52
            if not criterias:
55 53
                criterias = []
56
            if using_postgresql:
57
                criterias.append(Null('anonymised'))
54
            criterias.append(Null('anonymised'))
58 55
            items, total_count = self.get_listing_items(
59 56
                fields,
60 57
                selected_filter,
......
101 98
        r += htmltext('</colgroup>')
102 99

  
103 100
        r += htmltext('<thead><tr>')
104
        if self.formdef.workflow.criticality_levels and using_postgresql:
101
        if self.formdef.workflow.criticality_levels:
105 102
            r += htmltext(
106 103
                '<th class="criticality-level-cell" data-field-sort-key="criticality_level"><span></span></th>'
107 104
            )
......
127 124
            else:
128 125
                field_sort_key = 'f%s' % f.contextual_id
129 126

  
130
            if field_sort_key and using_postgresql:
127
            if field_sort_key:
131 128
                r += htmltext('<th data-field-sort-key="%s">') % field_sort_key
132 129
            else:
133 130
                r += htmltext('<th>')
......
144 141
        r += htmltext('</tbody>')
145 142
        r += htmltext('</table>')
146 143

  
147
        if get_publisher().is_using_postgresql():
148
            # add links to paginate
149
            r += pagination_links(offset, limit, total_count)
144
        # add links to paginate
145
        r += pagination_links(offset, limit, total_count)
150 146

  
151 147
        return r.getvalue()
152 148

  
......
159 155
        user=None,
160 156
        criterias=None,
161 157
        anonymise=False,
162
    ):
163
        if get_publisher().is_using_postgresql():
164
            return self.get_listing_item_ids_sql(
165
                selected_filter, selected_filter_operator, query, order_by, user, criterias, anonymise
166
            )
167

  
168
        def get_all_except_drafts():
169
            item_ids = formdata_class.keys()
170
            drafts = formdata_class.get_ids_with_indexed_value('status', 'draft')
171
            return [x for x in item_ids if x not in drafts]
172

  
173
        formdata_class = self.formdef.data_class()
174
        # used for postgresql mode only
175
        if selected_filter == 'all':
176
            if selected_filter_operator == 'ne':
177
                # nothing
178
                item_ids = []
179
            else:
180
                # all except drafts
181
                item_ids = get_all_except_drafts()
182
        elif selected_filter == 'waiting':
183
            user_roles = [logged_users_role().id] + user.get_roles()
184
            waiting_item_ids = formdata_class.get_actionable_ids(user_roles)
185
            if selected_filter_operator == 'ne':
186
                # select all ids except drafts
187
                item_ids = get_all_except_drafts()
188
                # exclude waiting ids
189
                item_ids = [x for x in item_ids if x not in waiting_item_ids]
190
            else:
191
                # only waiting ids
192
                item_ids = waiting_item_ids
193
        else:
194
            # build selected status list
195
            applied_filters = []
196
            if selected_filter == 'pending':
197
                applied_filters = ['wf-%s' % x.id for x in self.formdef.workflow.get_not_endpoint_status()]
198
            elif selected_filter == 'done':
199
                applied_filters = ['wf-%s' % x.id for x in self.formdef.workflow.get_endpoint_status()]
200
            else:
201
                applied_filters = ['wf-%s' % selected_filter]
202

  
203
            filtered_item_ids = []
204
            for status_id in applied_filters:
205
                filtered_item_ids.extend(
206
                    formdata_class.get_ids_with_indexed_value(
207
                        'status',
208
                        status_id,
209
                    )
210
                )
211
            if selected_filter_operator == 'ne':
212
                # select all ids except drafts
213
                item_ids = get_all_except_drafts()
214
                # exclude selected status list
215
                item_ids = [x for x in item_ids if x not in filtered_item_ids]
216
            else:
217
                # only selected status list
218
                item_ids = filtered_item_ids
219

  
220
        if query:
221
            query_ids = formdata_class.get_ids_from_query(query)
222
            item_ids = list(set(item_ids).intersection(query_ids))
223

  
224
        if criterias:
225
            select_ids = formdata_class.keys(clause=criterias)
226
            item_ids = list(set(item_ids).intersection(select_ids))
227

  
228
        if item_ids and not anonymise:
229
            # as we are in the backoffice, we don't have to care about the
230
            # situation where the user is the submitter, and we limit ourselves
231
            # to consider treating roles.
232
            if not user.is_admin:
233
                user_roles = set(user.get_roles())
234
                concerned_ids = set()
235
                for role in user_roles:
236
                    concerned_ids |= set(
237
                        formdata_class.get_ids_with_indexed_value('concerned_roles', str(role))
238
                    )
239
                item_ids = list(set(item_ids).intersection(concerned_ids))
240

  
241
        return item_ids
242

  
243
    def get_listing_item_ids_sql(
244
        self,
245
        selected_filter,
246
        selected_filter_operator,
247
        query,
248
        order_by,
249
        user,
250
        criterias,
251
        anonymise,
252 158
    ):
253 159
        formdata_class = self.formdef.data_class()
254 160
        criterias = [] or criterias[:]
......
354 260
            criterias=criterias,
355 261
            anonymise=anonymise,
356 262
        )
357
        if not get_publisher().is_using_postgresql():
358
            item_ids.sort(key=int)
359
            item_ids.reverse()
360 263

  
361 264
        total_count = len(item_ids)
362 265

  
......
364 267
            offset = 0
365 268

  
366 269
        kwargs = {}
367
        if get_publisher().is_using_postgresql():
368
            kwargs['fields'] = fields
270
        kwargs['fields'] = fields
369 271

  
370 272
        if limit:
371 273
            items = formdata_class.get_ids(item_ids[offset : offset + limit], keep_order=True, **kwargs)
wcs/publisher.py
132 132

  
133 133
        DeprecationsScanAfterJob().execute()
134 134

  
135
    def is_using_postgresql(self):
136
        return True
137

  
138 135
    def has_postgresql_config(self):
139 136
        return bool(self.cfg.get('postgresql', {}))
140 137

  
......
467 464

  
468 465
    def cleanup(self):
469 466
        self._cached_user_fields_formdef = None
470
        if self.is_using_postgresql():
471
            from . import sql
467
        from . import sql
472 468

  
473
            sql.cleanup_connection()
469
        sql.cleanup_connection()
474 470

  
475 471
    @contextmanager
476 472
    def complex_data(self):
wcs/qommon/cron.py
84 84
        jobs = delayed_jobs
85 85
    else:
86 86
        # reindex user and formdata if needed (should only be run once)
87
        if publisher.is_using_postgresql():
88
            publisher.reindex_sql()
87
        publisher.reindex_sql()
89 88

  
90 89
        jobs = []
91 90

  
wcs/qommon/tokens.py
19 19
import string
20 20

  
21 21
from django.utils.timezone import make_aware, now
22
from quixote import get_publisher
23 22

  
24 23
from .storage import Equal, Less, StorableObject
25 24

  
......
75 74

  
76 75
    @classmethod
77 76
    def clean(cls):
78
        if get_publisher().is_using_postgresql():
79
            # noqa pylint: disable=unexpected-keyword-arg
80
            cls.wipe(clause=[Less('expiration', now())])
81
        else:
82
            for token_id in cls.keys():
83
                try:
84
                    cls.get(token_id)  # will run migrate, will check expiration
85
                except KeyError:
86
                    pass
87
                except AttributeError:
88
                    # old python2 tokens:
89
                    # AttributeError: module 'builtins' has no attribute 'unicode'
90
                    cls.remove_object(token_id)
77
        # noqa pylint: disable=unexpected-keyword-arg
78
        cls.wipe(clause=[Less('expiration', now())])
wcs/sql.py
1581 1581

  
1582 1582
@guard_postgres
1583 1583
def redo_views(conn, cur, formdef, rebuild_global_views=False):
1584
    if get_publisher().get_site_option('postgresql_views') == 'false':
1585
        return
1586

  
1587 1584
    if formdef.id is None:
1588 1585
        return
1589 1586

  
......
1961 1958
            sql_statement += ' WHERE ' + ' AND '.join(where_clauses)
1962 1959
        sql_statement += ' LIMIT 1'
1963 1960
        conn, cur = get_connection_and_cursor()
1964
        cur.execute(sql_statement, parameters)
1965
        check = cur.fetchone()
1966
        result = check is not None
1961
        try:
1962
            cur.execute(sql_statement, parameters)
1963
        except psycopg2.errors.UndefinedTable:
1964
            result = False
1965
        else:
1966
            check = cur.fetchone()
1967
            result = check is not None
1967 1968
        conn.commit()
1968 1969
        cur.close()
1969 1970
        return result
wcs/statistics/views.py
19 19
from django.http import HttpResponseBadRequest, HttpResponseForbidden, JsonResponse
20 20
from django.urls import reverse
21 21
from django.views.generic import View
22
from quixote import get_publisher
23 22

  
24 23
from wcs import sql
25 24
from wcs.api_utils import is_url_signed
......
42 41

  
43 42
class IndexView(RestrictedView):
44 43
    def get(self, request, *args, **kwargs):
45
        if not get_publisher().is_using_postgresql():
46
            return JsonResponse({'data': [], 'err': 0})
47

  
48 44
        categories = Category.select()
49 45
        categories.sort(key=lambda x: misc.simplify(x.name))
50 46
        category_options = [{'id': '_all', 'label': C_('categories|All')}] + [
......
306 302
                for status in waitpoint_status:
307 303
                    options.append((status.id, status.name))
308 304
            elif field.type in ('item', 'items'):
309
                if not get_publisher().is_using_postgresql():
310
                    continue
311 305
                options = form_page.get_item_filter_options(field, selected_filter='all', anonymised=True)
312 306
                if not options:
313 307
                    continue
wcs/users.py
188 188

  
189 189
    @classmethod
190 190
    def get_users_with_roles(cls, included_roles=None, excluded_roles=None, order_by=None):
191
        if not get_publisher().is_using_postgresql():
192
            return []
193

  
194 191
        from wcs import sql
195 192

  
196 193
        criterias = [sql.Null('deleted_timestamp')]
wcs/variables.py
69 69
        )
70 70

  
71 71
    def order_by(self, attribute):
72
        if get_publisher().is_using_postgresql():
73
            field = self.get_field(attribute)
74
        else:
75
            field = None  # no support for field search
72
        field = self.get_field(attribute)
76 73
        return self._clone(self._criterias, order_by=field or attribute)
77 74

  
78 75
    def limit(self, limit):
wcs/wf/jump.py
340 340
        ) if job else contextlib.ExitStack():
341 341
            formdata_class = formdef.data_class()
342 342
            for status_id in status_ids:
343
                if publisher.is_using_postgresql():
344
                    # get minimum delay for jumps in this status
345
                    delay = math.inf
346
                    for jump_action in wfs_status[str(formdef.workflow_id)][status_id]:
347
                        if Template.is_template_string(jump_action.timeout):
348
                            delay = 0
349
                            break
350
                        delay = min(delay, int(jump_action.timeout))
351
                    # limit delay to minimal delay
352
                    if delay < JUMP_TIMEOUT_INTERVAL * 60:
353
                        delay = JUMP_TIMEOUT_INTERVAL * 60
354

  
355
                    criterias = [
356
                        Equal('status', status_id),
357
                        LessOrEqual(
358
                            'last_update_time',
359
                            (datetime.datetime.now() - datetime.timedelta(seconds=delay)).timetuple(),
360
                        ),
361
                    ]
362
                    formdatas = formdata_class.select_iterator(criterias, ignore_errors=True, itersize=200)
363
                else:
364
                    formdatas = formdata_class.get_with_indexed_value('status', status_id, ignore_errors=True)
343
                # get minimum delay for jumps in this status
344
                delay = math.inf
345
                for jump_action in wfs_status[str(formdef.workflow_id)][status_id]:
346
                    if Template.is_template_string(jump_action.timeout):
347
                        delay = 0
348
                        break
349
                    delay = min(delay, int(jump_action.timeout))
350
                # limit delay to minimal delay
351
                if delay < JUMP_TIMEOUT_INTERVAL * 60:
352
                    delay = JUMP_TIMEOUT_INTERVAL * 60
353

  
354
                criterias = [
355
                    Equal('status', status_id),
356
                    LessOrEqual(
357
                        'last_update_time',
358
                        (datetime.datetime.now() - datetime.timedelta(seconds=delay)).timetuple(),
359
                    ),
360
                ]
361
                formdatas = formdata_class.select_iterator(criterias, ignore_errors=True, itersize=200)
365 362

  
366 363
                for formdata in formdatas:
367 364
                    for jump_action in wfs_status[str(formdef.workflow_id)][formdata.status]:
368
-