Projet

Général

Profil

0003-tests-split-wcs-tests-68063.patch

Lauréline Guérin, 12 août 2022 09:43

Télécharger (189 ko)

Voir les différences:

Subject: [PATCH 3/8] tests: split wcs tests (#68063)

 tests/wcs/conftest.py  |   14 +
 tests/wcs/test_all.py  | 2492 +---------------------------------------
 tests/wcs/test_card.py | 2091 +++++++++++++++++++++++++++++++++
 tests/wcs/utils.py     |  413 +++++++
 4 files changed, 2520 insertions(+), 2490 deletions(-)
 create mode 100644 tests/wcs/conftest.py
 create mode 100644 tests/wcs/test_card.py
 create mode 100644 tests/wcs/utils.py
tests/wcs/conftest.py
1
from importlib import import_module
2

  
3
import pytest
4
from django.conf import settings
5
from django.test.client import RequestFactory
6

  
7

  
8
@pytest.fixture
9
def context():
10
    ctx = {'request': RequestFactory().get('/')}
11
    ctx['request'].user = None
12
    session_engine = import_module(settings.SESSION_ENGINE)
13
    ctx['request'].session = session_engine.SessionStore()
14
    return ctx
tests/wcs/test_all.py
1
import copy
2 1
import json
3 2
import re
4
import urllib.parse
5
from importlib import import_module
6 3
from unittest import mock
7 4

  
8 5
import pytest
......
21 18
from combo.apps.search.engines import engines
22 19
from combo.apps.search.models import SearchCell
23 20
from combo.apps.search.utils import index_site, search_site
24
from combo.apps.wcs.forms import WcsCardInfoCellDisplayForm
25 21
from combo.apps.wcs.models import (
26 22
    BackofficeSubmissionCell,
27 23
    CategoriesCell,
......
41 37
from tests.test_manager import login
42 38
from tests.utils import manager_submit_cell
43 39

  
44
pytestmark = pytest.mark.django_db
45

  
46

  
47
WCS_FORMDEFS_DATA = [
48
    {'slug': 'a-private-form', 'title': 'a private form', 'url': '/a-private-form/'},
49
    {'slug': 'a-second-form-title', 'title': 'a second form title', 'url': '/a-second-form-title/'},
50
    {'slug': 'form-title', 'title': 'form title', 'url': '/form-title/', 'keywords': ['foo', 'bar']},
51
    {'slug': 'third-form-title', 'title': 'Third form title', 'url': '/third-form-title/'},
52
]
53

  
54
WCS_CATEGORIES_DATA = [
55
    {'slug': 'test-%s' % i, 'title': 'Test %s' % i, 'url': '/test-%s/' % i} for i in [3, 9]
56
]
57

  
58
WCS_CATEGORIES_FORMDEFS_DATA = [
59
    {
60
        'slug': 'form-title',
61
        'title': 'form title',
62
        'url': '/form-title/',
63
        'keywords': ['foo', 'bar'],
64
        'count': 42,
65
    },
66
    {
67
        'slug': 'a-second-form-title',
68
        'title': 'a second form title',
69
        'url': '/a-second-form-title/',
70
        'count': 35,
71
    },
72
]
73

  
74
WCS_USER_FORMS_DATA = [
75
    {
76
        'name': 'name',
77
        'title': 'Title',
78
        'url': '/form/1/',
79
        'form_receipt_datetime': '2015-01-01T00:00:00',
80
        'readable': True,
81
        'category_slug': 'test-9',
82
    },
83
    {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True},
84
    {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
85
]
86

  
87
WCS_FORMS_DATA = [
88
    {
89
        'form_receipt_datetime': '2019-10-17T16:46:03',
90
        'form_url': '/foobar/1',
91
        'form_url_backoffice': '/backoffice/management/foobar/1/',
92
    },
93
    {
94
        'form_receipt_datetime': '2019-10-17T16:46:04',
95
        'form_url': '/foobar/2',
96
        'form_url_backoffice': '/backoffice/management/foobar/2/',
97
    },
98
]
99

  
100
WCS_USER_DRAFTS_DATA = [
101
    {
102
        'name': 'name',
103
        'title': 'Title',
104
        'url': '/form/1/',
105
        'form_receipt_datetime': '2015-01-01T00:00:00',
106
        'category_slug': 'test-9',
107
    },
108
    {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
109
    {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
110
    {
111
        'name': 'name',
112
        'title': 'Title',
113
        'url': '/form/4/',
114
        'form_receipt_datetime': '2015-01-01T00:00:00',
115
        'form_status_is_endpoint': True,
116
        'category_slug': 'test-9',
117
    },
118
]
119

  
120
WCS_CARDDEFS_DATA = [
121
    {'title': 'Card Model 1', 'slug': 'card_model_1', 'custom_views': [{'id': 'foo', 'text': 'bar'}]},
122
    {'title': 'Card Model 2', 'slug': 'card_model_2'},
123
    {'title': 'Card Model 3', 'slug': 'card_model_3'},
124
    {'title': 'Card A', 'slug': 'card_a'},
125
    {'title': 'Card B', 'slug': 'card_b', 'custom_views': [{'id': 'a-custom-view', 'text': 'foo bar'}]},
126
    {'title': 'Card C', 'slug': 'card_c'},
127
    {'title': 'Card D', 'slug': 'card_d'},
128
    {'title': 'Card E', 'slug': 'card_e'},
129
]
130

  
131
WCS_CARDS_DATA = {
132
    'card_model_1': [
133
        {
134
            'id': 11,
135
            'display_id': '10-11',
136
            'display_name': 'Card Model 1 - n°10-11',
137
            'digest': 'a a a',
138
            'text': 'aa',
139
            'url': '/backoffice/data/card_model_1/11/',
140
            'fields': {
141
                'fielda': '<i>a</i>',
142
                'fieldb': True,
143
                'fieldc': '2020-09-28',
144
                'fieldd': {'filename': 'file.pdf', 'url': 'http://127.0.0.1:8999/download?f=42'},
145
                'fielde': "lorem<strong>ipsum\n\nhello'world",
146
                'fieldf': 'lorem<strong>ipsum\n\nhello world',
147
                'fieldg': 'test@localhost',
148
                'fieldh': 'https://www.example.net/',
149
                'related': 'Foo Bar',
150
                'related_raw': 42,
151
                'related_structured': {'id': 42, 'text': 'blah'},
152
            },
153
        },
154
        {
155
            'id': 12,
156
            'display_id': '10-12',
157
            'display_name': 'Card Model 1 - n°10-12',
158
            'digest': 'b b b',
159
            'text': 'bb',
160
            'url': '/backoffice/data/card_model_1/12/',
161
        },
162
        {
163
            'id': 13,
164
            'display_id': '10-13',
165
            'display_name': 'Card Model 1 - n°10-13',
166
            'digest': 'c c c',
167
            'text': 'cc',
168
            'url': '/backoffice/data/card_model_1/13/',
169
        },
170
    ],
171
    'card_a': [
172
        {
173
            'id': 1,
174
            'fields': {
175
                'cardb_raw': 1,
176
                'cardsb_raw': [2, 3],
177
                'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
178
                'cardc_raw': 6,
179
                'cardz_raw': 42,
180
            },
181
        },
182
        {
183
            'id': 2,
184
            'fields': {
185
                'cardb_raw': 1,
186
                'cardsb_raw': [2, 3],
187
                'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
188
                'cardc_raw': 61,  # unknown card_c
189
            },
190
        },
191
        {
192
            'id': 3,
193
            'fields': {
194
                # some missing fields
195
                'blockb_raw': [{}],
196
            },
197
        },
198
        {
199
            'id': 4,
200
            'fields': {
201
                # some empty fields
202
                'cardb_raw': None,
203
                'cardsb_raw': None,
204
                'blockb_raw': [{'cardb_raw': None}],
205
                'cardc_raw': 7,
206
            },
207
        },
208
    ],
209
    'card_b': [{'id': i, 'fields': []} for i in range(1, 12) if i != 6],
210
    'card_c': [
211
        {
212
            'id': 6,
213
            'fields': {
214
                'cardb_raw': 7,
215
                'cardsb_raw': [8, 9],
216
                'blockb_raw': [{'cardb_raw': 10}, {'cardb_raw': 11}],
217
            },
218
        },
219
        {
220
            'id': 7,
221
            'fields': {},
222
        },
223
    ],
224
    'card_f': [
225
        {'id': 41, 'fields': {'cardh_raw': 42}},
226
    ],
227
    'card_g': [
228
        {'id': 43, 'fields': {'cardh_raw': 44}},
229
    ],
230
    'card_h': [
231
        {'id': 42, 'fields': {}},
232
        {'id': 44, 'fields': {}},
233
    ],
234
}
235

  
236
WCS_CARDS_CUSTOM_VIEW_DATA = [
237
    {
238
        'id': 11,
239
        'display_id': '10-11',
240
        'display_name': 'Card Model 1 - n°10-11',
241
        'digest': 'a a a',
242
        'text': 'aa',
243
        'url': '/backoffice/data/card_model_1/11/',
244
    },
245
    {
246
        'id': 12,
247
        'display_id': '10-12',
248
        'display_name': 'Card Model 1 - n°10-12',
249
        'digest': 'b b b',
250
        'text': 'bb',
251
        'url': '/backoffice/data/card_model_1/12/',
252
    },
253
]
254

  
255
WCS_CARDDEF_SCHEMAS = {
256
    'card_model_1': {
257
        'name': 'Card Model 1',
258
        'fields': [
259
            {'label': 'Field A', 'varname': 'fielda', 'type': 'string'},
260
            {'label': 'Field B', 'varname': 'fieldb', 'type': 'bool'},
261
            {'label': 'Field C', 'varname': 'fieldc', 'type': 'date'},
262
            {'label': 'Field D', 'varname': 'fieldd', 'type': 'file'},
263
            {'label': 'Field E', 'varname': 'fielde', 'type': 'text'},
264
            {'label': 'Field F', 'varname': 'fieldf', 'type': 'text', 'pre': True},
265
            {'label': 'Field G', 'varname': 'fieldg', 'type': 'email'},
266
            {'label': 'Field H', 'varname': 'fieldh', 'type': 'string'},
267
            {'label': 'Empty', 'varname': 'empty', 'type': 'string'},
268
            {'label': 'Related', 'varname': 'related', 'type': 'item'},
269
            {'label': 'Page', 'type': 'page'},
270
            {'label': 'Comment', 'type': 'comment'},
271
            {'label': 'Title', 'type': 'title'},
272
            {'label': 'Subtitle', 'type': 'subtitle'},
273
            {'label': 'Empty', 'varname': None, 'type': 'string'},
274
        ],
275
    },
276
    'card_a': {
277
        'name': 'Card A',
278
        'fields': [
279
            {'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
280
            {'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
281
            {'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
282
            {'label': 'Card C', 'varname': 'cardc', 'type': 'item'},
283
        ],
284
        'relations': [
285
            {'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
286
            {'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
287
            {'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
288
            {'obj': 'carddef:card_c', 'varname': 'cardc', 'type': 'item', 'reverse': False},
289
            {
290
                'obj': 'carddef:card_z',  # unknown card model
291
                'varname': 'cardz',
292
                'type': 'item',
293
                'reverse': False,
294
            },
295
        ],
296
    },
297
    'card_b': {
298
        'name': 'Card B',
299
        'fields': [],
300
        'relations': [
301
            {'obj': 'carddef:card_a', 'varname': 'cardb', 'type': 'item', 'reverse': True},
302
            {'obj': 'carddef:card_a', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
303
            {'obj': 'carddef:card_a', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
304
            {'obj': 'carddef:card_c', 'varname': 'cardb', 'type': 'item', 'reverse': True},
305
            {'obj': 'carddef:card_c', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
306
            {'obj': 'carddef:card_c', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
307
        ],
308
    },
309
    'card_c': {
310
        'name': 'Card C',
311
        'fields': [
312
            {'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
313
            {'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
314
            {'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
315
        ],
316
        'relations': [
317
            {'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
318
            {'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
319
            {'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
320
            {'obj': 'carddef:card_a', 'varname': 'cardc', 'type': 'item', 'reverse': True},
321
        ],
322
    },
323
    'card_d': {
324
        'name': 'Card D',
325
        'fields': [
326
            {'label': 'Card D', 'varname': 'cardd-foo', 'type': 'item'},
327
            {'label': 'Card E', 'varname': 'carde-foo', 'type': 'item'},
328
        ],
329
        'relations': [
330
            {'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': False},
331
            {'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': True},
332
            {'obj': 'carddef:card_e', 'varname': 'carde-foo', 'type': 'item', 'reverse': False},
333
        ],
334
    },
335
    'card_e': {
336
        'name': 'Card E',
337
        'fields': [
338
            {'label': 'Card D', 'varname': 'cardd-bar', 'type': 'item'},
339
        ],
340
        'relations': [
341
            {'obj': 'carddef:card_d', 'varname': 'cardd-bar', 'type': 'item', 'reverse': False},
342
            {'obj': 'carddef:card_d', 'varname': 'carde-foo', 'type': 'item', 'reverse': True},
343
        ],
344
    },
345
    'card_f': {
346
        'name': 'Card F',
347
        'fields': [
348
            {'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
349
        ],
350
        'relations': [
351
            {'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
352
        ],
353
    },
354
    'card_g': {
355
        'name': 'Card G',
356
        'fields': [
357
            {'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
358
        ],
359
        'relations': [
360
            {'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
361
        ],
362
    },
363
    'card_h': {
364
        'name': 'Card H',
365
        'fields': [],
366
        'relations': [
367
            {'obj': 'carddef:card_f', 'varname': 'cardh', 'type': 'item', 'reverse': True},
368
            {'obj': 'carddef:card_g', 'varname': 'cardh', 'type': 'item', 'reverse': True},
369
        ],
370
    },
371
}
372

  
373

  
374
class MockUser:
375
    email = 'foo@example.net'
376
    is_authenticated = True
377
    is_anonymous = False
378

  
379
    def get_name_id(self):
380
        return None
381

  
382

  
383
class MockUserWithNameId:
384
    email = 'foo@example.net'
385
    is_authenticated = True
386
    is_anonymous = False
387

  
388
    def get_name_id(self):
389
        return 'xyz'
390

  
391

  
392
class MockedRequestResponse(mock.Mock):
393
    status_code = 200
394

  
395
    def json(self):
396
        return json.loads(self.content)
397

  
398

  
399
def get_data_from_url(url):
400
    if '/api/formdefs/' in url:
401
        return WCS_FORMDEFS_DATA
402
    if '/api/categories/' in url:
403
        if '/formdefs/' in url:
404
            return WCS_CATEGORIES_FORMDEFS_DATA
405
        return WCS_CATEGORIES_DATA
406
    if '/api/user/forms' in url:
407
        return WCS_USER_FORMS_DATA
408
    if '/api/forms' in url:
409
        return WCS_FORMS_DATA
410
    if '/api/user/drafts' in url:
411
        return WCS_USER_DRAFTS_DATA
412
    if '/api/cards/@list' in url:
413
        return WCS_CARDDEFS_DATA
414
    m_schema = re.match(r'/api/cards/([a-z0-9_]+)/@schema', url)
415
    if m_schema:
416
        return WCS_CARDDEF_SCHEMAS.get(m_schema.group(1)) or {}
417
    m_card = re.match(r'/api/cards/([a-z0-9_]+)/(\d+)/', url)
418
    if m_card:
419
        try:
420
            return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(2))][0]
421
        except IndexError:
422
            return {}
423
    m_card = re.match(r'/api/cards/([a-z0-9_]+)/([a-z0-9_]+)/(\d+)/', url)  # model/custom-view/id
424
    if m_card:
425
        try:
426
            return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(3))][0]
427
        except IndexError:
428
            return {}
429
    if 'api/cards/card_model_1/list/foo' in url:
430
        return WCS_CARDS_CUSTOM_VIEW_DATA
431
    m_list = re.match(r'/api/cards/([a-z0-9_]+)/list', url)
432
    if m_list:
433
        return WCS_CARDS_DATA.get(m_list.group(1)) or []
434
    return []
435

  
436

  
437
def mocked_requests_send(request, **kwargs):
438
    request_url = urllib.parse.urlparse(request.url)
439
    data = copy.deepcopy(get_data_from_url(request_url.path))
440

  
441
    if not isinstance(data, list):
442
        return MockedRequestResponse(content=json.dumps(data))
443

  
444
    for elem in data:
445
        for key in ['url', 'form_url', 'form_url_backoffice']:
446
            if key not in elem:
447
                continue
448
            elem_url = elem[key]
449
            elem[key] = '{scheme}://{netloc}{url}'.format(
450
                scheme=request_url.scheme, netloc=request_url.netloc, url=elem_url
451
            )
40
from .utils import MockedRequestResponse, MockUser, MockUserWithNameId, mocked_requests_send
452 41

  
453
    return MockedRequestResponse(content=json.dumps({'data': data}))
454

  
455

  
456
@pytest.fixture
457
def context():
458
    ctx = {'request': RequestFactory().get('/')}
459
    ctx['request'].user = None
460
    session_engine = import_module(settings.SESSION_ENGINE)
461
    ctx['request'].session = session_engine.SessionStore()
462
    return ctx
42
pytestmark = pytest.mark.django_db
463 43

  
464 44

  
465 45
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
......
1985 1565
    assert 'email' not in mock_send.call_args_list[0][0][0].url
1986 1566

  
1987 1567

  
1988
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1989
def test_card_cell_setup(mock_send, app, admin_user):
1990
    page = Page.objects.create(
1991
        title='xxx', slug='test_card_cell_save_cache', template_name='standard', sub_slug='foobar'
1992
    )
1993
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
1994
    form_class = cell.get_default_form_class()
1995
    form = form_class(instance=cell)
1996
    assert form.fields['carddef_reference'].widget.choices == [
1997
        ('default:card_model_1', 'test : Card Model 1'),
1998
        ('default:card_model_1:foo', 'test : Card Model 1 - bar'),
1999
        ('default:card_model_2', 'test : Card Model 2'),
2000
        ('default:card_model_3', 'test : Card Model 3'),
2001
        ('default:card_a', 'test : Card A'),
2002
        ('default:card_b', 'test : Card B'),
2003
        ('default:card_b:a-custom-view', 'test : Card B - foo bar'),
2004
        ('default:card_c', 'test : Card C'),
2005
        ('default:card_d', 'test : Card D'),
2006
        ('default:card_e', 'test : Card E'),
2007
        ('other:card_model_1', 'test2 : Card Model 1'),
2008
        ('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
2009
        ('other:card_model_2', 'test2 : Card Model 2'),
2010
        ('other:card_model_3', 'test2 : Card Model 3'),
2011
        ('other:card_a', 'test2 : Card A'),
2012
        ('other:card_b', 'test2 : Card B'),
2013
        ('other:card_b:a-custom-view', 'test2 : Card B - foo bar'),
2014
        ('other:card_c', 'test2 : Card C'),
2015
        ('other:card_d', 'test2 : Card D'),
2016
        ('other:card_e', 'test2 : Card E'),
2017
    ]
2018

  
2019
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
2020
    assert 'customize_display' not in form_display.fields
2021
    assert 'custom_schema' not in form_display.fields
2022

  
2023
    cell.save()
2024
    assert 'customize_display' not in form_display.fields
2025
    assert 'custom_schema' not in form_display.fields
2026

  
2027
    cell.carddef_reference = 'default:card_model_1'
2028
    cell.save()
2029
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
2030
    assert 'customize_display' in form_display.fields
2031
    assert 'custom_schema' in form_display.fields
2032
    assert 'customize_display' not in form_display.initial
2033
    assert form_display.initial['custom_schema'] == {}
2034

  
2035
    cell.carddef_reference = 'default:card_model_1:foo'
2036
    cell.save()
2037
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
2038
    assert 'customize_display' in form_display.fields
2039
    assert 'custom_schema' in form_display.fields
2040
    assert 'customize_display' not in form_display.initial
2041
    assert form_display.initial['custom_schema'] == {}
2042

  
2043
    cell.carddef_reference = 'default:card_model_1'
2044
    cell.save()
2045

  
2046
    cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
2047
    cell.save()
2048
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
2049
    assert 'customize_display' in form_display.fields
2050
    assert 'custom_schema' in form_display.fields
2051
    assert form_display.initial['customize_display'] is True
2052
    assert form_display.initial['custom_schema'] == {
2053
        'cells': [
2054
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
2055
        ]
2056
    }
2057

  
2058
    WcsCardInfosCell.objects.all().delete()
2059

  
2060
    # check adding a cell from the UI
2061
    app = login(app)
2062
    resp = app.get('/manage/pages/%s/' % page.pk)
2063
    cell_add_url = [x for x in resp.html.find_all('option') if x.text == 'Card Information Cell'][0].get(
2064
        'data-add-url'
2065
    )
2066
    resp = app.get(cell_add_url).follow()
2067
    cell = WcsCardInfosCell.objects.all().first()
2068
    manager_submit_cell(resp.forms[0])  # will save card model
2069
    cell.refresh_from_db()
2070

  
2071
    # check getting back to uncustomized display reset the schema
2072
    cell.custom_schema = {
2073
        'cells': [
2074
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
2075
        ]
2076
    }
2077
    cell.save()
2078

  
2079
    resp = app.get('/manage/pages/%s/' % page.pk)
2080
    assert resp.forms[0]['c%s-customize_display' % cell.get_reference()].value == 'on'
2081
    resp.forms[0]['c%s-customize_display' % cell.get_reference()].value = False
2082
    manager_submit_cell(resp.forms[0])
2083
    cell.refresh_from_db()
2084
    assert cell.custom_schema == {}
2085

  
2086
    cell.custom_schema = {
2087
        'cells': [
2088
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
2089
        ]
2090
    }
2091
    cell.save()
2092
    resp = app.get('/manage/pages/%s/' % page.pk)
2093
    assert resp.forms[0]['c%s-display_mode' % cell.get_reference()].value == 'card'
2094
    resp.forms[0]['c%s-display_mode' % cell.get_reference()].value = 'table'
2095
    manager_submit_cell(resp.forms[0])
2096
    cell.refresh_from_db()
2097
    assert cell.custom_schema == {}
2098

  
2099
    assert cell.related_card_path == ''
2100
    assert cell.card_ids == ''
2101
    resp = app.get('/manage/pages/%s/' % page.pk)
2102
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
2103
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
2104
    manager_submit_cell(resp.forms[0])
2105
    cell.refresh_from_db()
2106
    assert cell.related_card_path == ''
2107
    assert cell.card_ids == ''
2108
    resp = app.get('/manage/pages/%s/' % page.pk)
2109
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
2110
    resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value = ''
2111
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
2112
    manager_submit_cell(resp.forms[0])
2113
    cell.refresh_from_db()
2114
    assert cell.related_card_path == ''
2115
    assert cell.card_ids == '42'
2116

  
2117
    # current page has a sub_slug, '--' option is present
2118
    resp = app.get('/manage/pages/%s/' % page.pk)
2119
    assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
2120

  
2121
    # current_page has no sub_slug, but parent page has one
2122
    parent_page = Page.objects.create(
2123
        title='parent', slug='parent', template_name='standard', sub_slug='foobar'
2124
    )
2125
    page.parent = parent_page
2126
    page.sub_slug = ''
2127
    page.save()
2128
    resp = app.get('/manage/pages/%s/' % page.pk)
2129
    assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
2130

  
2131
    # no sub_slug
2132
    parent_page.sub_slug = ''
2133
    parent_page.save()
2134
    resp = app.get('/manage/pages/%s/' % page.pk)
2135
    assert '--' not in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
2136
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == ''
2137
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = ''
2138
    resp = resp.forms[0].submit()
2139
    assert resp.context['form'].errors == {'card_ids': ['This field is required.']}
2140

  
2141

  
2142
def test_card_cell_custom_schema_migration():
2143
    cell = WcsCardInfosCell()
2144

  
2145
    cell.custom_schema = {
2146
        'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
2147
    }
2148
    assert cell.get_custom_schema() == {
2149
        'cells': [
2150
            {
2151
                'varname': 'some-field',
2152
                'field_content': 'label',
2153
                'display_mode': 'text',
2154
                'empty_value': '@empty@',
2155
                'cell_size': 'foobar',
2156
            }
2157
        ]
2158
    }
2159
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'value'}]}
2160
    assert cell.get_custom_schema() == {
2161
        'cells': [
2162
            {
2163
                'varname': 'some-field',
2164
                'field_content': 'value',
2165
                'display_mode': 'text',
2166
                'empty_value': '@empty@',
2167
            }
2168
        ]
2169
    }
2170
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'label-and-value'}]}
2171
    assert cell.get_custom_schema() == {
2172
        'cells': [
2173
            {
2174
                'varname': 'some-field',
2175
                'field_content': 'label-and-value',
2176
                'display_mode': 'text',
2177
                'empty_value': '@empty@',
2178
            }
2179
        ]
2180
    }
2181
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'title'}]}
2182
    assert cell.get_custom_schema() == {
2183
        'cells': [
2184
            {
2185
                'varname': 'some-field',
2186
                'field_content': 'value',
2187
                'display_mode': 'title',
2188
                'empty_value': '@empty@',
2189
            }
2190
        ]
2191
    }
2192

  
2193
    cell.custom_schema = {
2194
        'cells': [
2195
            {'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
2196
        ]
2197
    }
2198
    assert cell.get_custom_schema() == {
2199
        'cells': [
2200
            {'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
2201
        ]
2202
    }
2203
    cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'value'}]}
2204
    assert cell.get_custom_schema() == {
2205
        'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'text'}]
2206
    }
2207
    cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]}
2208
    assert cell.get_custom_schema() == {
2209
        'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]
2210
    }
2211

  
2212

  
2213
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2214
def test_card_cell_save_cache(mock_send):
2215
    page = Page.objects.create(title='xxx', slug='test_card_cell_save_cache', template_name='standard')
2216
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2217
    assert cell.get_additional_label() is None
2218
    cell.carddef_reference = 'default:card_model_1'
2219
    cell.save()
2220
    assert cell.cached_title == 'Card Model 1'
2221
    assert cell.cached_json != {}
2222
    assert cell.get_additional_label() == 'Card Model 1'
2223
    # make sure cached attributes are removed from serialized pages
2224
    assert 'cached_' not in json.dumps(page.get_serialized_page())
2225

  
2226
    # artificially change title and json
2227
    WcsCardInfosCell.objects.filter(pk=cell.pk).update(cached_title='XXX', cached_json={})
2228
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'XXX'
2229
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json == {}
2230
    # run update db cache
2231
    appconfig = apps.get_app_config('wcs')
2232
    appconfig.update_db_cache()
2233
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1'
2234
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json != {}
2235

  
2236

  
2237
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2238
def test_card_cell_validity(mock_send):
2239
    page = Page.objects.create(title='xxx', template_name='standard')
2240
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
2241
    validity_info = ValidityInfo.objects.latest('pk')
2242
    assert validity_info.invalid_reason_code == 'wcs_card_not_defined'
2243
    assert validity_info.invalid_since is not None
2244

  
2245
    cell.carddef_reference = 'default:card_model_1'
2246
    cell.save()
2247
    assert ValidityInfo.objects.exists() is False
2248

  
2249
    # can not retrieve data, don't set cell as invalid
2250
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2251
        mock_resp = Response()
2252
        mock_resp.status_code = 500
2253
        requests_get.return_value = mock_resp
2254
        cell.save()
2255
    assert ValidityInfo.objects.exists() is False
2256
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2257
        requests_get.side_effect = ConnectionError()
2258
        cell.save()
2259
    assert ValidityInfo.objects.exists() is False
2260

  
2261
    # can not retrieve carddefs, don't set cell as invalid
2262
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2263
        mock_resp = Response()
2264
        mock_resp.status_code = 404
2265
        requests_get.return_value = mock_resp
2266
        cell.save()
2267
    assert ValidityInfo.objects.exists() is False
2268

  
2269
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2270
        mock_resp = Response()
2271
        mock_resp.json = lambda *a, **k: {'err': 1, 'err_class': 'Page not found'}
2272
        mock_resp.status_code = 404
2273
        requests_get.return_value = mock_resp
2274
        cell.carddef_reference = 'default:foobar'
2275
        cell.save()
2276
    validity_info = ValidityInfo.objects.latest('pk')
2277
    assert validity_info.invalid_reason_code == 'wcs_card_not_found'
2278
    assert validity_info.invalid_since is not None
2279

  
2280

  
2281
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2282
def test_card_cell_check_validity(mock_send):
2283
    page = Page.objects.create(title='xxx', template_name='standard')
2284
    cell = WcsCardInfosCell.objects.create(
2285
        page=page,
2286
        placeholder='content',
2287
        order=0,
2288
        carddef_reference='default:card_a',
2289
        card_ids='1',
2290
    )
2291
    cell2 = WcsCardInfosCell.objects.create(
2292
        page=page, placeholder='content', order=1, carddef_reference='default:card_b'
2293
    )
2294

  
2295
    # no related_card_path
2296
    cell2.check_validity()
2297
    assert ValidityInfo.objects.exists() is False
2298

  
2299
    # correct related_card_path but sluga is not defined
2300
    cell2.related_card_path = 'sluga/cardb'
2301
    cell2.save()
2302
    cell2.check_validity()
2303
    validity_info = ValidityInfo.objects.latest('pk')
2304
    assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
2305
    assert validity_info.invalid_since is not None
2306

  
2307
    # sluga is now defined
2308
    cell.slug = 'sluga'
2309
    cell.save()
2310
    cell2.check_validity()
2311
    assert ValidityInfo.objects.exists() is False
2312

  
2313
    # bad related_card_path
2314
    cell2.related_card_path = 'sluga/foobar'
2315
    cell2.save()
2316
    cell2.check_validity()
2317
    validity_info = ValidityInfo.objects.latest('pk')
2318
    assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
2319
    assert validity_info.invalid_since is not None
2320

  
2321

  
2322
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2323
def test_manager_card_cell(mock_send, app, admin_user):
2324
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
2325
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
2326

  
2327
    app = login(app)
2328
    resp = app.get('/manage/pages/%s/' % page.pk)
2329
    assert 'application/json' not in resp
2330

  
2331
    cell.carddef_reference = 'default:card_model_1'
2332
    cell.save()
2333
    resp = app.get('/manage/pages/%s/' % page.pk)
2334
    assert '<script id="cell-%s-card-schema-default:card_model_1" type="application/json">' % cell.pk in resp
2335

  
2336
    assert ('data-cell-reference="%s"' % cell.get_reference()) in resp.text
2337
    assert cell.without_user is False
2338
    assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value == 'on'
2339
    resp.forms[0]['c%s-with_user' % cell.get_reference()].value = False
2340
    manager_submit_cell(resp.forms[0])
2341
    cell.refresh_from_db()
2342
    assert cell.without_user is True
2343
    assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value is None
2344

  
2345
    # card with relations
2346
    cell.carddef_reference = 'default:card_a'
2347
    cell.save()
2348
    resp = app.get('/manage/pages/%s/' % page.pk)
2349
    # but only one cell on the page, no relations to follow
2350
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2351
        ('--', True, 'Identifier from page URL'),
2352
        ('__all__', False, 'All cards'),
2353
        ('', False, 'Other Card Identifiers'),
2354
    ]
2355

  
2356
    # all cards
2357
    cell.related_card_path = '__all__'
2358
    cell.save()
2359
    resp = app.get('/manage/pages/%s/' % page.pk)
2360
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2361
        ('--', False, 'Identifier from page URL'),
2362
        ('__all__', True, 'All cards'),
2363
        ('', False, 'Other Card Identifiers'),
2364
    ]
2365

  
2366
    # add a second cell, related to the first card model
2367
    cell.related_card_path = ''
2368
    cell.save()
2369
    cell2 = WcsCardInfosCell.objects.create(
2370
        page=page, placeholder='content', order=1, carddef_reference='default:card_b'
2371
    )
2372
    resp = app.get('/manage/pages/%s/' % page.pk)
2373
    # still no relation to follow
2374
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2375
        ('--', True, 'Identifier from page URL'),
2376
        ('__all__', False, 'All cards'),
2377
        ('', False, 'Other Card Identifiers'),
2378
    ]
2379
    # no cell with id and slug
2380
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2381
        ('--', True, 'Identifier from page URL'),
2382
        ('__all__', False, 'All cards'),
2383
        ('', False, 'Other Card Identifiers'),
2384
    ]
2385

  
2386
    # set a slug on first cell
2387
    cell.slug = 'sluga'
2388
    cell.save()
2389
    resp = app.get('/manage/pages/%s/' % page.pk)
2390
    # still no relation to follow
2391
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2392
        ('--', True, 'Identifier from page URL'),
2393
        ('__all__', False, 'All cards'),
2394
        ('', False, 'Other Card Identifiers'),
2395
    ]
2396
    # multiple relations to follow
2397
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2398
        ('--', True, 'Identifier from page URL'),
2399
        ('__all__', False, 'All cards'),
2400
        ('', False, 'Other Card Identifiers'),
2401
        ('sluga/cardb', False, 'sluga/cardb'),
2402
        ('sluga/cardsb', False, 'sluga/cardsb'),
2403
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
2404
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
2405
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
2406
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
2407
    ]
2408

  
2409
    # set a list of ids on first cell
2410
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
2411
    cell.save()
2412
    resp = app.get('/manage/pages/%s/' % page.pk)
2413
    # still no relation to follow
2414
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2415
        ('--', False, 'Identifier from page URL'),
2416
        ('__all__', False, 'All cards'),
2417
        ('', True, 'Other Card Identifiers'),
2418
    ]
2419
    # can not user cell with multiple ids as reference
2420
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2421
        ('--', True, 'Identifier from page URL'),
2422
        ('__all__', False, 'All cards'),
2423
        ('', False, 'Other Card Identifiers'),
2424
    ]
2425

  
2426
    # define a slug on second cell
2427
    cell.card_ids = ''
2428
    cell.save()
2429
    cell2.slug = 'slugb'
2430
    cell2.save()
2431
    resp = app.get('/manage/pages/%s/' % page.pk)
2432
    # multiple relations to follow
2433
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2434
        ('--', True, 'Identifier from page URL'),
2435
        ('__all__', False, 'All cards'),
2436
        ('', False, 'Other Card Identifiers'),
2437
        ('slugb/reverse:cardb', False, 'slugb/cardb (reverse)'),
2438
        ('slugb/reverse:cardsb', False, 'slugb/cardsb (reverse)'),
2439
        ('slugb/reverse:blockb_cardb', False, 'slugb/blockb_cardb (reverse)'),
2440
    ]
2441
    # still multiple relations to follow
2442
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2443
        ('--', True, 'Identifier from page URL'),
2444
        ('__all__', False, 'All cards'),
2445
        ('', False, 'Other Card Identifiers'),
2446
        ('sluga/cardb', False, 'sluga/cardb'),
2447
        ('sluga/cardsb', False, 'sluga/cardsb'),
2448
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
2449
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
2450
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
2451
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
2452
    ]
2453

  
2454
    # set a related_path on cell2
2455
    resp.forms[1]['c%s-related_card_path' % cell2.get_reference()] = 'sluga/cardb'
2456
    resp.forms[1]['c%s-card_ids' % cell2.get_reference()] = 'foobar'
2457
    resp = resp.forms[1].submit()
2458
    cell2.refresh_from_db()
2459
    assert cell2.related_card_path == 'sluga/cardb'
2460
    assert cell2.card_ids == ''
2461
    resp = app.get('/manage/pages/%s/' % page.pk)
2462
    # no more relation to follow
2463
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2464
        ('--', True, 'Identifier from page URL'),
2465
        ('__all__', False, 'All cards'),
2466
        ('', False, 'Other Card Identifiers'),
2467
    ]
2468
    # still multiple relations to follow
2469
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2470
        ('--', False, 'Identifier from page URL'),
2471
        ('__all__', False, 'All cards'),
2472
        ('', False, 'Other Card Identifiers'),
2473
        ('sluga/cardb', True, 'sluga/cardb'),
2474
        ('sluga/cardsb', False, 'sluga/cardsb'),
2475
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
2476
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
2477
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
2478
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
2479
    ]
2480
    resp.forms[1].submit()
2481
    cell2.refresh_from_db()
2482
    assert cell2.related_card_path == 'sluga/cardb'
2483
    assert cell2.card_ids == ''
2484

  
2485
    # check circular relations
2486
    cell.slug = 'sluge'
2487
    cell.carddef_reference = 'default:card_e'
2488
    cell.save()
2489
    cell2.carddef_reference = 'default:card_d'
2490
    cell2.slug = 'slugd'
2491
    cell2.related_card_path = ''
2492
    cell2.save()
2493
    resp = app.get('/manage/pages/%s/' % page.pk)
2494
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2495
        ('--', True, 'Identifier from page URL'),
2496
        ('__all__', False, 'All cards'),
2497
        ('', False, 'Other Card Identifiers'),
2498
        ('slugd/cardd-foo/carde-foo', False, 'slugd/cardd-foo/carde-foo'),
2499
        ('slugd/carde-foo', False, 'slugd/carde-foo'),
2500
    ]
2501
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2502
        ('--', True, 'Identifier from page URL'),
2503
        ('__all__', False, 'All cards'),
2504
        ('', False, 'Other Card Identifiers'),
2505
        ('sluge/cardd-bar', False, 'sluge/cardd-bar'),
2506
        ('sluge/reverse:carde-foo', False, 'sluge/carde-foo (reverse)'),
2507
    ]
2508

  
2509
    cell.slug = 'slugd'
2510
    cell.carddef_reference = 'default:card_d'
2511
    cell.save()
2512
    cell2.carddef_reference = 'default:card_d'
2513
    cell2.slug = 'slugd-bis'
2514
    cell2.related_card_path = ''
2515
    cell2.save()
2516
    resp = app.get('/manage/pages/%s/' % page.pk)
2517
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2518
        ('--', True, 'Identifier from page URL'),
2519
        ('__all__', False, 'All cards'),
2520
        ('', False, 'Other Card Identifiers'),
2521
        ('slugd-bis/cardd-foo', False, 'slugd-bis/cardd-foo'),
2522
        ('slugd-bis/reverse:cardd-foo', False, 'slugd-bis/cardd-foo (reverse)'),
2523
        ('slugd-bis/carde-foo/cardd-bar', False, 'slugd-bis/carde-foo/cardd-bar'),
2524
        ('slugd-bis/carde-foo/reverse:carde-foo', False, 'slugd-bis/carde-foo/carde-foo (reverse)'),
2525
    ]
2526
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2527
        ('--', True, 'Identifier from page URL'),
2528
        ('__all__', False, 'All cards'),
2529
        ('', False, 'Other Card Identifiers'),
2530
        ('slugd/cardd-foo', False, 'slugd/cardd-foo'),
2531
        ('slugd/reverse:cardd-foo', False, 'slugd/cardd-foo (reverse)'),
2532
        ('slugd/carde-foo/cardd-bar', False, 'slugd/carde-foo/cardd-bar'),
2533
        ('slugd/carde-foo/reverse:carde-foo', False, 'slugd/carde-foo/carde-foo (reverse)'),
2534
    ]
2535

  
2536
    cell.slug = 'sluge'
2537
    cell.carddef_reference = 'default:card_e'
2538
    cell.save()
2539
    cell2.carddef_reference = 'default:card_e'
2540
    cell2.slug = 'sluge-bis'
2541
    cell2.related_card_path = ''
2542
    cell2.save()
2543
    resp = app.get('/manage/pages/%s/' % page.pk)
2544
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
2545
        ('--', True, 'Identifier from page URL'),
2546
        ('__all__', False, 'All cards'),
2547
        ('', False, 'Other Card Identifiers'),
2548
        ('sluge-bis/cardd-bar/carde-foo', False, 'sluge-bis/cardd-bar/carde-foo'),
2549
    ]
2550
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
2551
        ('--', True, 'Identifier from page URL'),
2552
        ('__all__', False, 'All cards'),
2553
        ('', False, 'Other Card Identifiers'),
2554
        ('sluge/cardd-bar/carde-foo', False, 'sluge/cardd-bar/carde-foo'),
2555
    ]
2556

  
2557

  
2558
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2559
def test_manager_card_cell_tabs(mock_send, app, admin_user):
2560
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
2561
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
2562

  
2563
    app = login(app)
2564
    resp = app.get('/manage/pages/%s/' % page.pk)
2565
    assert not resp.pyquery('[data-tab-slug="general"] select[name$="title_type"]')
2566
    assert not resp.pyquery('[data-tab-slug="general"] input[name$="custom_title"]')
2567
    assert not resp.pyquery('[data-tab-slug="general"] input[name$="limit"]')
2568
    assert not resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
2569
    assert resp.pyquery('[data-tab-slug="appearance"] select[name$="title_type"]')
2570
    assert resp.pyquery('[data-tab-slug="appearance"] input[name$="custom_title"]')
2571
    assert not resp.pyquery('[data-tab-slug="appearance"] input[name$="customize_display"]')
2572
    assert resp.pyquery('[data-tab-slug="display"] input[name$="limit"]')
2573

  
2574
    cell.carddef_reference = 'default:card_model_1'
2575
    cell.save()
2576
    resp = app.get('/manage/pages/%s/' % page.pk)
2577
    assert resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
2578
    assert resp.pyquery('[data-tab-slug="display"] input[name$="customize_display"]')
2579

  
2580

  
2581
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2582
def test_card_cell_load(mock_send):
2583
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
2584
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2585
    cell.carddef_reference = 'default:card_model_1'
2586
    cell.save()
2587
    site_export = [page.get_serialized_page()]
2588
    cell.delete()
2589
    assert not Page.objects.get(pk=page.pk).get_cells()
2590
    Page.load_serialized_pages(site_export)
2591
    page = Page.objects.get(slug='test_cards')
2592
    cells = page.get_cells()
2593
    assert len(cells) == 1
2594
    cell = cells[0]
2595
    assert cell.cached_title == 'Card Model 1'
2596

  
2597

  
2598
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2599
def test_card_cell_render(mock_send, context, app):
2600
    page = Page.objects.create(title='xxx', template_name='standard')
2601
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2602
    cell.title_type = 'manual'
2603
    cell.custom_title = 'Foo bar {{ card.fields.title }}'
2604
    cell.save()
2605

  
2606
    # carddef_reference is not defined
2607
    context['card_model_1_id'] = 11
2608
    request = RequestFactory().get('/')
2609
    cell.modify_global_context(context, request)
2610
    context['synchronous'] = True  # to get fresh content
2611

  
2612
    result = cell.render(context)
2613
    assert '<h2>Card Model 1</h2>' not in result
2614
    assert '<p>Unknown Card</p>' in result
2615

  
2616
    # card id not in context
2617
    cell.carddef_reference = 'default:card_model_1'
2618
    cell.save()
2619
    del context['card_model_1_id']
2620
    assert 'card_model_1_id' not in context
2621
    result = cell.render(context)
2622
    assert '<h2>Card Model 1</h2>' in result  # default value
2623
    assert '<p>Unknown Card</p>' in result
2624

  
2625
    context['card_model_1_id'] = 11
2626
    request = RequestFactory().get('/')
2627
    cell.modify_global_context(context, request)
2628
    cell.repeat_index = 0
2629

  
2630
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2631
        mock_resp = Response()
2632
        mock_resp.status_code = 500
2633
        requests_get.return_value = mock_resp
2634
        result = cell.render(context)
2635
    assert '<h2>Card Model 1</h2>' in result  # default value
2636
    assert '<p>Unknown Card</p>' in result
2637
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2638
        requests_get.side_effect = ConnectionError()
2639
        result = cell.render(context)
2640
    assert '<h2>Card Model 1</h2>' in result  # default value
2641
    assert '<p>Unknown Card</p>' in result
2642

  
2643
    context.pop('title')
2644
    cell.title_type = 'auto'
2645
    cell.save()
2646
    mock_send.reset_mock()
2647
    result = cell.render(context)
2648
    assert '<h2>Card Model 1 - aa</h2>' in result
2649
    assert PyQuery(result).find('.label:contains("Field A") + .value').text() == '<i>a</i>'
2650
    assert PyQuery(result).find('.label:contains("Field B") + .value').text() == 'yes'
2651
    assert PyQuery(result).find('.label:contains("Field C") + .value').text() == 'Sept. 28, 2020'
2652
    assert PyQuery(result).find('.label:contains("Related") + .value').text() == 'Foo Bar'
2653
    assert 'related_raw' not in result
2654
    assert 'related_structured' not in result
2655
    assert PyQuery(result).find('.label:contains("Field D") + .value a').text() == 'file.pdf'
2656

  
2657
    context.pop('title')
2658
    cell.title_type = 'manual'
2659
    cell.custom_title = '<b>Foo bar {{ card.fields.fielda }}</b>'
2660
    cell.save()
2661
    assert cell.get_additional_label() == '&lt;b&gt;Foo bar {{ card.fields.fielda }}&lt;/b&gt;'
2662
    result = cell.render(context)
2663
    assert '<h2>&lt;b&gt;Foo bar &lt;i&gt;a&lt;/i&gt;&lt;/b&gt;</h2>' in result
2664

  
2665
    context.pop('title')
2666
    cell.custom_title = '{{ foobar }}'
2667
    cell.save()
2668
    result = cell.render(context)
2669
    assert '<h2>Card Model 1 - aa</h2>' in result  # empty value from template, default value
2670

  
2671
    context.pop('title')
2672
    cell.custom_title = '{% if %}'
2673
    cell.save()
2674
    result = cell.render(context)
2675
    assert '<h2>Card Model 1 - aa</h2>' in result  # template error, default value
2676

  
2677
    context.pop('title')
2678
    cell.title_type = 'empty'
2679
    cell.save()
2680
    result = cell.render(context)
2681
    assert '<h2>' not in result
2682

  
2683
    # test available context
2684
    cell.title_type = 'manual'
2685
    cell.custom_title = 'X{{ site_base }}Y'
2686
    cell.card_ids = '11'
2687
    cell.save()
2688
    resp = app.get(page.get_online_url())
2689
    assert len(resp.context['cells']) == 1
2690
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
2691
    cell_url = reverse(
2692
        'combo-public-ajax-page-cell',
2693
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
2694
    )
2695
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
2696
    assert '<h2>Xhttp://testserverY</h2>' in cell_resp
2697

  
2698
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
2699
    cell.title_type = 'manual'
2700
    cell.custom_title = 'Foo bar X{{ repeat_index }}Y'
2701
    cell.save()
2702
    resp = app.get(page.get_online_url())
2703
    assert len(resp.context['cells']) == 3
2704

  
2705
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
2706
    for i in range(0, 3):
2707
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
2708
        assert '<h2>Foo bar X%sY</h2>' % i in cell_resp
2709
    # again, without ajax: urls are already in cache
2710
    resp = app.get(page.get_online_url())
2711
    assert len(resp.context['cells']) == 3
2712
    for i in range(0, 3):
2713
        assert '<h2>Foo bar X%sY</h2>' % i in resp
2714
    assert 'data-paginate-by="10"' in resp
2715

  
2716
    cell.limit = 42
2717
    cell.save()
2718
    resp = app.get(page.get_online_url())
2719
    assert len(resp.context['cells']) == 3
2720
    for i in range(0, 3):
2721
        assert '<h2>Foo bar X%sY</h2>' % i in resp
2722
    assert 'data-paginate-by="42"' in resp
2723

  
2724
    # using custom view
2725
    cell.carddef_reference = 'default:card_model_1:foo'
2726
    cell.save()
2727
    result = cell.render(context)
2728
    assert 'Foo bar X0Y' in result
2729

  
2730
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
2731
        mock_resp = Response()
2732
        mock_resp.status_code = 404
2733
        requests_get.return_value = mock_resp
2734
        result = cell.render(context)
2735

  
2736
    # nothing, hide cell
2737
    assert not result.strip()
2738

  
2739

  
2740
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2741
def test_card_cell_render_text_field(mock_send, context):
2742
    page = Page.objects.create(title='xxx', template_name='standard')
2743
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2744
    cell.carddef_reference = 'default:card_model_1'
2745
    cell.save()
2746

  
2747
    context['card_model_1_id'] = 11
2748
    request = RequestFactory().get('/')
2749
    cell.modify_global_context(context, request)
2750
    cell.repeat_index = 0
2751
    context['synchronous'] = True  # to get fresh content
2752

  
2753
    result = cell.render(context)
2754

  
2755
    # field E is split in paragraphs
2756
    assert (
2757
        PyQuery(result).find('.label:contains("Field E") + .value p:first-child').text().strip()
2758
        == 'lorem<strong>ipsum'
2759
    )
2760
    assert (
2761
        PyQuery(result).find('.label:contains("Field E") + .value p:last-child').text().strip()
2762
        == "hello'world"
2763
    )
2764

  
2765
    # field F is put in a <pre>
2766
    assert (
2767
        PyQuery(result).find('.label:contains("Field F") + .value pre').text()
2768
        == 'lorem<strong>ipsum hello world'
2769
    )
2770

  
2771

  
2772
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2773
def test_card_cell_render_email_field(mock_send, context):
2774
    page = Page.objects.create(title='xxx', template_name='standard')
2775
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2776
    cell.carddef_reference = 'default:card_model_1'
2777
    cell.save()
2778

  
2779
    context['card_model_1_id'] = 11
2780
    request = RequestFactory().get('/')
2781
    cell.modify_global_context(context, request)
2782
    cell.repeat_index = 0
2783
    context['synchronous'] = True  # to get fresh content
2784

  
2785
    result = cell.render(context)
2786

  
2787
    assert PyQuery(result).find('.label:contains("Field G") + .value a').text() == 'test@localhost'
2788

  
2789
    assert (
2790
        PyQuery(result).find('.label:contains("Field G") + .value a').attr['href'] == 'mailto:test@localhost'
2791
    )
2792

  
2793

  
2794
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2795
def test_card_cell_render_string_with_url_field(mock_send, context):
2796
    page = Page.objects.create(title='xxx', template_name='standard')
2797
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2798
    cell.carddef_reference = 'default:card_model_1'
2799
    cell.custom_title = 'Foo bar {{ card.fields.title }}'
2800
    cell.save()
2801

  
2802
    context['card_model_1_id'] = 11
2803
    request = RequestFactory().get('/')
2804
    cell.modify_global_context(context, request)
2805
    cell.repeat_index = 0
2806
    context['synchronous'] = True  # to get fresh content
2807

  
2808
    result = cell.render(context)
2809

  
2810
    assert PyQuery(result).find('.label:contains("Field H") + .value a').text() == 'https://www.example.net/'
2811

  
2812
    assert (
2813
        PyQuery(result).find('.label:contains("Field H") + .value a').attr['href']
2814
        == 'https://www.example.net/'
2815
    )
2816

  
2817

  
2818
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2819
def test_card_cell_render_custom_schema_card_field(mock_send, context):
2820
    page = Page.objects.create(title='xxx', template_name='standard')
2821
    cell = WcsCardInfosCell.objects.create(
2822
        page=page,
2823
        placeholder='content',
2824
        order=0,
2825
        carddef_reference='default:card_model_1',
2826
        custom_schema={'cells': [{'varname': 'fielda', 'field_content': 'value', 'display_mode': 'title'}]},
2827
    )
2828

  
2829
    context['card_model_1_id'] = 11
2830
    request = RequestFactory().get('/')
2831
    cell.modify_global_context(context, request)
2832
    cell.repeat_index = 0
2833
    context['synchronous'] = True  # to get fresh content
2834

  
2835
    result = cell.render(context)
2836
    assert PyQuery(result).find('h3').text() == '<i>a</i>'
2837

  
2838
    cell.custom_schema['cells'][0] = {
2839
        'varname': 'fielda',
2840
        'field_content': 'value',
2841
        'display_mode': 'subtitle',
2842
    }
2843
    cell.save()
2844
    result = cell.render(context)
2845
    assert PyQuery(result).find('h4').text() == '<i>a</i>'
2846

  
2847
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'title'}
2848
    cell.save()
2849
    result = cell.render(context)
2850
    assert PyQuery(result).find('h3').text() == 'Field A'
2851

  
2852
    cell.custom_schema['cells'][0] = {
2853
        'varname': 'fielda',
2854
        'field_content': 'label',
2855
        'display_mode': 'subtitle',
2856
    }
2857
    cell.save()
2858
    result = cell.render(context)
2859
    assert PyQuery(result).find('h4').text() == 'Field A'
2860

  
2861
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'text'}
2862
    cell.save()
2863
    result = cell.render(context)
2864
    assert PyQuery(result).find('.label').text() == 'Field A'
2865

  
2866
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'value', 'display_mode': 'text'}
2867
    cell.save()
2868
    result = cell.render(context)
2869
    assert PyQuery(result).find('.value').text() == '<i>a</i>'
2870

  
2871
    cell.custom_schema['cells'][0] = {
2872
        'varname': 'fielda',
2873
        'field_content': 'label-and-value',
2874
        'display_mode': 'text',
2875
    }
2876
    cell.save()
2877
    result = cell.render(context)
2878
    assert PyQuery(result).find('.label').text() == 'Field A'
2879
    assert PyQuery(result).find('.value').text() == '<i>a</i>'
2880

  
2881
    cell.custom_schema['cells'][0] = {
2882
        'varname': 'fieldb',
2883
        'field_content': 'label-and-value',
2884
        'display_mode': 'text',
2885
    }
2886
    cell.save()
2887
    result = cell.render(context)
2888
    assert PyQuery(result).find('.label').text() == 'Field B'
2889
    assert PyQuery(result).find('.value').text() == 'yes'
2890

  
2891
    cell.custom_schema['cells'][0] = {
2892
        'varname': 'fieldc',
2893
        'field_content': 'label-and-value',
2894
        'display_mode': 'text',
2895
    }
2896
    cell.save()
2897
    result = cell.render(context)
2898
    assert PyQuery(result).find('.label').text() == 'Field C'
2899
    assert PyQuery(result).find('.value').text() == 'Sept. 28, 2020'
2900

  
2901
    cell.custom_schema['cells'][0] = {
2902
        'varname': 'related',
2903
        'field_content': 'label-and-value',
2904
        'display_mode': 'text',
2905
    }
2906
    cell.save()
2907
    result = cell.render(context)
2908
    assert PyQuery(result).find('.label').text() == 'Related'
2909
    assert PyQuery(result).find('.value').text() == 'Foo Bar'
2910

  
2911
    cell.custom_schema['cells'][0] = {
2912
        'varname': 'fieldd',
2913
        'field_content': 'label-and-value',
2914
        'display_mode': 'text',
2915
    }
2916
    cell.save()
2917
    result = cell.render(context)
2918
    assert PyQuery(result).find('.label').text() == 'Field D'
2919
    assert PyQuery(result).find('.value').text() == 'file.pdf'
2920

  
2921
    cell.custom_schema['cells'][0] = {
2922
        'varname': 'fielde',
2923
        'field_content': 'label-and-value',
2924
        'display_mode': 'text',
2925
    }
2926
    cell.save()
2927
    result = cell.render(context)
2928
    # check multiline text field is rendered with multiple paragraphs
2929
    # (first line "lorem<strong>ipsum" and last line ("hello'world")
2930
    # and the content is kept properly escaped.
2931
    assert PyQuery(result).find('.label').text() == 'Field E'
2932
    assert PyQuery(result).find('.value p:first-child').text().strip() == 'lorem<strong>ipsum'
2933
    assert PyQuery(result).find('.value p:last-child').text().strip() == "hello'world"
2934

  
2935
    cell.custom_schema['cells'][0] = {
2936
        'varname': 'fieldf',
2937
        'field_content': 'label-and-value',
2938
        'display_mode': 'text',
2939
    }
2940
    cell.save()
2941
    result = cell.render(context)
2942
    assert PyQuery(result).find('.label').text() == 'Field F'
2943
    assert PyQuery(result).find('.value pre').text() == 'lorem<strong>ipsum hello world'
2944

  
2945
    cell.custom_schema['cells'][0] = {
2946
        'varname': 'fieldg',
2947
        'field_content': 'label-and-value',
2948
        'display_mode': 'text',
2949
    }
2950
    cell.save()
2951
    result = cell.render(context)
2952
    assert PyQuery(result).find('.label').text() == 'Field G'
2953
    assert PyQuery(result).find('.value a').text() == 'test@localhost'
2954
    assert PyQuery(result).find('.value a').attr['href'] == 'mailto:test@localhost'
2955

  
2956
    cell.custom_schema['cells'][0] = {
2957
        'varname': 'fieldh',
2958
        'field_content': 'label-and-value',
2959
        'display_mode': 'text',
2960
    }
2961
    cell.save()
2962
    result = cell.render(context)
2963
    assert PyQuery(result).find('.label').text() == 'Field H'
2964
    assert PyQuery(result).find('.value a').text() == 'https://www.example.net/'
2965
    assert PyQuery(result).find('.value a').attr['href'] == 'https://www.example.net/'
2966

  
2967

  
2968
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2969
def test_card_cell_render_custom_schema_card_empty_field(mock_send, context):
2970
    page = Page.objects.create(title='xxx', template_name='standard')
2971
    cell = WcsCardInfosCell.objects.create(
2972
        page=page,
2973
        placeholder='content',
2974
        order=0,
2975
        carddef_reference='default:card_model_1',
2976
        custom_schema={
2977
            'cells': [
2978
                {
2979
                    'varname': 'empty',
2980
                    'field_content': 'label-and-value',
2981
                    'display_mode': 'text',
2982
                    'empty_value': '@skip@',
2983
                }
2984
            ]
2985
        },
2986
    )
2987

  
2988
    context['card_model_1_id'] = 11
2989
    request = RequestFactory().get('/')
2990
    cell.modify_global_context(context, request)
2991
    cell.repeat_index = 0
2992
    context['synchronous'] = True  # to get fresh content
2993

  
2994
    result = cell.render(context)
2995
    assert len(PyQuery(result).find('.cell--body > div > div')) == 0
2996
    assert PyQuery(result).find('.label') == []
2997
    assert PyQuery(result).find('.value') == []
2998

  
2999
    cell.custom_schema['cells'][0] = {
3000
        'varname': 'empty',
3001
        'field_content': 'label-and-value',
3002
        'display_mode': 'text',
3003
        'empty_value': '@empty@',
3004
    }
3005
    cell.save()
3006
    result = cell.render(context)
3007
    assert len(PyQuery(result).find('.cell--body > div > div')) == 1
3008
    assert PyQuery(result).find('.label').text() == 'Empty'
3009
    assert PyQuery(result).find('.value').text() == ''
3010

  
3011
    cell.custom_schema['cells'][0] = {
3012
        'varname': 'empty',
3013
        'field_content': 'label-and-value',
3014
        'display_mode': 'text',
3015
        'empty_value': 'Custom text',
3016
    }
3017
    cell.save()
3018
    result = cell.render(context)
3019
    assert len(PyQuery(result).find('.cell--body > div > div')) == 1
3020
    assert PyQuery(result).find('.label').text() == 'Empty'
3021
    assert PyQuery(result).find('.value').text() == 'Custom text'
3022

  
3023
    for field_content in ['label', 'value']:
3024
        for display_mode in ['text', 'title', 'subtitle']:
3025
            if display_mode == 'title':
3026
                html_tag = 'h3'
3027
            elif display_mode == 'subtitle':
3028
                html_tag = 'h4'
3029
            elif display_mode == 'text' and field_content == 'label':
3030
                html_tag = '.label'
3031
            elif display_mode == 'text' and field_content == 'value':
3032
                html_tag = '.value'
3033
            cell.custom_schema['cells'][0] = {
3034
                'varname': 'empty',
3035
                'field_content': field_content,
3036
                'display_mode': display_mode,
3037
                'empty_value': '@skip@',
3038
            }
3039
            cell.save()
3040
            result = cell.render(context)
3041
            assert len(PyQuery(result).find('.cell--body > div > div')) == 0
3042
            assert PyQuery(result).find(html_tag) == []
3043

  
3044
            cell.custom_schema['cells'][0] = {
3045
                'varname': 'empty',
3046
                'field_content': field_content,
3047
                'display_mode': display_mode,
3048
                'empty_value': '@empty@',
3049
            }
3050
            cell.save()
3051
            result = cell.render(context)
3052
            assert len(PyQuery(result).find('.cell--body > div > div')) == 1
3053
            assert PyQuery(result).find(html_tag).text() == ('Empty' if field_content == 'label' else '')
3054

  
3055
            cell.custom_schema['cells'][0] = {
3056
                'varname': 'empty',
3057
                'field_content': field_content,
3058
                'display_mode': display_mode,
3059
                'empty_value': 'Custom text',
3060
            }
3061
            cell.save()
3062
            result = cell.render(context)
3063
            assert len(PyQuery(result).find('.cell--body > div > div')) == 1
3064
            assert PyQuery(result).find(html_tag).text() == (
3065
                'Empty' if field_content == 'label' else 'Custom text'
3066
            )
3067

  
3068

  
3069
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3070
def test_card_cell_render_custom_schema_custom_entry(mock_send, context, app):
3071
    page = Page.objects.create(title='xxx', template_name='standard')
3072
    cell = WcsCardInfosCell.objects.create(
3073
        page=page,
3074
        placeholder='content',
3075
        order=0,
3076
        carddef_reference='default:card_model_1',
3077
        custom_schema={
3078
            'cells': [
3079
                {
3080
                    'varname': '@custom@',
3081
                    'template': "<b>Foo</b> bar'baz {{ card.fields.fielde }}",
3082
                    'display_mode': 'title',
3083
                },
3084
            ]
3085
        },
3086
    )
3087

  
3088
    context['card_model_1_id'] = 11
3089
    request = RequestFactory().get('/')
3090
    cell.modify_global_context(context, request)
3091
    cell.repeat_index = 0
3092
    context['synchronous'] = True  # to get fresh content
3093

  
3094
    result = cell.render(context)
3095
    assert '&lt;b&gt;Foo&lt;/b&gt;' in result
3096
    assert PyQuery(result).find('h3').text() == "<b>Foo</b> bar'baz lorem<strong>ipsum hello'world"
3097

  
3098
    # test context
3099
    cell.custom_schema['cells'][0][
3100
        'template'
3101
    ] = '{{ card.fields.fielda }} - {{ card.fields.related }} ({{ card.fields.related_structured.id }})'
3102
    cell.custom_schema['cells'][0]['display_mode'] = 'subtitle'
3103
    cell.save()
3104
    result = cell.render(context)
3105
    assert PyQuery(result).find('h4').text() == '<i>a</i> - Foo Bar (42)'
3106

  
3107
    # test display_mode & filters in template
3108
    cell.custom_schema = {
3109
        'cells': [
3110
            {'varname': '@custom@', 'template': 'Foo bar baz', 'display_mode': 'label'},
3111
            {
3112
                'varname': '@custom@',
3113
                'template': '{{ card.fields.related|split:" "|join:"," }}',
3114
                'display_mode': 'text',
3115
            },
3116
        ]
3117
    }
3118
    cell.save()
3119
    result = cell.render(context)
3120
    assert PyQuery(result).find('.label').text() == 'Foo bar baz'
3121
    assert PyQuery(result).find('.value').text() == 'Foo,Bar'
3122

  
3123
    # test available context
3124
    cell.card_ids = '11'
3125
    cell.custom_schema = {
3126
        'cells': [
3127
            {
3128
                'varname': '@custom@',
3129
                'template': 'Foo bar baz {% make_public_url url="http://127.0.0.1:8999/" %}',
3130
                'display_mode': 'label',
3131
            },
3132
        ]
3133
    }
3134
    cell.save()
3135
    resp = app.get(page.get_online_url())
3136
    assert len(resp.context['cells']) == 1
3137
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3138
    cell_url = reverse(
3139
        'combo-public-ajax-page-cell',
3140
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3141
    )
3142
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3143
    assert '/api/wcs/file/' in PyQuery(cell_resp.text).find('.label').text()
3144

  
3145
    cell.custom_schema = {
3146
        'cells': [
3147
            {'varname': '@custom@', 'template': 'Foo bar baz X{{ site_base }}Y', 'display_mode': 'label'},
3148
        ]
3149
    }
3150
    cell.save()
3151
    resp = app.get(page.get_online_url())
3152
    assert len(resp.context['cells']) == 1
3153
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3154
    cell_url = reverse(
3155
        'combo-public-ajax-page-cell',
3156
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3157
    )
3158
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3159
    assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz Xhttp://testserverY'
3160

  
3161
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
3162
    cell.custom_schema = {
3163
        'cells': [
3164
            {'varname': '@custom@', 'template': 'Foo bar baz X{{ repeat_index }}Y', 'display_mode': 'label'},
3165
        ]
3166
    }
3167
    cell.save()
3168
    resp = app.get(page.get_online_url())
3169
    assert len(resp.context['cells']) == 3
3170
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3171
    cell_url = reverse(
3172
        'combo-public-ajax-page-cell',
3173
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3174
    )
3175
    for i in range(0, 3):
3176
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
3177
        assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz X%sY' % i
3178

  
3179
    # custom schema but empty
3180
    cell.custom_schema = {'cells': []}
3181
    cell.save()
3182
    result = cell.render(context)
3183
    assert PyQuery(result).find('div.cell--body') == []
3184

  
3185

  
3186
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3187
def test_card_cell_render_custom_schema_link_entry(mock_send, context, app):
3188
    page = Page.objects.create(title='xxx', template_name='standard')
3189
    cell = WcsCardInfosCell.objects.create(
3190
        page=page,
3191
        placeholder='content',
3192
        order=0,
3193
        carddef_reference='default:card_model_1',
3194
        custom_schema={
3195
            'cells': [
3196
                {
3197
                    'varname': '@link@',
3198
                    'url_template': '/foo/bar/{{ card.fields.related_structured.id }}/',
3199
                    'template': '{{ card.fields.fielda }} - {{ card.fields.related }}',
3200
                    'display_mode': 'link',
3201
                },
3202
            ]
3203
        },
3204
    )
3205

  
3206
    context['card_model_1_id'] = 11
3207
    request = RequestFactory().get('/')
3208
    cell.modify_global_context(context, request)
3209
    cell.repeat_index = 0
3210
    context['synchronous'] = True  # to get fresh content
3211

  
3212
    result = cell.render(context)
3213
    assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
3214
    assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
3215
    assert PyQuery(result).find('.value a').attr['class'] is None
3216

  
3217
    cell.custom_schema['cells'][0]['display_mode'] = 'button'
3218
    cell.save()
3219
    result = cell.render(context)
3220
    assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
3221
    assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
3222
    assert PyQuery(result).find('.value a').attr['class'] == 'pk-button'
3223

  
3224
    cell.custom_schema['cells'][0][
3225
        'url_template'
3226
    ] = '{{ site_base }}/foo/bar/{{ card.fields.related_structured.id }}/'
3227
    cell.custom_schema['cells'][0]['template'] = '<b>{{ card.fields.fielda }}</b> - {{ card.fields.related }}'
3228
    cell.card_ids = '11'
3229
    cell.save()
3230
    resp = app.get(page.get_online_url())
3231
    assert len(resp.context['cells']) == 1
3232
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3233
    cell_url = reverse(
3234
        'combo-public-ajax-page-cell',
3235
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3236
    )
3237
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3238
    assert (
3239
        '<div class="value"><a href="http://testserver/foo/bar/42/" class="pk-button">&lt;b&gt;&lt;i&gt;a&lt;/i&gt;&lt;/b&gt; - Foo Bar</a></div>'
3240
        in cell_resp
3241
    )
3242

  
3243

  
3244
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3245
def test_card_cell_render_all_cards(mock_send, nocache, app):
3246
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
3247
    cell = WcsCardInfosCell.objects.create(
3248
        page=page,
3249
        placeholder='content',
3250
        order=0,
3251
        carddef_reference='default:card_model_1',
3252
        related_card_path='__all__',
3253
    )
3254

  
3255
    cell_url = reverse(
3256
        'combo-public-ajax-page-cell',
3257
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3258
    )
3259

  
3260
    # check url called
3261
    mock_send.reset_mock()
3262
    resp = app.get(page.get_online_url())
3263
    assert len(resp.context['cells']) == 3
3264
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3265
    for i in range(0, 3):
3266
        assert resp.context['cells'][i].pk == cell.pk
3267
        assert resp.context['cells'][i].repeat_index == i
3268
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
3269
        assert cell_resp.context['repeat_index'] == i
3270
    assert len(mock_send.call_args_list) == 7
3271
    # page rendering
3272
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
3273
    # cell rendering
3274
    for i in range(0, 3):
3275
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
3276
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
3277
        assert 'filter-internal-id' not in mock_send.call_args_list[i * 2 + 2][0][0].url
3278

  
3279

  
3280
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3281
def test_card_cell_render_identifier(mock_send, nocache, app):
3282
    page = Page.objects.create(
3283
        title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
3284
    )
3285
    cell = WcsCardInfosCell.objects.create(
3286
        page=page, placeholder='content', order=0, carddef_reference='default:card_model_1'
3287
    )
3288

  
3289
    cell_url = reverse(
3290
        'combo-public-ajax-page-cell',
3291
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
3292
    )
3293

  
3294
    # check url called
3295
    mock_send.reset_mock()
3296
    resp = app.get(page.get_online_url() + '11/')
3297
    assert len(resp.context['cells']) == 1
3298
    assert resp.context['cells'][0].pk == cell.pk
3299
    assert resp.context['cells'][0].repeat_index == 0
3300
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3301
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3302
    assert cell_resp.context['repeat_index'] == 0
3303
    assert 'Card Model 1' in cell_resp
3304
    assert '<p>Unknown Card</p>' not in cell_resp
3305
    assert len(mock_send.call_args_list) == 1
3306
    assert '/api/cards/card_model_1/11/' in mock_send.call_args_list[0][0][0].url
3307

  
3308
    # with identifiers
3309
    page.sub_slug = ''
3310
    page.save()
3311
    cell.card_ids = '42'
3312
    cell.save()
3313
    mock_send.reset_mock()
3314
    resp = app.get(page.get_online_url())
3315
    assert len(resp.context['cells']) == 1
3316
    assert resp.context['cells'][0].pk == cell.pk
3317
    assert resp.context['cells'][0].repeat_index == 0
3318
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3319
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3320
    assert cell_resp.context['repeat_index'] == 0
3321
    assert 'Card Model 1' in cell_resp
3322
    assert '<p>Unknown Card</p>' in cell_resp
3323
    assert len(mock_send.call_args_list) == 1
3324
    assert '/api/cards/card_model_1/42/' in mock_send.call_args_list[0][0][0].url
3325

  
3326
    cell.card_ids = '42, , 35'
3327
    cell.save()
3328
    mock_send.reset_mock()
3329
    resp = app.get(page.get_online_url())
3330
    assert len(resp.context['cells']) == 2
3331
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3332
    for i in range(0, 2):
3333
        assert resp.context['cells'][i].pk == cell.pk
3334
        assert resp.context['cells'][i].repeat_index == i
3335
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
3336
        assert cell_resp.context['repeat_index'] == i
3337
        assert 'Card Model 1' in cell_resp
3338
        assert '<p>Unknown Card</p>' in cell_resp
3339
    assert len(mock_send.call_args_list) == 2
3340
    for i in range(0, 2):
3341
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i][0][0].url
3342
        assert '&filter-internal-id=42&filter-internal-id=35&' in mock_send.call_args_list[i][0][0].url
3343

  
3344
    cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}'  # syntax error
3345
    cell.save()
3346
    mock_send.reset_mock()
3347
    resp = app.get(page.get_online_url())
3348
    assert len(resp.context['cells']) == 1
3349
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3350
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3351
    assert cell_resp.text.replace('\n', '') == ''  # empty-cell
3352

  
3353
    cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
3354
    cell.save()
3355
    mock_send.reset_mock()
3356
    resp = app.get(page.get_online_url())
3357
    assert len(resp.context['cells']) == 1
3358
    assert resp.context['cells'][0].pk == cell.pk
3359
    assert resp.context['cells'][0].repeat_index == 0
3360
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3361
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3362
    assert cell_resp.context['repeat_index'] == 0
3363
    assert len(mock_send.call_args_list) == 3
3364
    # page rendering
3365
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
3366
    # cell rendering
3367
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
3368
    assert '/api/cards/card_model_1/13' in mock_send.call_args_list[2][0][0].url
3369

  
3370
    def test_card_ids():
3371
        mock_send.reset_mock()
3372
        resp = app.get(page.get_online_url())
3373
        assert len(resp.context['cells']) == 3
3374
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3375
        for i in range(0, 3):
3376
            assert resp.context['cells'][i].pk == cell.pk
3377
            assert resp.context['cells'][i].repeat_index == i
3378
            cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
3379
            assert cell_resp.context['repeat_index'] == i
3380
        assert len(mock_send.call_args_list) == 7
3381
        # page rendering
3382
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
3383
        # cell rendering
3384
        card_ids = [c['id'] for c in WCS_CARDS_DATA['card_model_1']]
3385
        filters = '&%s&' % '&'.join('filter-internal-id=%s' % cid for cid in card_ids)
3386
        for i in range(0, 3):
3387
            assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
3388
            assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
3389
            assert filters in mock_send.call_args_list[i * 2 + 2][0][0].url
3390

  
3391
    for card_ids in [
3392
        '{% for card in cards|objects:"card_model_1" %}{{ card.id }},{% endfor %}',
3393
        '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}',
3394
    ]:
3395
        cell.card_ids = card_ids
3396
        cell.save()
3397
        test_card_ids()
3398

  
3399
        cell.card_ids = '{{ var1 }}'
3400
        cell.save()
3401
        page.extra_variables = {'var1': card_ids}
3402
        page.save()
3403
        test_card_ids()
3404
        page.extra_variables = {}
3405
        page.save()
3406

  
3407
    # with a card_ids template, but result is empty
3408
    cell.card_ids = '{{ foo }}'
3409
    cell.save()
3410
    resp = app.get(page.get_online_url())
3411
    assert len(resp.context['cells']) == 1
3412
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3413
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
3414
    assert cell_resp.text.replace('\n', '') == ''  # empty-cell
3415

  
3416

  
3417
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3418
def test_card_cell_render_identifier_from_related(mock_send, nocache, app):
3419
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
3420
    cell = WcsCardInfosCell.objects.create(
3421
        page=page,
3422
        placeholder='content',
3423
        order=0,
3424
        slug='sluga',
3425
        carddef_reference='default:card_a',
3426
        card_ids='1',
3427
    )
3428
    cell2 = WcsCardInfosCell.objects.create(
3429
        page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
3430
    )
3431

  
3432
    cell2_url = reverse(
3433
        'combo-public-ajax-page-cell',
3434
        kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
3435
    )
3436

  
3437
    def failing(urls):
3438
        resp = app.get(page.get_online_url())
3439
        assert len(resp.context['cells']) >= 2
3440
        for i in range(0, len(resp.context['cells']) - 1):
3441
            assert resp.context['cells'][i].pk == cell.pk
3442
        assert resp.context['cells'][-1].pk == cell2.pk
3443
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3444
        mock_send.reset_mock()
3445
        cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[-1])
3446
        assert cell_resp.text.replace('\n', '') == ''  # empty-cell
3447
        assert len(mock_send.call_args_list) == len(urls)
3448
        for j, url in enumerate(urls):
3449
            assert url in mock_send.call_args_list[j][0][0].url
3450

  
3451
    def single(urls):
3452
        resp = app.get(page.get_online_url())
3453
        assert len(resp.context['cells']) == 2
3454
        assert resp.context['cells'][0].pk == cell.pk
3455
        assert resp.context['cells'][1].pk == cell2.pk
3456
        assert resp.context['cells'][1].repeat_index == 0
3457
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3458
        mock_send.reset_mock()
3459
        cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[1])
3460
        assert cell_resp.context['repeat_index'] == 0
3461
        assert len(mock_send.call_args_list) == len(urls)
3462
        for j, url_parts in enumerate(urls):
3463
            if not isinstance(url_parts, tuple):
3464
                url_parts = (url_parts,)
3465
            for url_part in url_parts:
3466
                assert url_part in mock_send.call_args_list[j][0][0].url
3467

  
3468
    def multiple(urls):
3469
        resp = app.get(page.get_online_url())
3470
        assert len(resp.context['cells']) >= 2
3471
        assert resp.context['cells'][0].pk == cell.pk
3472
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3473
        for i in range(0, len(resp.context['cells']) - 1):
3474
            assert resp.context['cells'][i + 1].pk == cell2.pk
3475
            assert resp.context['cells'][i + 1].repeat_index == i
3476
            mock_send.reset_mock()
3477
            cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[i + 1])
3478
            assert cell_resp.context['repeat_index'] == i
3479
            assert len(mock_send.call_args_list) == len(urls)
3480
            for j, url_parts in enumerate(urls):
3481
                if not isinstance(url_parts, tuple):
3482
                    url_parts = (url_parts,)
3483
                for url_part in url_parts:
3484
                    assert url_part in mock_send.call_args_list[j][0][0].url
3485

  
3486
    # no cell with this slug
3487
    cell2.related_card_path = 'slugz/cardb'
3488
    cell2.save()
3489
    failing(urls=[])
3490

  
3491
    # another cell with the same slug
3492
    cell3 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
3493
    cell2.related_card_path = 'sluga/foo'
3494
    cell2.save()
3495
    failing(urls=[])
3496
    cell3.delete()
3497

  
3498
    # multiple ids configured on first cell
3499
    cell.card_ids = '{{ cards|objects:"card_a"|getlist:"id"|join:"," }}'
3500
    cell.save()
3501
    failing(
3502
        urls=[
3503
            # get first cell data
3504
            '/api/cards/card_a/list',
3505
        ]
3506
    )
3507

  
3508
    # related_card_path configured on first cell
3509
    cell.card_ids = '1'  # reset
3510
    cell.related_path = 'foobar'
3511
    cell.save()
3512
    failing(
3513
        urls=[
3514
            # get first cell data
3515
            '/api/cards/card_a/1/',
3516
        ]
3517
    )
3518

  
3519
    # reset
3520
    cell.related_path = ''
3521
    cell.save()
3522

  
3523
    # another cell as the same slug, but not a WcsCardInfosCell
3524
    cell3 = WcsCardsCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
3525

  
3526
    # direct and single relation (item)
3527
    cell2.related_card_path = 'sluga/cardb'
3528
    cell2.save()
3529
    single(
3530
        urls=[
3531
            # get first cell data
3532
            '/api/cards/card_a/1/',
3533
            # and follow cardb relation
3534
            '/api/cards/card_b/1/',  # check user access
3535
            '/api/cards/card_b/1/',  # get card
3536
        ]
3537
    )
3538
    cell3.delete()  # reset
3539

  
3540
    cell2.related_card_path = 'sluga/cardc/cardb'
3541
    cell2.save()
3542
    single(
3543
        urls=[
3544
            # get first cell data
3545
            '/api/cards/card_a/1/',
3546
            # get card_c schema
3547
            '/api/cards/card_c/@schema',
3548
            # follow cardc relation
3549
            '/api/cards/card_c/6/',
3550
            # and follow cardb relation
3551
            '/api/cards/card_b/7/',  # check user access
3552
            '/api/cards/card_b/7/',  # get card
3553
        ]
3554
    )
3555

  
3556
    # change cell ordering - cell with slug is after cell with related
3557
    cell.order = 42
3558
    cell.save()
3559
    # no error, but it does not work as expected: both cells has slug.
3560
    app.get(page.get_online_url(), status=200)
3561
    # remove slug of second cell
3562
    cell2.slug = ''
3563
    cell2.save()
3564
    urls = [
3565
        # get first cell data
3566
        '/api/cards/card_a/1/',
3567
        # get card_c schema
3568
        '/api/cards/card_c/@schema',
3569
        # follow cardc relation
3570
        '/api/cards/card_c/6/',
3571
        # and follow cardb relation
3572
        '/api/cards/card_b/7/',  # check user access
3573
        '/api/cards/card_b/7/',  # get card
3574
    ]
3575
    resp = app.get(page.get_online_url())
3576
    assert len(resp.context['cells']) == 2
3577
    assert resp.context['cells'][0].pk == cell2.pk
3578
    assert resp.context['cells'][0].repeat_index == 0
3579
    assert resp.context['cells'][1].pk == cell.pk
3580
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
3581
    mock_send.reset_mock()
3582
    cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[0])
3583
    assert cell_resp.context['repeat_index'] == 0
3584
    assert len(mock_send.call_args_list) == len(urls)
3585
    for j, url_parts in enumerate(urls):
3586
        if not isinstance(url_parts, tuple):
3587
            url_parts = (url_parts,)
3588
        for url_part in url_parts:
3589
            assert url_part in mock_send.call_args_list[j][0][0].url
3590

  
3591
    # reset
3592
    cell.order = 0  # reset
3593
    cell.save()
3594
    cell2.slug = 'slugb'
3595
    cell2.save()
3596

  
3597
    # test with custom_view
3598
    cell2.carddef_reference = 'default:card_b:a-custom-view'
3599
    cell2.save()
3600
    single(
3601
        urls=[
3602
            # get first cell data
3603
            '/api/cards/card_a/1/',
3604
            # get card_c schema
3605
            '/api/cards/card_c/@schema',
3606
            # follow cardc relation
3607
            '/api/cards/card_c/6/',
3608
            # and follow cardb relation
3609
            '/api/cards/card_b/a-custom-view/7/',  # check user access
3610
            '/api/cards/card_b/a-custom-view/7/',  # get card
3611
        ]
3612
    )
3613

  
3614
    # direct and multiple relation (items)
3615
    cell2.carddef_reference = 'default:card_b'  # reset
3616
    cell2.related_card_path = 'sluga/cardsb'
3617
    cell2.save()
3618
    multiple(
3619
        urls=[
3620
            # get first cell data
3621
            '/api/cards/card_a/1/',
3622
            # and follow cardb relation
3623
            ('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'),  # check user access
3624
            ('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'),  # get card
3625
        ]
3626
    )
3627

  
3628
    cell2.related_card_path = 'sluga/cardc/cardsb'
3629
    cell2.save()
3630
    multiple(
3631
        urls=[
3632
            # get first cell data
3633
            '/api/cards/card_a/1/',
3634
            # get card_c schema
3635
            '/api/cards/card_c/@schema',
3636
            # follow cardc relation
3637
            '/api/cards/card_c/6/',
3638
            # and follow cardb relation
3639
            ('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'),  # check user access
3640
            ('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'),  # get card
3641
        ]
3642
    )
3643

  
3644
    # direct and multiple relation through a block
3645
    cell2.related_card_path = 'sluga/blockb_cardb'
3646
    cell2.save()
3647
    multiple(
3648
        urls=[
3649
            # get first cell data
3650
            '/api/cards/card_a/1/',
3651
            # and follow cardb relation
3652
            ('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'),  # check user access
3653
            ('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'),  # get card
3654
        ]
3655
    )
3656

  
3657
    cell2.related_card_path = 'sluga/cardc/blockb_cardb'
3658
    cell2.save()
3659
    multiple(
3660
        urls=[
3661
            # get first cell data
3662
            '/api/cards/card_a/1/',
3663
            # get card_c schema
3664
            '/api/cards/card_c/@schema',
3665
            # follow cardc relation
3666
            '/api/cards/card_c/6/',
3667
            # and follow cardb relation
3668
            ('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'),  # check user access
3669
            ('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'),  # get card
3670
        ]
3671
    )
3672

  
3673
    # unknown part in related_card_path
3674
    cell2.related_card_path = 'sluga/foobar'
3675
    cell2.save()
3676
    failing(
3677
        urls=[
3678
            # get first cell data
3679
            '/api/cards/card_a/1/',
3680
        ]
3681
    )
3682
    cell2.related_card_path = 'sluga/cardc/foobar'
3683
    cell2.save()
3684
    failing(
3685
        urls=[
3686
            # get first cell data
3687
            '/api/cards/card_a/1/',
3688
            # get card_c schema
3689
            '/api/cards/card_c/@schema',
3690
            # follow cardc relation
3691
            '/api/cards/card_c/6/',
3692
        ]
3693
    )
3694

  
3695
    # card data not found
3696
    cell.card_ids = '42'
3697
    cell.save()
3698
    cell2.related_card_path = 'sluga/cardb'
3699
    cell2.save()
3700
    failing(
3701
        urls=[
3702
            # get first cell data
3703
            '/api/cards/card_a/42/',
3704
        ]
3705
    )
3706

  
3707
    cell.card_ids = '2'
3708
    cell.save()
3709
    cell2.related_card_path = 'sluga/cardc/cardb'
3710
    cell2.save()
3711
    failing(
3712
        urls=[
3713
            # get first cell data
3714
            '/api/cards/card_a/2/',
3715
            # get card_c schema
3716
            '/api/cards/card_c/@schema',
3717
            # follow cardc relation
3718
            '/api/cards/card_c/61/',
3719
        ]
3720
    )
3721
    # reset
3722
    cell.card_ids = '1'
3723
    cell.save()
3724

  
3725
    # last part has not the correct card slug
3726
    cell2.related_card_path = 'sluga/cardc'
3727
    cell2.save()
3728
    failing(
3729
        urls=[
3730
            # get first cell data
3731
            '/api/cards/card_a/1/',
3732
        ]
3733
    )
3734

  
3735
    # unknown schema
3736
    cell2.related_card_path = 'sluga/cardz/cardb'
3737
    cell2.save()
3738
    failing(
3739
        urls=[
3740
            # get first cell data
3741
            '/api/cards/card_a/1/',
3742
            # get card_z schema
3743
            '/api/cards/card_z/@schema',
3744
        ]
3745
    )
3746

  
3747
    # multiple relation of multiple relation
3748
    cell2.related_card_path = 'sluga/cardsb/reverse:cardb'
3749
    cell2.save()
3750
    failing(
3751
        urls=[
3752
            # get first cell data
3753
            '/api/cards/card_a/1/',
3754
        ]
3755
    )
3756

  
3757
    # field not found
3758
    cell.card_ids = '3'
3759
    cell.save()
3760
    cell2.related_card_path = 'sluga/cardb'
3761
    cell2.save()
3762
    failing(
3763
        urls=[
3764
            # get first cell data
3765
            '/api/cards/card_a/3/',
3766
        ]
3767
    )
3768
    cell2.related_card_path = 'sluga/cardc/cardb'
3769
    cell2.save()
3770
    failing(
3771
        urls=[
3772
            # get first cell data
3773
            '/api/cards/card_a/3/',
3774
        ]
3775
    )
3776

  
3777
    # field empty
3778
    cell.card_ids = '4'
3779
    cell.save()
3780
    cell2.related_card_path = 'sluga/cardb'
3781
    cell2.save()
3782
    failing(
3783
        urls=[
3784
            # get first cell data
3785
            '/api/cards/card_a/4/',
3786
        ]
3787
    )
3788

  
3789
    # field not found in block
3790
    cell.card_ids = '3'
3791
    cell.save()
3792
    cell2.related_card_path = 'sluga/blockb_cardb'
3793
    cell2.save()
3794
    failing(
3795
        urls=[
3796
            # get first cell data
3797
            '/api/cards/card_a/3/',
3798
        ]
3799
    )
3800

  
3801
    # field empty in block
3802
    cell.card_ids = '4'
3803
    cell.save()
3804
    cell2.related_card_path = 'sluga/blockb_cardb'
3805
    cell2.save()
3806
    failing(
3807
        urls=[
3808
            # get first cell data
3809
            '/api/cards/card_a/4/',
3810
        ]
3811
    )
3812

  
3813
    # reverse relation of item
3814
    cell.carddef_reference = 'default:card_b'
3815
    cell.slug = 'slugb'
3816
    cell.card_ids = '1'
3817
    cell.related_card_path = ''
3818
    cell.save()
3819
    cell2.carddef_reference = 'default:card_a'
3820
    cell2.slug = 'sluga'
3821
    cell2.card_ids = ''
3822
    cell2.related_card_path = 'slugb/reverse:cardb'
3823
    cell2.save()
3824
    multiple(
3825
        urls=[
3826
            # get first cell data
3827
            '/api/cards/card_b/1/',
3828
            # get list of card_a with cardb=1
3829
            '/api/cards/card_a/list?orig=combo&filter-cardb=1',
3830
            # and follow carda reverse relation
3831
            # check user access
3832
            (
3833
                '/api/cards/card_a/list',
3834
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3835
            ),
3836
            # get card
3837
            (
3838
                '/api/cards/card_a/list',
3839
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3840
            ),
3841
        ]
3842
    )
3843

  
3844
    # reverse relation of items
3845
    cell2.related_card_path = 'slugb/reverse:cardsb'
3846
    cell2.save()
3847
    multiple(
3848
        urls=[
3849
            # get first cell data
3850
            '/api/cards/card_b/1/',
3851
            # get list of card_a with cardsb=1
3852
            '/api/cards/card_a/list?orig=combo&filter-cardsb=1',
3853
            # and follow carda reverse relation
3854
            # check user access
3855
            (
3856
                '/api/cards/card_a/list',
3857
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3858
            ),
3859
            # get card
3860
            (
3861
                '/api/cards/card_a/list',
3862
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3863
            ),
3864
        ]
3865
    )
3866

  
3867
    # reverse relation of item through a block
3868
    cell2.related_card_path = 'slugb/reverse:blockb_cardb'
3869
    cell2.save()
3870
    multiple(
3871
        urls=[
3872
            # get first cell data
3873
            '/api/cards/card_b/1/',
3874
            # get list of card_a with cardsb=1
3875
            '/api/cards/card_a/list?orig=combo&filter-blockb_cardb=1',
3876
            # and follow carda reverse relation
3877
            # check user access
3878
            (
3879
                '/api/cards/card_a/list',
3880
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3881
            ),
3882
            # get card
3883
            (
3884
                '/api/cards/card_a/list',
3885
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
3886
            ),
3887
        ]
3888
    )
3889

  
3890
    # unknown part in related_card_path
3891
    cell2.related_card_path = 'slugb/foobar'
3892
    cell2.save()
3893
    failing(
3894
        urls=[
3895
            # get first cell data
3896
            '/api/cards/card_b/1/',
3897
        ]
3898
    )
3899

  
3900
    # multiple relation of multiple relation
3901
    cell2.related_card_path = 'slugb/reverse:cardb/cardsb'
3902
    cell2.save()
3903
    failing(
3904
        urls=[
3905
            # get first cell data
3906
            '/api/cards/card_b/1/',
3907
        ]
3908
    )
3909

  
3910
    # reverse relation with many models using the same varname
3911
    cell.carddef_reference = 'default:card_h'
3912
    cell.slug = 'slugh'
3913
    cell.card_ids = '42'
3914
    cell.related_card_path = ''
3915
    cell.save()
3916
    cell2.carddef_reference = 'default:card_f'
3917
    cell2.slug = 'slugf'
3918
    cell2.card_ids = ''
3919
    cell2.related_card_path = 'slugh/reverse:cardh'
3920
    cell2.save()
3921
    multiple(
3922
        urls=[
3923
            # get first cell data
3924
            '/api/cards/card_h/42/',
3925
            # get list of card_f with cardf=42
3926
            '/api/cards/card_f/list?orig=combo&filter-cardh=42',
3927
            # and follow cardf reverse relation
3928
            '/api/cards/card_f/41/',  # check user access
3929
            '/api/cards/card_f/41/',  # get card
3930
        ]
3931
    )
3932

  
3933
    cell.card_ids = '44'
3934
    cell.related_card_path = ''
3935
    cell.save()
3936
    cell2.carddef_reference = 'default:card_g'
3937
    cell2.slug = 'slugg'
3938
    cell2.card_ids = ''
3939
    cell2.related_card_path = 'slugh/reverse:cardh'
3940
    cell2.save()
3941
    multiple(
3942
        urls=[
3943
            # get first cell data
3944
            '/api/cards/card_h/44/',
3945
            # get list of card_g with cardf=44
3946
            '/api/cards/card_g/list?orig=combo&filter-cardh=44',
3947
            # and follow cardf reverse relation
3948
            '/api/cards/card_g/43/',  # check user access
3949
            '/api/cards/card_g/43/',  # get card
3950
        ]
3951
    )
3952

  
3953

  
3954
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
3955
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
3956
def test_card_cell_only_for_user(mock_send, context, carddef_reference):
3957
    page = Page.objects.create(title='xxx', template_name='standard')
3958
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
3959
    cell.carddef_reference = carddef_reference
3960
    cell.only_for_user = False
3961
    cell.save()
3962

  
3963
    context['card_model_1_id'] = 11
3964
    request = RequestFactory().get('/')
3965
    cell.modify_global_context(context, request)
3966
    cell.repeat_index = 0
3967

  
3968
    assert cell.is_visible(request=context['request']) is True
3969
    context['request'].user = MockUserWithNameId()
3970
    assert cell.is_visible(request=context['request']) is True
3971

  
3972
    cell.only_for_user = True
3973
    cell.save()
3974
    context['request'].user = None
3975
    assert cell.is_visible(request=context['request']) is False
3976
    context['request'].user = MockUserWithNameId()
3977
    assert cell.is_visible(request=context['request']) is True
3978

  
3979
    cache.clear()
3980
    context['synchronous'] = True  # to get fresh content
3981
    context['request'].user = None
3982

  
3983
    mock_send.reset_mock()
3984
    cell.render(context)
3985
    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
3986

  
3987
    context['request'].user = MockUser()
3988
    mock_send.reset_mock()
3989
    cell.render(context)
3990
    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
3991

  
3992
    context['request'].user = MockUserWithNameId()
3993
    mock_send.reset_mock()
3994
    cell.render(context)
3995
    assert 'filter-user-uuid=xyz' in mock_send.call_args_list[0][0][0].url
3996

  
3997

  
3998
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
3999
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
4000
def test_card_cell_render_user(mock_send, context, nocache, carddef_reference):
4001
    page = Page.objects.create(title='xxx', template_name='standard')
4002
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
4003
    cell.carddef_reference = carddef_reference
4004
    cell.save()
4005

  
4006
    context['card_model_1_id'] = 11
4007
    request = RequestFactory().get('/')
4008
    cell.modify_global_context(context, request)
4009
    cell.repeat_index = 0
4010
    context['synchronous'] = True  # to get fresh content
4011

  
4012
    assert context['request'].user is None
4013
    mock_send.reset_mock()
4014
    cell.render(context)
4015
    assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
4016
    assert 'email=&' in mock_send.call_args_list[0][0][0].url
4017

  
4018
    context['request'].user = AnonymousUser()
4019
    mock_send.reset_mock()
4020
    cell.render(context)
4021
    assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
4022
    assert 'email=&' in mock_send.call_args_list[0][0][0].url
4023

  
4024
    context['request'].user = MockUser()
4025
    mock_send.reset_mock()
4026
    cell.render(context)
4027
    assert 'email=foo%40example.net' in mock_send.call_args_list[0][0][0].url
4028

  
4029
    context['request'].user = MockUserWithNameId()
4030
    mock_send.reset_mock()
4031
    cell.render(context)
4032
    assert 'NameID=xyz' in mock_send.call_args_list[0][0][0].url
4033

  
4034
    cell.without_user = True
4035
    cell.save()
4036

  
4037
    context['request'].user = None
4038
    mock_send.reset_mock()
4039
    cell.render(context)
4040
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
4041
    assert 'email' not in mock_send.call_args_list[0][0][0].url
4042

  
4043
    context['request'].user = MockUser()
4044
    mock_send.reset_mock()
4045
    cell.render(context)
4046
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
4047
    assert 'email' not in mock_send.call_args_list[0][0][0].url
4048

  
4049
    context['request'].user = MockUserWithNameId()
4050
    mock_send.reset_mock()
4051
    cell.render(context)
4052
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
4053
    assert 'email' not in mock_send.call_args_list[0][0][0].url
4054

  
4055

  
4056 1568
def test_tracking_code_cell(app, nocache):
4057 1569
    page = Page(title='One', slug='index', template_name='standard')
4058 1570
    page.save()
tests/wcs/test_card.py
1
import json
2
import re
3
from unittest import mock
4

  
5
import pytest
6
from django.apps import apps
7
from django.contrib.auth.models import AnonymousUser
8
from django.core.cache import cache
9
from django.test.client import RequestFactory
10
from django.urls import reverse
11
from pyquery import PyQuery
12
from requests.exceptions import ConnectionError
13
from requests.models import Response
14

  
15
from combo.apps.wcs.forms import WcsCardInfoCellDisplayForm
16
from combo.apps.wcs.models import WcsCardInfosCell
17
from combo.data.models import Page, TextCell, ValidityInfo
18
from tests.test_manager import login
19
from tests.utils import manager_submit_cell
20

  
21
from .utils import WCS_CARDS_DATA, MockUser, MockUserWithNameId, mocked_requests_send
22

  
23
pytestmark = pytest.mark.django_db
24

  
25

  
26
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
27
def test_card_cell_setup(mock_send, app, admin_user):
28
    page = Page.objects.create(
29
        title='xxx', slug='test_card_cell_save_cache', template_name='standard', sub_slug='foobar'
30
    )
31
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
32
    form_class = cell.get_default_form_class()
33
    form = form_class(instance=cell)
34
    assert form.fields['carddef_reference'].widget.choices == [
35
        ('default:card_model_1', 'test : Card Model 1'),
36
        ('default:card_model_1:foo', 'test : Card Model 1 - bar'),
37
        ('default:card_model_2', 'test : Card Model 2'),
38
        ('default:card_model_3', 'test : Card Model 3'),
39
        ('default:card_a', 'test : Card A'),
40
        ('default:card_b', 'test : Card B'),
41
        ('default:card_b:a-custom-view', 'test : Card B - foo bar'),
42
        ('default:card_c', 'test : Card C'),
43
        ('default:card_d', 'test : Card D'),
44
        ('default:card_e', 'test : Card E'),
45
        ('other:card_model_1', 'test2 : Card Model 1'),
46
        ('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
47
        ('other:card_model_2', 'test2 : Card Model 2'),
48
        ('other:card_model_3', 'test2 : Card Model 3'),
49
        ('other:card_a', 'test2 : Card A'),
50
        ('other:card_b', 'test2 : Card B'),
51
        ('other:card_b:a-custom-view', 'test2 : Card B - foo bar'),
52
        ('other:card_c', 'test2 : Card C'),
53
        ('other:card_d', 'test2 : Card D'),
54
        ('other:card_e', 'test2 : Card E'),
55
    ]
56

  
57
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
58
    assert 'customize_display' not in form_display.fields
59
    assert 'custom_schema' not in form_display.fields
60

  
61
    cell.save()
62
    assert 'customize_display' not in form_display.fields
63
    assert 'custom_schema' not in form_display.fields
64

  
65
    cell.carddef_reference = 'default:card_model_1'
66
    cell.save()
67
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
68
    assert 'customize_display' in form_display.fields
69
    assert 'custom_schema' in form_display.fields
70
    assert 'customize_display' not in form_display.initial
71
    assert form_display.initial['custom_schema'] == {}
72

  
73
    cell.carddef_reference = 'default:card_model_1:foo'
74
    cell.save()
75
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
76
    assert 'customize_display' in form_display.fields
77
    assert 'custom_schema' in form_display.fields
78
    assert 'customize_display' not in form_display.initial
79
    assert form_display.initial['custom_schema'] == {}
80

  
81
    cell.carddef_reference = 'default:card_model_1'
82
    cell.save()
83

  
84
    cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
85
    cell.save()
86
    form_display = WcsCardInfoCellDisplayForm(instance=cell)
87
    assert 'customize_display' in form_display.fields
88
    assert 'custom_schema' in form_display.fields
89
    assert form_display.initial['customize_display'] is True
90
    assert form_display.initial['custom_schema'] == {
91
        'cells': [
92
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
93
        ]
94
    }
95

  
96
    WcsCardInfosCell.objects.all().delete()
97

  
98
    # check adding a cell from the UI
99
    app = login(app)
100
    resp = app.get('/manage/pages/%s/' % page.pk)
101
    cell_add_url = [x for x in resp.html.find_all('option') if x.text == 'Card Information Cell'][0].get(
102
        'data-add-url'
103
    )
104
    resp = app.get(cell_add_url).follow()
105
    cell = WcsCardInfosCell.objects.all().first()
106
    manager_submit_cell(resp.forms[0])  # will save card model
107
    cell.refresh_from_db()
108

  
109
    # check getting back to uncustomized display reset the schema
110
    cell.custom_schema = {
111
        'cells': [
112
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
113
        ]
114
    }
115
    cell.save()
116

  
117
    resp = app.get('/manage/pages/%s/' % page.pk)
118
    assert resp.forms[0]['c%s-customize_display' % cell.get_reference()].value == 'on'
119
    resp.forms[0]['c%s-customize_display' % cell.get_reference()].value = False
120
    manager_submit_cell(resp.forms[0])
121
    cell.refresh_from_db()
122
    assert cell.custom_schema == {}
123

  
124
    cell.custom_schema = {
125
        'cells': [
126
            {'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
127
        ]
128
    }
129
    cell.save()
130
    resp = app.get('/manage/pages/%s/' % page.pk)
131
    assert resp.forms[0]['c%s-display_mode' % cell.get_reference()].value == 'card'
132
    resp.forms[0]['c%s-display_mode' % cell.get_reference()].value = 'table'
133
    manager_submit_cell(resp.forms[0])
134
    cell.refresh_from_db()
135
    assert cell.custom_schema == {}
136

  
137
    assert cell.related_card_path == ''
138
    assert cell.card_ids == ''
139
    resp = app.get('/manage/pages/%s/' % page.pk)
140
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
141
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
142
    manager_submit_cell(resp.forms[0])
143
    cell.refresh_from_db()
144
    assert cell.related_card_path == ''
145
    assert cell.card_ids == ''
146
    resp = app.get('/manage/pages/%s/' % page.pk)
147
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
148
    resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value = ''
149
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
150
    manager_submit_cell(resp.forms[0])
151
    cell.refresh_from_db()
152
    assert cell.related_card_path == ''
153
    assert cell.card_ids == '42'
154

  
155
    # current page has a sub_slug, '--' option is present
156
    resp = app.get('/manage/pages/%s/' % page.pk)
157
    assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
158

  
159
    # current_page has no sub_slug, but parent page has one
160
    parent_page = Page.objects.create(
161
        title='parent', slug='parent', template_name='standard', sub_slug='foobar'
162
    )
163
    page.parent = parent_page
164
    page.sub_slug = ''
165
    page.save()
166
    resp = app.get('/manage/pages/%s/' % page.pk)
167
    assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
168

  
169
    # no sub_slug
170
    parent_page.sub_slug = ''
171
    parent_page.save()
172
    resp = app.get('/manage/pages/%s/' % page.pk)
173
    assert '--' not in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
174
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == ''
175
    resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = ''
176
    resp = resp.forms[0].submit()
177
    assert resp.context['form'].errors == {'card_ids': ['This field is required.']}
178

  
179

  
180
def test_card_cell_custom_schema_migration():
181
    cell = WcsCardInfosCell()
182

  
183
    cell.custom_schema = {
184
        'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
185
    }
186
    assert cell.get_custom_schema() == {
187
        'cells': [
188
            {
189
                'varname': 'some-field',
190
                'field_content': 'label',
191
                'display_mode': 'text',
192
                'empty_value': '@empty@',
193
                'cell_size': 'foobar',
194
            }
195
        ]
196
    }
197
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'value'}]}
198
    assert cell.get_custom_schema() == {
199
        'cells': [
200
            {
201
                'varname': 'some-field',
202
                'field_content': 'value',
203
                'display_mode': 'text',
204
                'empty_value': '@empty@',
205
            }
206
        ]
207
    }
208
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'label-and-value'}]}
209
    assert cell.get_custom_schema() == {
210
        'cells': [
211
            {
212
                'varname': 'some-field',
213
                'field_content': 'label-and-value',
214
                'display_mode': 'text',
215
                'empty_value': '@empty@',
216
            }
217
        ]
218
    }
219
    cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'title'}]}
220
    assert cell.get_custom_schema() == {
221
        'cells': [
222
            {
223
                'varname': 'some-field',
224
                'field_content': 'value',
225
                'display_mode': 'title',
226
                'empty_value': '@empty@',
227
            }
228
        ]
229
    }
230

  
231
    cell.custom_schema = {
232
        'cells': [
233
            {'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
234
        ]
235
    }
236
    assert cell.get_custom_schema() == {
237
        'cells': [
238
            {'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
239
        ]
240
    }
241
    cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'value'}]}
242
    assert cell.get_custom_schema() == {
243
        'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'text'}]
244
    }
245
    cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]}
246
    assert cell.get_custom_schema() == {
247
        'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]
248
    }
249

  
250

  
251
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
252
def test_card_cell_save_cache(mock_send):
253
    page = Page.objects.create(title='xxx', slug='test_card_cell_save_cache', template_name='standard')
254
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
255
    assert cell.get_additional_label() is None
256
    cell.carddef_reference = 'default:card_model_1'
257
    cell.save()
258
    assert cell.cached_title == 'Card Model 1'
259
    assert cell.cached_json != {}
260
    assert cell.get_additional_label() == 'Card Model 1'
261
    # make sure cached attributes are removed from serialized pages
262
    assert 'cached_' not in json.dumps(page.get_serialized_page())
263

  
264
    # artificially change title and json
265
    WcsCardInfosCell.objects.filter(pk=cell.pk).update(cached_title='XXX', cached_json={})
266
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'XXX'
267
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json == {}
268
    # run update db cache
269
    appconfig = apps.get_app_config('wcs')
270
    appconfig.update_db_cache()
271
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1'
272
    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json != {}
273

  
274

  
275
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
276
def test_card_cell_validity(mock_send):
277
    page = Page.objects.create(title='xxx', template_name='standard')
278
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
279
    validity_info = ValidityInfo.objects.latest('pk')
280
    assert validity_info.invalid_reason_code == 'wcs_card_not_defined'
281
    assert validity_info.invalid_since is not None
282

  
283
    cell.carddef_reference = 'default:card_model_1'
284
    cell.save()
285
    assert ValidityInfo.objects.exists() is False
286

  
287
    # can not retrieve data, don't set cell as invalid
288
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
289
        mock_resp = Response()
290
        mock_resp.status_code = 500
291
        requests_get.return_value = mock_resp
292
        cell.save()
293
    assert ValidityInfo.objects.exists() is False
294
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
295
        requests_get.side_effect = ConnectionError()
296
        cell.save()
297
    assert ValidityInfo.objects.exists() is False
298

  
299
    # can not retrieve carddefs, don't set cell as invalid
300
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
301
        mock_resp = Response()
302
        mock_resp.status_code = 404
303
        requests_get.return_value = mock_resp
304
        cell.save()
305
    assert ValidityInfo.objects.exists() is False
306

  
307
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
308
        mock_resp = Response()
309
        mock_resp.json = lambda *a, **k: {'err': 1, 'err_class': 'Page not found'}
310
        mock_resp.status_code = 404
311
        requests_get.return_value = mock_resp
312
        cell.carddef_reference = 'default:foobar'
313
        cell.save()
314
    validity_info = ValidityInfo.objects.latest('pk')
315
    assert validity_info.invalid_reason_code == 'wcs_card_not_found'
316
    assert validity_info.invalid_since is not None
317

  
318

  
319
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
320
def test_card_cell_check_validity(mock_send):
321
    page = Page.objects.create(title='xxx', template_name='standard')
322
    cell = WcsCardInfosCell.objects.create(
323
        page=page,
324
        placeholder='content',
325
        order=0,
326
        carddef_reference='default:card_a',
327
        card_ids='1',
328
    )
329
    cell2 = WcsCardInfosCell.objects.create(
330
        page=page, placeholder='content', order=1, carddef_reference='default:card_b'
331
    )
332

  
333
    # no related_card_path
334
    cell2.check_validity()
335
    assert ValidityInfo.objects.exists() is False
336

  
337
    # correct related_card_path but sluga is not defined
338
    cell2.related_card_path = 'sluga/cardb'
339
    cell2.save()
340
    cell2.check_validity()
341
    validity_info = ValidityInfo.objects.latest('pk')
342
    assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
343
    assert validity_info.invalid_since is not None
344

  
345
    # sluga is now defined
346
    cell.slug = 'sluga'
347
    cell.save()
348
    cell2.check_validity()
349
    assert ValidityInfo.objects.exists() is False
350

  
351
    # bad related_card_path
352
    cell2.related_card_path = 'sluga/foobar'
353
    cell2.save()
354
    cell2.check_validity()
355
    validity_info = ValidityInfo.objects.latest('pk')
356
    assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
357
    assert validity_info.invalid_since is not None
358

  
359

  
360
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
361
def test_manager_card_cell(mock_send, app, admin_user):
362
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
363
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
364

  
365
    app = login(app)
366
    resp = app.get('/manage/pages/%s/' % page.pk)
367
    assert 'application/json' not in resp
368

  
369
    cell.carddef_reference = 'default:card_model_1'
370
    cell.save()
371
    resp = app.get('/manage/pages/%s/' % page.pk)
372
    assert '<script id="cell-%s-card-schema-default:card_model_1" type="application/json">' % cell.pk in resp
373

  
374
    assert ('data-cell-reference="%s"' % cell.get_reference()) in resp.text
375
    assert cell.without_user is False
376
    assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value == 'on'
377
    resp.forms[0]['c%s-with_user' % cell.get_reference()].value = False
378
    manager_submit_cell(resp.forms[0])
379
    cell.refresh_from_db()
380
    assert cell.without_user is True
381
    assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value is None
382

  
383
    # card with relations
384
    cell.carddef_reference = 'default:card_a'
385
    cell.save()
386
    resp = app.get('/manage/pages/%s/' % page.pk)
387
    # but only one cell on the page, no relations to follow
388
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
389
        ('--', True, 'Identifier from page URL'),
390
        ('__all__', False, 'All cards'),
391
        ('', False, 'Other Card Identifiers'),
392
    ]
393

  
394
    # all cards
395
    cell.related_card_path = '__all__'
396
    cell.save()
397
    resp = app.get('/manage/pages/%s/' % page.pk)
398
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
399
        ('--', False, 'Identifier from page URL'),
400
        ('__all__', True, 'All cards'),
401
        ('', False, 'Other Card Identifiers'),
402
    ]
403

  
404
    # add a second cell, related to the first card model
405
    cell.related_card_path = ''
406
    cell.save()
407
    cell2 = WcsCardInfosCell.objects.create(
408
        page=page, placeholder='content', order=1, carddef_reference='default:card_b'
409
    )
410
    resp = app.get('/manage/pages/%s/' % page.pk)
411
    # still no relation to follow
412
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
413
        ('--', True, 'Identifier from page URL'),
414
        ('__all__', False, 'All cards'),
415
        ('', False, 'Other Card Identifiers'),
416
    ]
417
    # no cell with id and slug
418
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
419
        ('--', True, 'Identifier from page URL'),
420
        ('__all__', False, 'All cards'),
421
        ('', False, 'Other Card Identifiers'),
422
    ]
423

  
424
    # set a slug on first cell
425
    cell.slug = 'sluga'
426
    cell.save()
427
    resp = app.get('/manage/pages/%s/' % page.pk)
428
    # still no relation to follow
429
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
430
        ('--', True, 'Identifier from page URL'),
431
        ('__all__', False, 'All cards'),
432
        ('', False, 'Other Card Identifiers'),
433
    ]
434
    # multiple relations to follow
435
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
436
        ('--', True, 'Identifier from page URL'),
437
        ('__all__', False, 'All cards'),
438
        ('', False, 'Other Card Identifiers'),
439
        ('sluga/cardb', False, 'sluga/cardb'),
440
        ('sluga/cardsb', False, 'sluga/cardsb'),
441
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
442
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
443
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
444
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
445
    ]
446

  
447
    # set a list of ids on first cell
448
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
449
    cell.save()
450
    resp = app.get('/manage/pages/%s/' % page.pk)
451
    # still no relation to follow
452
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
453
        ('--', False, 'Identifier from page URL'),
454
        ('__all__', False, 'All cards'),
455
        ('', True, 'Other Card Identifiers'),
456
    ]
457
    # can not user cell with multiple ids as reference
458
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
459
        ('--', True, 'Identifier from page URL'),
460
        ('__all__', False, 'All cards'),
461
        ('', False, 'Other Card Identifiers'),
462
    ]
463

  
464
    # define a slug on second cell
465
    cell.card_ids = ''
466
    cell.save()
467
    cell2.slug = 'slugb'
468
    cell2.save()
469
    resp = app.get('/manage/pages/%s/' % page.pk)
470
    # multiple relations to follow
471
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
472
        ('--', True, 'Identifier from page URL'),
473
        ('__all__', False, 'All cards'),
474
        ('', False, 'Other Card Identifiers'),
475
        ('slugb/reverse:cardb', False, 'slugb/cardb (reverse)'),
476
        ('slugb/reverse:cardsb', False, 'slugb/cardsb (reverse)'),
477
        ('slugb/reverse:blockb_cardb', False, 'slugb/blockb_cardb (reverse)'),
478
    ]
479
    # still multiple relations to follow
480
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
481
        ('--', True, 'Identifier from page URL'),
482
        ('__all__', False, 'All cards'),
483
        ('', False, 'Other Card Identifiers'),
484
        ('sluga/cardb', False, 'sluga/cardb'),
485
        ('sluga/cardsb', False, 'sluga/cardsb'),
486
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
487
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
488
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
489
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
490
    ]
491

  
492
    # set a related_path on cell2
493
    resp.forms[1]['c%s-related_card_path' % cell2.get_reference()] = 'sluga/cardb'
494
    resp.forms[1]['c%s-card_ids' % cell2.get_reference()] = 'foobar'
495
    resp = resp.forms[1].submit()
496
    cell2.refresh_from_db()
497
    assert cell2.related_card_path == 'sluga/cardb'
498
    assert cell2.card_ids == ''
499
    resp = app.get('/manage/pages/%s/' % page.pk)
500
    # no more relation to follow
501
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
502
        ('--', True, 'Identifier from page URL'),
503
        ('__all__', False, 'All cards'),
504
        ('', False, 'Other Card Identifiers'),
505
    ]
506
    # still multiple relations to follow
507
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
508
        ('--', False, 'Identifier from page URL'),
509
        ('__all__', False, 'All cards'),
510
        ('', False, 'Other Card Identifiers'),
511
        ('sluga/cardb', True, 'sluga/cardb'),
512
        ('sluga/cardsb', False, 'sluga/cardsb'),
513
        ('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
514
        ('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
515
        ('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
516
        ('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
517
    ]
518
    resp.forms[1].submit()
519
    cell2.refresh_from_db()
520
    assert cell2.related_card_path == 'sluga/cardb'
521
    assert cell2.card_ids == ''
522

  
523
    # check circular relations
524
    cell.slug = 'sluge'
525
    cell.carddef_reference = 'default:card_e'
526
    cell.save()
527
    cell2.carddef_reference = 'default:card_d'
528
    cell2.slug = 'slugd'
529
    cell2.related_card_path = ''
530
    cell2.save()
531
    resp = app.get('/manage/pages/%s/' % page.pk)
532
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
533
        ('--', True, 'Identifier from page URL'),
534
        ('__all__', False, 'All cards'),
535
        ('', False, 'Other Card Identifiers'),
536
        ('slugd/cardd-foo/carde-foo', False, 'slugd/cardd-foo/carde-foo'),
537
        ('slugd/carde-foo', False, 'slugd/carde-foo'),
538
    ]
539
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
540
        ('--', True, 'Identifier from page URL'),
541
        ('__all__', False, 'All cards'),
542
        ('', False, 'Other Card Identifiers'),
543
        ('sluge/cardd-bar', False, 'sluge/cardd-bar'),
544
        ('sluge/reverse:carde-foo', False, 'sluge/carde-foo (reverse)'),
545
    ]
546

  
547
    cell.slug = 'slugd'
548
    cell.carddef_reference = 'default:card_d'
549
    cell.save()
550
    cell2.carddef_reference = 'default:card_d'
551
    cell2.slug = 'slugd-bis'
552
    cell2.related_card_path = ''
553
    cell2.save()
554
    resp = app.get('/manage/pages/%s/' % page.pk)
555
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
556
        ('--', True, 'Identifier from page URL'),
557
        ('__all__', False, 'All cards'),
558
        ('', False, 'Other Card Identifiers'),
559
        ('slugd-bis/cardd-foo', False, 'slugd-bis/cardd-foo'),
560
        ('slugd-bis/reverse:cardd-foo', False, 'slugd-bis/cardd-foo (reverse)'),
561
        ('slugd-bis/carde-foo/cardd-bar', False, 'slugd-bis/carde-foo/cardd-bar'),
562
        ('slugd-bis/carde-foo/reverse:carde-foo', False, 'slugd-bis/carde-foo/carde-foo (reverse)'),
563
    ]
564
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
565
        ('--', True, 'Identifier from page URL'),
566
        ('__all__', False, 'All cards'),
567
        ('', False, 'Other Card Identifiers'),
568
        ('slugd/cardd-foo', False, 'slugd/cardd-foo'),
569
        ('slugd/reverse:cardd-foo', False, 'slugd/cardd-foo (reverse)'),
570
        ('slugd/carde-foo/cardd-bar', False, 'slugd/carde-foo/cardd-bar'),
571
        ('slugd/carde-foo/reverse:carde-foo', False, 'slugd/carde-foo/carde-foo (reverse)'),
572
    ]
573

  
574
    cell.slug = 'sluge'
575
    cell.carddef_reference = 'default:card_e'
576
    cell.save()
577
    cell2.carddef_reference = 'default:card_e'
578
    cell2.slug = 'sluge-bis'
579
    cell2.related_card_path = ''
580
    cell2.save()
581
    resp = app.get('/manage/pages/%s/' % page.pk)
582
    assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
583
        ('--', True, 'Identifier from page URL'),
584
        ('__all__', False, 'All cards'),
585
        ('', False, 'Other Card Identifiers'),
586
        ('sluge-bis/cardd-bar/carde-foo', False, 'sluge-bis/cardd-bar/carde-foo'),
587
    ]
588
    assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
589
        ('--', True, 'Identifier from page URL'),
590
        ('__all__', False, 'All cards'),
591
        ('', False, 'Other Card Identifiers'),
592
        ('sluge/cardd-bar/carde-foo', False, 'sluge/cardd-bar/carde-foo'),
593
    ]
594

  
595

  
596
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
597
def test_manager_card_cell_tabs(mock_send, app, admin_user):
598
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
599
    cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
600

  
601
    app = login(app)
602
    resp = app.get('/manage/pages/%s/' % page.pk)
603
    assert not resp.pyquery('[data-tab-slug="general"] select[name$="title_type"]')
604
    assert not resp.pyquery('[data-tab-slug="general"] input[name$="custom_title"]')
605
    assert not resp.pyquery('[data-tab-slug="general"] input[name$="limit"]')
606
    assert not resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
607
    assert resp.pyquery('[data-tab-slug="appearance"] select[name$="title_type"]')
608
    assert resp.pyquery('[data-tab-slug="appearance"] input[name$="custom_title"]')
609
    assert not resp.pyquery('[data-tab-slug="appearance"] input[name$="customize_display"]')
610
    assert resp.pyquery('[data-tab-slug="display"] input[name$="limit"]')
611

  
612
    cell.carddef_reference = 'default:card_model_1'
613
    cell.save()
614
    resp = app.get('/manage/pages/%s/' % page.pk)
615
    assert resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
616
    assert resp.pyquery('[data-tab-slug="display"] input[name$="customize_display"]')
617

  
618

  
619
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
620
def test_card_cell_load(mock_send):
621
    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
622
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
623
    cell.carddef_reference = 'default:card_model_1'
624
    cell.save()
625
    site_export = [page.get_serialized_page()]
626
    cell.delete()
627
    assert not Page.objects.get(pk=page.pk).get_cells()
628
    Page.load_serialized_pages(site_export)
629
    page = Page.objects.get(slug='test_cards')
630
    cells = page.get_cells()
631
    assert len(cells) == 1
632
    cell = cells[0]
633
    assert cell.cached_title == 'Card Model 1'
634

  
635

  
636
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
637
def test_card_cell_render(mock_send, context, app):
638
    page = Page.objects.create(title='xxx', template_name='standard')
639
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
640
    cell.title_type = 'manual'
641
    cell.custom_title = 'Foo bar {{ card.fields.title }}'
642
    cell.save()
643

  
644
    # carddef_reference is not defined
645
    context['card_model_1_id'] = 11
646
    request = RequestFactory().get('/')
647
    cell.modify_global_context(context, request)
648
    context['synchronous'] = True  # to get fresh content
649

  
650
    result = cell.render(context)
651
    assert '<h2>Card Model 1</h2>' not in result
652
    assert '<p>Unknown Card</p>' in result
653

  
654
    # card id not in context
655
    cell.carddef_reference = 'default:card_model_1'
656
    cell.save()
657
    del context['card_model_1_id']
658
    assert 'card_model_1_id' not in context
659
    result = cell.render(context)
660
    assert '<h2>Card Model 1</h2>' in result  # default value
661
    assert '<p>Unknown Card</p>' in result
662

  
663
    context['card_model_1_id'] = 11
664
    request = RequestFactory().get('/')
665
    cell.modify_global_context(context, request)
666
    cell.repeat_index = 0
667

  
668
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
669
        mock_resp = Response()
670
        mock_resp.status_code = 500
671
        requests_get.return_value = mock_resp
672
        result = cell.render(context)
673
    assert '<h2>Card Model 1</h2>' in result  # default value
674
    assert '<p>Unknown Card</p>' in result
675
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
676
        requests_get.side_effect = ConnectionError()
677
        result = cell.render(context)
678
    assert '<h2>Card Model 1</h2>' in result  # default value
679
    assert '<p>Unknown Card</p>' in result
680

  
681
    context.pop('title')
682
    cell.title_type = 'auto'
683
    cell.save()
684
    mock_send.reset_mock()
685
    result = cell.render(context)
686
    assert '<h2>Card Model 1 - aa</h2>' in result
687
    assert PyQuery(result).find('.label:contains("Field A") + .value').text() == '<i>a</i>'
688
    assert PyQuery(result).find('.label:contains("Field B") + .value').text() == 'yes'
689
    assert PyQuery(result).find('.label:contains("Field C") + .value').text() == 'Sept. 28, 2020'
690
    assert PyQuery(result).find('.label:contains("Related") + .value').text() == 'Foo Bar'
691
    assert 'related_raw' not in result
692
    assert 'related_structured' not in result
693
    assert PyQuery(result).find('.label:contains("Field D") + .value a').text() == 'file.pdf'
694

  
695
    context.pop('title')
696
    cell.title_type = 'manual'
697
    cell.custom_title = '<b>Foo bar {{ card.fields.fielda }}</b>'
698
    cell.save()
699
    assert cell.get_additional_label() == '&lt;b&gt;Foo bar {{ card.fields.fielda }}&lt;/b&gt;'
700
    result = cell.render(context)
701
    assert '<h2>&lt;b&gt;Foo bar &lt;i&gt;a&lt;/i&gt;&lt;/b&gt;</h2>' in result
702

  
703
    context.pop('title')
704
    cell.custom_title = '{{ foobar }}'
705
    cell.save()
706
    result = cell.render(context)
707
    assert '<h2>Card Model 1 - aa</h2>' in result  # empty value from template, default value
708

  
709
    context.pop('title')
710
    cell.custom_title = '{% if %}'
711
    cell.save()
712
    result = cell.render(context)
713
    assert '<h2>Card Model 1 - aa</h2>' in result  # template error, default value
714

  
715
    context.pop('title')
716
    cell.title_type = 'empty'
717
    cell.save()
718
    result = cell.render(context)
719
    assert '<h2>' not in result
720

  
721
    # test available context
722
    cell.title_type = 'manual'
723
    cell.custom_title = 'X{{ site_base }}Y'
724
    cell.card_ids = '11'
725
    cell.save()
726
    resp = app.get(page.get_online_url())
727
    assert len(resp.context['cells']) == 1
728
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
729
    cell_url = reverse(
730
        'combo-public-ajax-page-cell',
731
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
732
    )
733
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
734
    assert '<h2>Xhttp://testserverY</h2>' in cell_resp
735

  
736
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
737
    cell.title_type = 'manual'
738
    cell.custom_title = 'Foo bar X{{ repeat_index }}Y'
739
    cell.save()
740
    resp = app.get(page.get_online_url())
741
    assert len(resp.context['cells']) == 3
742

  
743
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
744
    for i in range(0, 3):
745
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
746
        assert '<h2>Foo bar X%sY</h2>' % i in cell_resp
747
    # again, without ajax: urls are already in cache
748
    resp = app.get(page.get_online_url())
749
    assert len(resp.context['cells']) == 3
750
    for i in range(0, 3):
751
        assert '<h2>Foo bar X%sY</h2>' % i in resp
752
    assert 'data-paginate-by="10"' in resp
753

  
754
    cell.limit = 42
755
    cell.save()
756
    resp = app.get(page.get_online_url())
757
    assert len(resp.context['cells']) == 3
758
    for i in range(0, 3):
759
        assert '<h2>Foo bar X%sY</h2>' % i in resp
760
    assert 'data-paginate-by="42"' in resp
761

  
762
    # using custom view
763
    cell.carddef_reference = 'default:card_model_1:foo'
764
    cell.save()
765
    result = cell.render(context)
766
    assert 'Foo bar X0Y' in result
767

  
768
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
769
        mock_resp = Response()
770
        mock_resp.status_code = 404
771
        requests_get.return_value = mock_resp
772
        result = cell.render(context)
773

  
774
    # nothing, hide cell
775
    assert not result.strip()
776

  
777

  
778
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
779
def test_card_cell_render_text_field(mock_send, context):
780
    page = Page.objects.create(title='xxx', template_name='standard')
781
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
782
    cell.carddef_reference = 'default:card_model_1'
783
    cell.save()
784

  
785
    context['card_model_1_id'] = 11
786
    request = RequestFactory().get('/')
787
    cell.modify_global_context(context, request)
788
    cell.repeat_index = 0
789
    context['synchronous'] = True  # to get fresh content
790

  
791
    result = cell.render(context)
792

  
793
    # field E is split in paragraphs
794
    assert (
795
        PyQuery(result).find('.label:contains("Field E") + .value p:first-child').text().strip()
796
        == 'lorem<strong>ipsum'
797
    )
798
    assert (
799
        PyQuery(result).find('.label:contains("Field E") + .value p:last-child').text().strip()
800
        == "hello'world"
801
    )
802

  
803
    # field F is put in a <pre>
804
    assert (
805
        PyQuery(result).find('.label:contains("Field F") + .value pre').text()
806
        == 'lorem<strong>ipsum hello world'
807
    )
808

  
809

  
810
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
811
def test_card_cell_render_email_field(mock_send, context):
812
    page = Page.objects.create(title='xxx', template_name='standard')
813
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
814
    cell.carddef_reference = 'default:card_model_1'
815
    cell.save()
816

  
817
    context['card_model_1_id'] = 11
818
    request = RequestFactory().get('/')
819
    cell.modify_global_context(context, request)
820
    cell.repeat_index = 0
821
    context['synchronous'] = True  # to get fresh content
822

  
823
    result = cell.render(context)
824

  
825
    assert PyQuery(result).find('.label:contains("Field G") + .value a').text() == 'test@localhost'
826

  
827
    assert (
828
        PyQuery(result).find('.label:contains("Field G") + .value a').attr['href'] == 'mailto:test@localhost'
829
    )
830

  
831

  
832
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
833
def test_card_cell_render_string_with_url_field(mock_send, context):
834
    page = Page.objects.create(title='xxx', template_name='standard')
835
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
836
    cell.carddef_reference = 'default:card_model_1'
837
    cell.custom_title = 'Foo bar {{ card.fields.title }}'
838
    cell.save()
839

  
840
    context['card_model_1_id'] = 11
841
    request = RequestFactory().get('/')
842
    cell.modify_global_context(context, request)
843
    cell.repeat_index = 0
844
    context['synchronous'] = True  # to get fresh content
845

  
846
    result = cell.render(context)
847

  
848
    assert PyQuery(result).find('.label:contains("Field H") + .value a').text() == 'https://www.example.net/'
849

  
850
    assert (
851
        PyQuery(result).find('.label:contains("Field H") + .value a').attr['href']
852
        == 'https://www.example.net/'
853
    )
854

  
855

  
856
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
857
def test_card_cell_render_custom_schema_card_field(mock_send, context):
858
    page = Page.objects.create(title='xxx', template_name='standard')
859
    cell = WcsCardInfosCell.objects.create(
860
        page=page,
861
        placeholder='content',
862
        order=0,
863
        carddef_reference='default:card_model_1',
864
        custom_schema={'cells': [{'varname': 'fielda', 'field_content': 'value', 'display_mode': 'title'}]},
865
    )
866

  
867
    context['card_model_1_id'] = 11
868
    request = RequestFactory().get('/')
869
    cell.modify_global_context(context, request)
870
    cell.repeat_index = 0
871
    context['synchronous'] = True  # to get fresh content
872

  
873
    result = cell.render(context)
874
    assert PyQuery(result).find('h3').text() == '<i>a</i>'
875

  
876
    cell.custom_schema['cells'][0] = {
877
        'varname': 'fielda',
878
        'field_content': 'value',
879
        'display_mode': 'subtitle',
880
    }
881
    cell.save()
882
    result = cell.render(context)
883
    assert PyQuery(result).find('h4').text() == '<i>a</i>'
884

  
885
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'title'}
886
    cell.save()
887
    result = cell.render(context)
888
    assert PyQuery(result).find('h3').text() == 'Field A'
889

  
890
    cell.custom_schema['cells'][0] = {
891
        'varname': 'fielda',
892
        'field_content': 'label',
893
        'display_mode': 'subtitle',
894
    }
895
    cell.save()
896
    result = cell.render(context)
897
    assert PyQuery(result).find('h4').text() == 'Field A'
898

  
899
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'text'}
900
    cell.save()
901
    result = cell.render(context)
902
    assert PyQuery(result).find('.label').text() == 'Field A'
903

  
904
    cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'value', 'display_mode': 'text'}
905
    cell.save()
906
    result = cell.render(context)
907
    assert PyQuery(result).find('.value').text() == '<i>a</i>'
908

  
909
    cell.custom_schema['cells'][0] = {
910
        'varname': 'fielda',
911
        'field_content': 'label-and-value',
912
        'display_mode': 'text',
913
    }
914
    cell.save()
915
    result = cell.render(context)
916
    assert PyQuery(result).find('.label').text() == 'Field A'
917
    assert PyQuery(result).find('.value').text() == '<i>a</i>'
918

  
919
    cell.custom_schema['cells'][0] = {
920
        'varname': 'fieldb',
921
        'field_content': 'label-and-value',
922
        'display_mode': 'text',
923
    }
924
    cell.save()
925
    result = cell.render(context)
926
    assert PyQuery(result).find('.label').text() == 'Field B'
927
    assert PyQuery(result).find('.value').text() == 'yes'
928

  
929
    cell.custom_schema['cells'][0] = {
930
        'varname': 'fieldc',
931
        'field_content': 'label-and-value',
932
        'display_mode': 'text',
933
    }
934
    cell.save()
935
    result = cell.render(context)
936
    assert PyQuery(result).find('.label').text() == 'Field C'
937
    assert PyQuery(result).find('.value').text() == 'Sept. 28, 2020'
938

  
939
    cell.custom_schema['cells'][0] = {
940
        'varname': 'related',
941
        'field_content': 'label-and-value',
942
        'display_mode': 'text',
943
    }
944
    cell.save()
945
    result = cell.render(context)
946
    assert PyQuery(result).find('.label').text() == 'Related'
947
    assert PyQuery(result).find('.value').text() == 'Foo Bar'
948

  
949
    cell.custom_schema['cells'][0] = {
950
        'varname': 'fieldd',
951
        'field_content': 'label-and-value',
952
        'display_mode': 'text',
953
    }
954
    cell.save()
955
    result = cell.render(context)
956
    assert PyQuery(result).find('.label').text() == 'Field D'
957
    assert PyQuery(result).find('.value').text() == 'file.pdf'
958

  
959
    cell.custom_schema['cells'][0] = {
960
        'varname': 'fielde',
961
        'field_content': 'label-and-value',
962
        'display_mode': 'text',
963
    }
964
    cell.save()
965
    result = cell.render(context)
966
    # check multiline text field is rendered with multiple paragraphs
967
    # (first line "lorem<strong>ipsum" and last line ("hello'world")
968
    # and the content is kept properly escaped.
969
    assert PyQuery(result).find('.label').text() == 'Field E'
970
    assert PyQuery(result).find('.value p:first-child').text().strip() == 'lorem<strong>ipsum'
971
    assert PyQuery(result).find('.value p:last-child').text().strip() == "hello'world"
972

  
973
    cell.custom_schema['cells'][0] = {
974
        'varname': 'fieldf',
975
        'field_content': 'label-and-value',
976
        'display_mode': 'text',
977
    }
978
    cell.save()
979
    result = cell.render(context)
980
    assert PyQuery(result).find('.label').text() == 'Field F'
981
    assert PyQuery(result).find('.value pre').text() == 'lorem<strong>ipsum hello world'
982

  
983
    cell.custom_schema['cells'][0] = {
984
        'varname': 'fieldg',
985
        'field_content': 'label-and-value',
986
        'display_mode': 'text',
987
    }
988
    cell.save()
989
    result = cell.render(context)
990
    assert PyQuery(result).find('.label').text() == 'Field G'
991
    assert PyQuery(result).find('.value a').text() == 'test@localhost'
992
    assert PyQuery(result).find('.value a').attr['href'] == 'mailto:test@localhost'
993

  
994
    cell.custom_schema['cells'][0] = {
995
        'varname': 'fieldh',
996
        'field_content': 'label-and-value',
997
        'display_mode': 'text',
998
    }
999
    cell.save()
1000
    result = cell.render(context)
1001
    assert PyQuery(result).find('.label').text() == 'Field H'
1002
    assert PyQuery(result).find('.value a').text() == 'https://www.example.net/'
1003
    assert PyQuery(result).find('.value a').attr['href'] == 'https://www.example.net/'
1004

  
1005

  
1006
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1007
def test_card_cell_render_custom_schema_card_empty_field(mock_send, context):
1008
    page = Page.objects.create(title='xxx', template_name='standard')
1009
    cell = WcsCardInfosCell.objects.create(
1010
        page=page,
1011
        placeholder='content',
1012
        order=0,
1013
        carddef_reference='default:card_model_1',
1014
        custom_schema={
1015
            'cells': [
1016
                {
1017
                    'varname': 'empty',
1018
                    'field_content': 'label-and-value',
1019
                    'display_mode': 'text',
1020
                    'empty_value': '@skip@',
1021
                }
1022
            ]
1023
        },
1024
    )
1025

  
1026
    context['card_model_1_id'] = 11
1027
    request = RequestFactory().get('/')
1028
    cell.modify_global_context(context, request)
1029
    cell.repeat_index = 0
1030
    context['synchronous'] = True  # to get fresh content
1031

  
1032
    result = cell.render(context)
1033
    assert len(PyQuery(result).find('.cell--body > div > div')) == 0
1034
    assert PyQuery(result).find('.label') == []
1035
    assert PyQuery(result).find('.value') == []
1036

  
1037
    cell.custom_schema['cells'][0] = {
1038
        'varname': 'empty',
1039
        'field_content': 'label-and-value',
1040
        'display_mode': 'text',
1041
        'empty_value': '@empty@',
1042
    }
1043
    cell.save()
1044
    result = cell.render(context)
1045
    assert len(PyQuery(result).find('.cell--body > div > div')) == 1
1046
    assert PyQuery(result).find('.label').text() == 'Empty'
1047
    assert PyQuery(result).find('.value').text() == ''
1048

  
1049
    cell.custom_schema['cells'][0] = {
1050
        'varname': 'empty',
1051
        'field_content': 'label-and-value',
1052
        'display_mode': 'text',
1053
        'empty_value': 'Custom text',
1054
    }
1055
    cell.save()
1056
    result = cell.render(context)
1057
    assert len(PyQuery(result).find('.cell--body > div > div')) == 1
1058
    assert PyQuery(result).find('.label').text() == 'Empty'
1059
    assert PyQuery(result).find('.value').text() == 'Custom text'
1060

  
1061
    for field_content in ['label', 'value']:
1062
        for display_mode in ['text', 'title', 'subtitle']:
1063
            if display_mode == 'title':
1064
                html_tag = 'h3'
1065
            elif display_mode == 'subtitle':
1066
                html_tag = 'h4'
1067
            elif display_mode == 'text' and field_content == 'label':
1068
                html_tag = '.label'
1069
            elif display_mode == 'text' and field_content == 'value':
1070
                html_tag = '.value'
1071
            cell.custom_schema['cells'][0] = {
1072
                'varname': 'empty',
1073
                'field_content': field_content,
1074
                'display_mode': display_mode,
1075
                'empty_value': '@skip@',
1076
            }
1077
            cell.save()
1078
            result = cell.render(context)
1079
            assert len(PyQuery(result).find('.cell--body > div > div')) == 0
1080
            assert PyQuery(result).find(html_tag) == []
1081

  
1082
            cell.custom_schema['cells'][0] = {
1083
                'varname': 'empty',
1084
                'field_content': field_content,
1085
                'display_mode': display_mode,
1086
                'empty_value': '@empty@',
1087
            }
1088
            cell.save()
1089
            result = cell.render(context)
1090
            assert len(PyQuery(result).find('.cell--body > div > div')) == 1
1091
            assert PyQuery(result).find(html_tag).text() == ('Empty' if field_content == 'label' else '')
1092

  
1093
            cell.custom_schema['cells'][0] = {
1094
                'varname': 'empty',
1095
                'field_content': field_content,
1096
                'display_mode': display_mode,
1097
                'empty_value': 'Custom text',
1098
            }
1099
            cell.save()
1100
            result = cell.render(context)
1101
            assert len(PyQuery(result).find('.cell--body > div > div')) == 1
1102
            assert PyQuery(result).find(html_tag).text() == (
1103
                'Empty' if field_content == 'label' else 'Custom text'
1104
            )
1105

  
1106

  
1107
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1108
def test_card_cell_render_custom_schema_custom_entry(mock_send, context, app):
1109
    page = Page.objects.create(title='xxx', template_name='standard')
1110
    cell = WcsCardInfosCell.objects.create(
1111
        page=page,
1112
        placeholder='content',
1113
        order=0,
1114
        carddef_reference='default:card_model_1',
1115
        custom_schema={
1116
            'cells': [
1117
                {
1118
                    'varname': '@custom@',
1119
                    'template': "<b>Foo</b> bar'baz {{ card.fields.fielde }}",
1120
                    'display_mode': 'title',
1121
                },
1122
            ]
1123
        },
1124
    )
1125

  
1126
    context['card_model_1_id'] = 11
1127
    request = RequestFactory().get('/')
1128
    cell.modify_global_context(context, request)
1129
    cell.repeat_index = 0
1130
    context['synchronous'] = True  # to get fresh content
1131

  
1132
    result = cell.render(context)
1133
    assert '&lt;b&gt;Foo&lt;/b&gt;' in result
1134
    assert PyQuery(result).find('h3').text() == "<b>Foo</b> bar'baz lorem<strong>ipsum hello'world"
1135

  
1136
    # test context
1137
    cell.custom_schema['cells'][0][
1138
        'template'
1139
    ] = '{{ card.fields.fielda }} - {{ card.fields.related }} ({{ card.fields.related_structured.id }})'
1140
    cell.custom_schema['cells'][0]['display_mode'] = 'subtitle'
1141
    cell.save()
1142
    result = cell.render(context)
1143
    assert PyQuery(result).find('h4').text() == '<i>a</i> - Foo Bar (42)'
1144

  
1145
    # test display_mode & filters in template
1146
    cell.custom_schema = {
1147
        'cells': [
1148
            {'varname': '@custom@', 'template': 'Foo bar baz', 'display_mode': 'label'},
1149
            {
1150
                'varname': '@custom@',
1151
                'template': '{{ card.fields.related|split:" "|join:"," }}',
1152
                'display_mode': 'text',
1153
            },
1154
        ]
1155
    }
1156
    cell.save()
1157
    result = cell.render(context)
1158
    assert PyQuery(result).find('.label').text() == 'Foo bar baz'
1159
    assert PyQuery(result).find('.value').text() == 'Foo,Bar'
1160

  
1161
    # test available context
1162
    cell.card_ids = '11'
1163
    cell.custom_schema = {
1164
        'cells': [
1165
            {
1166
                'varname': '@custom@',
1167
                'template': 'Foo bar baz {% make_public_url url="http://127.0.0.1:8999/" %}',
1168
                'display_mode': 'label',
1169
            },
1170
        ]
1171
    }
1172
    cell.save()
1173
    resp = app.get(page.get_online_url())
1174
    assert len(resp.context['cells']) == 1
1175
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1176
    cell_url = reverse(
1177
        'combo-public-ajax-page-cell',
1178
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1179
    )
1180
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1181
    assert '/api/wcs/file/' in PyQuery(cell_resp.text).find('.label').text()
1182

  
1183
    cell.custom_schema = {
1184
        'cells': [
1185
            {'varname': '@custom@', 'template': 'Foo bar baz X{{ site_base }}Y', 'display_mode': 'label'},
1186
        ]
1187
    }
1188
    cell.save()
1189
    resp = app.get(page.get_online_url())
1190
    assert len(resp.context['cells']) == 1
1191
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1192
    cell_url = reverse(
1193
        'combo-public-ajax-page-cell',
1194
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1195
    )
1196
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1197
    assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz Xhttp://testserverY'
1198

  
1199
    cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
1200
    cell.custom_schema = {
1201
        'cells': [
1202
            {'varname': '@custom@', 'template': 'Foo bar baz X{{ repeat_index }}Y', 'display_mode': 'label'},
1203
        ]
1204
    }
1205
    cell.save()
1206
    resp = app.get(page.get_online_url())
1207
    assert len(resp.context['cells']) == 3
1208
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1209
    cell_url = reverse(
1210
        'combo-public-ajax-page-cell',
1211
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1212
    )
1213
    for i in range(0, 3):
1214
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
1215
        assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz X%sY' % i
1216

  
1217
    # custom schema but empty
1218
    cell.custom_schema = {'cells': []}
1219
    cell.save()
1220
    result = cell.render(context)
1221
    assert PyQuery(result).find('div.cell--body') == []
1222

  
1223

  
1224
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1225
def test_card_cell_render_custom_schema_link_entry(mock_send, context, app):
1226
    page = Page.objects.create(title='xxx', template_name='standard')
1227
    cell = WcsCardInfosCell.objects.create(
1228
        page=page,
1229
        placeholder='content',
1230
        order=0,
1231
        carddef_reference='default:card_model_1',
1232
        custom_schema={
1233
            'cells': [
1234
                {
1235
                    'varname': '@link@',
1236
                    'url_template': '/foo/bar/{{ card.fields.related_structured.id }}/',
1237
                    'template': '{{ card.fields.fielda }} - {{ card.fields.related }}',
1238
                    'display_mode': 'link',
1239
                },
1240
            ]
1241
        },
1242
    )
1243

  
1244
    context['card_model_1_id'] = 11
1245
    request = RequestFactory().get('/')
1246
    cell.modify_global_context(context, request)
1247
    cell.repeat_index = 0
1248
    context['synchronous'] = True  # to get fresh content
1249

  
1250
    result = cell.render(context)
1251
    assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
1252
    assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
1253
    assert PyQuery(result).find('.value a').attr['class'] is None
1254

  
1255
    cell.custom_schema['cells'][0]['display_mode'] = 'button'
1256
    cell.save()
1257
    result = cell.render(context)
1258
    assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
1259
    assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
1260
    assert PyQuery(result).find('.value a').attr['class'] == 'pk-button'
1261

  
1262
    cell.custom_schema['cells'][0][
1263
        'url_template'
1264
    ] = '{{ site_base }}/foo/bar/{{ card.fields.related_structured.id }}/'
1265
    cell.custom_schema['cells'][0]['template'] = '<b>{{ card.fields.fielda }}</b> - {{ card.fields.related }}'
1266
    cell.card_ids = '11'
1267
    cell.save()
1268
    resp = app.get(page.get_online_url())
1269
    assert len(resp.context['cells']) == 1
1270
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1271
    cell_url = reverse(
1272
        'combo-public-ajax-page-cell',
1273
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1274
    )
1275
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1276
    assert (
1277
        '<div class="value"><a href="http://testserver/foo/bar/42/" class="pk-button">&lt;b&gt;&lt;i&gt;a&lt;/i&gt;&lt;/b&gt; - Foo Bar</a></div>'
1278
        in cell_resp
1279
    )
1280

  
1281

  
1282
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1283
def test_card_cell_render_all_cards(mock_send, nocache, app):
1284
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
1285
    cell = WcsCardInfosCell.objects.create(
1286
        page=page,
1287
        placeholder='content',
1288
        order=0,
1289
        carddef_reference='default:card_model_1',
1290
        related_card_path='__all__',
1291
    )
1292

  
1293
    cell_url = reverse(
1294
        'combo-public-ajax-page-cell',
1295
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1296
    )
1297

  
1298
    # check url called
1299
    mock_send.reset_mock()
1300
    resp = app.get(page.get_online_url())
1301
    assert len(resp.context['cells']) == 3
1302
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1303
    for i in range(0, 3):
1304
        assert resp.context['cells'][i].pk == cell.pk
1305
        assert resp.context['cells'][i].repeat_index == i
1306
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
1307
        assert cell_resp.context['repeat_index'] == i
1308
    assert len(mock_send.call_args_list) == 7
1309
    # page rendering
1310
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
1311
    # cell rendering
1312
    for i in range(0, 3):
1313
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
1314
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
1315
        assert 'filter-internal-id' not in mock_send.call_args_list[i * 2 + 2][0][0].url
1316

  
1317

  
1318
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1319
def test_card_cell_render_identifier(mock_send, nocache, app):
1320
    page = Page.objects.create(
1321
        title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
1322
    )
1323
    cell = WcsCardInfosCell.objects.create(
1324
        page=page, placeholder='content', order=0, carddef_reference='default:card_model_1'
1325
    )
1326

  
1327
    cell_url = reverse(
1328
        'combo-public-ajax-page-cell',
1329
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
1330
    )
1331

  
1332
    # check url called
1333
    mock_send.reset_mock()
1334
    resp = app.get(page.get_online_url() + '11/')
1335
    assert len(resp.context['cells']) == 1
1336
    assert resp.context['cells'][0].pk == cell.pk
1337
    assert resp.context['cells'][0].repeat_index == 0
1338
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1339
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1340
    assert cell_resp.context['repeat_index'] == 0
1341
    assert 'Card Model 1' in cell_resp
1342
    assert '<p>Unknown Card</p>' not in cell_resp
1343
    assert len(mock_send.call_args_list) == 1
1344
    assert '/api/cards/card_model_1/11/' in mock_send.call_args_list[0][0][0].url
1345

  
1346
    # with identifiers
1347
    page.sub_slug = ''
1348
    page.save()
1349
    cell.card_ids = '42'
1350
    cell.save()
1351
    mock_send.reset_mock()
1352
    resp = app.get(page.get_online_url())
1353
    assert len(resp.context['cells']) == 1
1354
    assert resp.context['cells'][0].pk == cell.pk
1355
    assert resp.context['cells'][0].repeat_index == 0
1356
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1357
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1358
    assert cell_resp.context['repeat_index'] == 0
1359
    assert 'Card Model 1' in cell_resp
1360
    assert '<p>Unknown Card</p>' in cell_resp
1361
    assert len(mock_send.call_args_list) == 1
1362
    assert '/api/cards/card_model_1/42/' in mock_send.call_args_list[0][0][0].url
1363

  
1364
    cell.card_ids = '42, , 35'
1365
    cell.save()
1366
    mock_send.reset_mock()
1367
    resp = app.get(page.get_online_url())
1368
    assert len(resp.context['cells']) == 2
1369
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1370
    for i in range(0, 2):
1371
        assert resp.context['cells'][i].pk == cell.pk
1372
        assert resp.context['cells'][i].repeat_index == i
1373
        cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
1374
        assert cell_resp.context['repeat_index'] == i
1375
        assert 'Card Model 1' in cell_resp
1376
        assert '<p>Unknown Card</p>' in cell_resp
1377
    assert len(mock_send.call_args_list) == 2
1378
    for i in range(0, 2):
1379
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i][0][0].url
1380
        assert '&filter-internal-id=42&filter-internal-id=35&' in mock_send.call_args_list[i][0][0].url
1381

  
1382
    cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}'  # syntax error
1383
    cell.save()
1384
    mock_send.reset_mock()
1385
    resp = app.get(page.get_online_url())
1386
    assert len(resp.context['cells']) == 1
1387
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1388
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1389
    assert cell_resp.text.replace('\n', '') == ''  # empty-cell
1390

  
1391
    cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
1392
    cell.save()
1393
    mock_send.reset_mock()
1394
    resp = app.get(page.get_online_url())
1395
    assert len(resp.context['cells']) == 1
1396
    assert resp.context['cells'][0].pk == cell.pk
1397
    assert resp.context['cells'][0].repeat_index == 0
1398
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1399
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1400
    assert cell_resp.context['repeat_index'] == 0
1401
    assert len(mock_send.call_args_list) == 3
1402
    # page rendering
1403
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
1404
    # cell rendering
1405
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
1406
    assert '/api/cards/card_model_1/13' in mock_send.call_args_list[2][0][0].url
1407

  
1408
    def test_card_ids():
1409
        mock_send.reset_mock()
1410
        resp = app.get(page.get_online_url())
1411
        assert len(resp.context['cells']) == 3
1412
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1413
        for i in range(0, 3):
1414
            assert resp.context['cells'][i].pk == cell.pk
1415
            assert resp.context['cells'][i].repeat_index == i
1416
            cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
1417
            assert cell_resp.context['repeat_index'] == i
1418
        assert len(mock_send.call_args_list) == 7
1419
        # page rendering
1420
        assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
1421
        # cell rendering
1422
        card_ids = [c['id'] for c in WCS_CARDS_DATA['card_model_1']]
1423
        filters = '&%s&' % '&'.join('filter-internal-id=%s' % cid for cid in card_ids)
1424
        for i in range(0, 3):
1425
            assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
1426
            assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
1427
            assert filters in mock_send.call_args_list[i * 2 + 2][0][0].url
1428

  
1429
    for card_ids in [
1430
        '{% for card in cards|objects:"card_model_1" %}{{ card.id }},{% endfor %}',
1431
        '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}',
1432
    ]:
1433
        cell.card_ids = card_ids
1434
        cell.save()
1435
        test_card_ids()
1436

  
1437
        cell.card_ids = '{{ var1 }}'
1438
        cell.save()
1439
        page.extra_variables = {'var1': card_ids}
1440
        page.save()
1441
        test_card_ids()
1442
        page.extra_variables = {}
1443
        page.save()
1444

  
1445
    # with a card_ids template, but result is empty
1446
    cell.card_ids = '{{ foo }}'
1447
    cell.save()
1448
    resp = app.get(page.get_online_url())
1449
    assert len(resp.context['cells']) == 1
1450
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1451
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
1452
    assert cell_resp.text.replace('\n', '') == ''  # empty-cell
1453

  
1454

  
1455
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1456
def test_card_cell_render_identifier_from_related(mock_send, nocache, app):
1457
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
1458
    cell = WcsCardInfosCell.objects.create(
1459
        page=page,
1460
        placeholder='content',
1461
        order=0,
1462
        slug='sluga',
1463
        carddef_reference='default:card_a',
1464
        card_ids='1',
1465
    )
1466
    cell2 = WcsCardInfosCell.objects.create(
1467
        page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
1468
    )
1469

  
1470
    cell2_url = reverse(
1471
        'combo-public-ajax-page-cell',
1472
        kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
1473
    )
1474

  
1475
    def failing(urls):
1476
        resp = app.get(page.get_online_url())
1477
        assert len(resp.context['cells']) >= 2
1478
        for i in range(0, len(resp.context['cells']) - 1):
1479
            assert resp.context['cells'][i].pk == cell.pk
1480
        assert resp.context['cells'][-1].pk == cell2.pk
1481
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1482
        mock_send.reset_mock()
1483
        cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[-1])
1484
        assert cell_resp.text.replace('\n', '') == ''  # empty-cell
1485
        assert len(mock_send.call_args_list) == len(urls)
1486
        for j, url in enumerate(urls):
1487
            assert url in mock_send.call_args_list[j][0][0].url
1488

  
1489
    def single(urls):
1490
        resp = app.get(page.get_online_url())
1491
        assert len(resp.context['cells']) == 2
1492
        assert resp.context['cells'][0].pk == cell.pk
1493
        assert resp.context['cells'][1].pk == cell2.pk
1494
        assert resp.context['cells'][1].repeat_index == 0
1495
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1496
        mock_send.reset_mock()
1497
        cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[1])
1498
        assert cell_resp.context['repeat_index'] == 0
1499
        assert len(mock_send.call_args_list) == len(urls)
1500
        for j, url_parts in enumerate(urls):
1501
            if not isinstance(url_parts, tuple):
1502
                url_parts = (url_parts,)
1503
            for url_part in url_parts:
1504
                assert url_part in mock_send.call_args_list[j][0][0].url
1505

  
1506
    def multiple(urls):
1507
        resp = app.get(page.get_online_url())
1508
        assert len(resp.context['cells']) >= 2
1509
        assert resp.context['cells'][0].pk == cell.pk
1510
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1511
        for i in range(0, len(resp.context['cells']) - 1):
1512
            assert resp.context['cells'][i + 1].pk == cell2.pk
1513
            assert resp.context['cells'][i + 1].repeat_index == i
1514
            mock_send.reset_mock()
1515
            cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[i + 1])
1516
            assert cell_resp.context['repeat_index'] == i
1517
            assert len(mock_send.call_args_list) == len(urls)
1518
            for j, url_parts in enumerate(urls):
1519
                if not isinstance(url_parts, tuple):
1520
                    url_parts = (url_parts,)
1521
                for url_part in url_parts:
1522
                    assert url_part in mock_send.call_args_list[j][0][0].url
1523

  
1524
    # no cell with this slug
1525
    cell2.related_card_path = 'slugz/cardb'
1526
    cell2.save()
1527
    failing(urls=[])
1528

  
1529
    # another cell with the same slug
1530
    cell3 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
1531
    cell2.related_card_path = 'sluga/foo'
1532
    cell2.save()
1533
    failing(urls=[])
1534
    cell3.delete()
1535

  
1536
    # multiple ids configured on first cell
1537
    cell.card_ids = '{{ cards|objects:"card_a"|getlist:"id"|join:"," }}'
1538
    cell.save()
1539
    failing(
1540
        urls=[
1541
            # get first cell data
1542
            '/api/cards/card_a/list',
1543
        ]
1544
    )
1545

  
1546
    # related_card_path configured on first cell
1547
    cell.card_ids = '1'  # reset
1548
    cell.related_path = 'foobar'
1549
    cell.save()
1550
    failing(
1551
        urls=[
1552
            # get first cell data
1553
            '/api/cards/card_a/1/',
1554
        ]
1555
    )
1556

  
1557
    # reset
1558
    cell.related_path = ''
1559
    cell.save()
1560

  
1561
    # another cell as the same slug, but not a WcsCardInfosCell
1562
    cell3 = TextCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
1563

  
1564
    # direct and single relation (item)
1565
    cell2.related_card_path = 'sluga/cardb'
1566
    cell2.save()
1567
    single(
1568
        urls=[
1569
            # get first cell data
1570
            '/api/cards/card_a/1/',
1571
            # and follow cardb relation
1572
            '/api/cards/card_b/1/',  # check user access
1573
            '/api/cards/card_b/1/',  # get card
1574
        ]
1575
    )
1576
    cell3.delete()  # reset
1577

  
1578
    cell2.related_card_path = 'sluga/cardc/cardb'
1579
    cell2.save()
1580
    single(
1581
        urls=[
1582
            # get first cell data
1583
            '/api/cards/card_a/1/',
1584
            # get card_c schema
1585
            '/api/cards/card_c/@schema',
1586
            # follow cardc relation
1587
            '/api/cards/card_c/6/',
1588
            # and follow cardb relation
1589
            '/api/cards/card_b/7/',  # check user access
1590
            '/api/cards/card_b/7/',  # get card
1591
        ]
1592
    )
1593

  
1594
    # change cell ordering - cell with slug is after cell with related
1595
    cell.order = 42
1596
    cell.save()
1597
    # no error, but it does not work as expected: both cells has slug.
1598
    app.get(page.get_online_url(), status=200)
1599
    # remove slug of second cell
1600
    cell2.slug = ''
1601
    cell2.save()
1602
    urls = [
1603
        # get first cell data
1604
        '/api/cards/card_a/1/',
1605
        # get card_c schema
1606
        '/api/cards/card_c/@schema',
1607
        # follow cardc relation
1608
        '/api/cards/card_c/6/',
1609
        # and follow cardb relation
1610
        '/api/cards/card_b/7/',  # check user access
1611
        '/api/cards/card_b/7/',  # get card
1612
    ]
1613
    resp = app.get(page.get_online_url())
1614
    assert len(resp.context['cells']) == 2
1615
    assert resp.context['cells'][0].pk == cell2.pk
1616
    assert resp.context['cells'][0].repeat_index == 0
1617
    assert resp.context['cells'][1].pk == cell.pk
1618
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
1619
    mock_send.reset_mock()
1620
    cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[0])
1621
    assert cell_resp.context['repeat_index'] == 0
1622
    assert len(mock_send.call_args_list) == len(urls)
1623
    for j, url_parts in enumerate(urls):
1624
        if not isinstance(url_parts, tuple):
1625
            url_parts = (url_parts,)
1626
        for url_part in url_parts:
1627
            assert url_part in mock_send.call_args_list[j][0][0].url
1628

  
1629
    # reset
1630
    cell.order = 0  # reset
1631
    cell.save()
1632
    cell2.slug = 'slugb'
1633
    cell2.save()
1634

  
1635
    # test with custom_view
1636
    cell2.carddef_reference = 'default:card_b:a-custom-view'
1637
    cell2.save()
1638
    single(
1639
        urls=[
1640
            # get first cell data
1641
            '/api/cards/card_a/1/',
1642
            # get card_c schema
1643
            '/api/cards/card_c/@schema',
1644
            # follow cardc relation
1645
            '/api/cards/card_c/6/',
1646
            # and follow cardb relation
1647
            '/api/cards/card_b/a-custom-view/7/',  # check user access
1648
            '/api/cards/card_b/a-custom-view/7/',  # get card
1649
        ]
1650
    )
1651

  
1652
    # direct and multiple relation (items)
1653
    cell2.carddef_reference = 'default:card_b'  # reset
1654
    cell2.related_card_path = 'sluga/cardsb'
1655
    cell2.save()
1656
    multiple(
1657
        urls=[
1658
            # get first cell data
1659
            '/api/cards/card_a/1/',
1660
            # and follow cardb relation
1661
            ('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'),  # check user access
1662
            ('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'),  # get card
1663
        ]
1664
    )
1665

  
1666
    cell2.related_card_path = 'sluga/cardc/cardsb'
1667
    cell2.save()
1668
    multiple(
1669
        urls=[
1670
            # get first cell data
1671
            '/api/cards/card_a/1/',
1672
            # get card_c schema
1673
            '/api/cards/card_c/@schema',
1674
            # follow cardc relation
1675
            '/api/cards/card_c/6/',
1676
            # and follow cardb relation
1677
            ('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'),  # check user access
1678
            ('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'),  # get card
1679
        ]
1680
    )
1681

  
1682
    # direct and multiple relation through a block
1683
    cell2.related_card_path = 'sluga/blockb_cardb'
1684
    cell2.save()
1685
    multiple(
1686
        urls=[
1687
            # get first cell data
1688
            '/api/cards/card_a/1/',
1689
            # and follow cardb relation
1690
            ('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'),  # check user access
1691
            ('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'),  # get card
1692
        ]
1693
    )
1694

  
1695
    cell2.related_card_path = 'sluga/cardc/blockb_cardb'
1696
    cell2.save()
1697
    multiple(
1698
        urls=[
1699
            # get first cell data
1700
            '/api/cards/card_a/1/',
1701
            # get card_c schema
1702
            '/api/cards/card_c/@schema',
1703
            # follow cardc relation
1704
            '/api/cards/card_c/6/',
1705
            # and follow cardb relation
1706
            ('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'),  # check user access
1707
            ('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'),  # get card
1708
        ]
1709
    )
1710

  
1711
    # unknown part in related_card_path
1712
    cell2.related_card_path = 'sluga/foobar'
1713
    cell2.save()
1714
    failing(
1715
        urls=[
1716
            # get first cell data
1717
            '/api/cards/card_a/1/',
1718
        ]
1719
    )
1720
    cell2.related_card_path = 'sluga/cardc/foobar'
1721
    cell2.save()
1722
    failing(
1723
        urls=[
1724
            # get first cell data
1725
            '/api/cards/card_a/1/',
1726
            # get card_c schema
1727
            '/api/cards/card_c/@schema',
1728
            # follow cardc relation
1729
            '/api/cards/card_c/6/',
1730
        ]
1731
    )
1732

  
1733
    # card data not found
1734
    cell.card_ids = '42'
1735
    cell.save()
1736
    cell2.related_card_path = 'sluga/cardb'
1737
    cell2.save()
1738
    failing(
1739
        urls=[
1740
            # get first cell data
1741
            '/api/cards/card_a/42/',
1742
        ]
1743
    )
1744

  
1745
    cell.card_ids = '2'
1746
    cell.save()
1747
    cell2.related_card_path = 'sluga/cardc/cardb'
1748
    cell2.save()
1749
    failing(
1750
        urls=[
1751
            # get first cell data
1752
            '/api/cards/card_a/2/',
1753
            # get card_c schema
1754
            '/api/cards/card_c/@schema',
1755
            # follow cardc relation
1756
            '/api/cards/card_c/61/',
1757
        ]
1758
    )
1759
    # reset
1760
    cell.card_ids = '1'
1761
    cell.save()
1762

  
1763
    # last part has not the correct card slug
1764
    cell2.related_card_path = 'sluga/cardc'
1765
    cell2.save()
1766
    failing(
1767
        urls=[
1768
            # get first cell data
1769
            '/api/cards/card_a/1/',
1770
        ]
1771
    )
1772

  
1773
    # unknown schema
1774
    cell2.related_card_path = 'sluga/cardz/cardb'
1775
    cell2.save()
1776
    failing(
1777
        urls=[
1778
            # get first cell data
1779
            '/api/cards/card_a/1/',
1780
            # get card_z schema
1781
            '/api/cards/card_z/@schema',
1782
        ]
1783
    )
1784

  
1785
    # multiple relation of multiple relation
1786
    cell2.related_card_path = 'sluga/cardsb/reverse:cardb'
1787
    cell2.save()
1788
    failing(
1789
        urls=[
1790
            # get first cell data
1791
            '/api/cards/card_a/1/',
1792
        ]
1793
    )
1794

  
1795
    # field not found
1796
    cell.card_ids = '3'
1797
    cell.save()
1798
    cell2.related_card_path = 'sluga/cardb'
1799
    cell2.save()
1800
    failing(
1801
        urls=[
1802
            # get first cell data
1803
            '/api/cards/card_a/3/',
1804
        ]
1805
    )
1806
    cell2.related_card_path = 'sluga/cardc/cardb'
1807
    cell2.save()
1808
    failing(
1809
        urls=[
1810
            # get first cell data
1811
            '/api/cards/card_a/3/',
1812
        ]
1813
    )
1814

  
1815
    # field empty
1816
    cell.card_ids = '4'
1817
    cell.save()
1818
    cell2.related_card_path = 'sluga/cardb'
1819
    cell2.save()
1820
    failing(
1821
        urls=[
1822
            # get first cell data
1823
            '/api/cards/card_a/4/',
1824
        ]
1825
    )
1826

  
1827
    # field not found in block
1828
    cell.card_ids = '3'
1829
    cell.save()
1830
    cell2.related_card_path = 'sluga/blockb_cardb'
1831
    cell2.save()
1832
    failing(
1833
        urls=[
1834
            # get first cell data
1835
            '/api/cards/card_a/3/',
1836
        ]
1837
    )
1838

  
1839
    # field empty in block
1840
    cell.card_ids = '4'
1841
    cell.save()
1842
    cell2.related_card_path = 'sluga/blockb_cardb'
1843
    cell2.save()
1844
    failing(
1845
        urls=[
1846
            # get first cell data
1847
            '/api/cards/card_a/4/',
1848
        ]
1849
    )
1850

  
1851
    # reverse relation of item
1852
    cell.carddef_reference = 'default:card_b'
1853
    cell.slug = 'slugb'
1854
    cell.card_ids = '1'
1855
    cell.related_card_path = ''
1856
    cell.save()
1857
    cell2.carddef_reference = 'default:card_a'
1858
    cell2.slug = 'sluga'
1859
    cell2.card_ids = ''
1860
    cell2.related_card_path = 'slugb/reverse:cardb'
1861
    cell2.save()
1862
    multiple(
1863
        urls=[
1864
            # get first cell data
1865
            '/api/cards/card_b/1/',
1866
            # get list of card_a with cardb=1
1867
            '/api/cards/card_a/list?orig=combo&filter-cardb=1',
1868
            # and follow carda reverse relation
1869
            # check user access
1870
            (
1871
                '/api/cards/card_a/list',
1872
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1873
            ),
1874
            # get card
1875
            (
1876
                '/api/cards/card_a/list',
1877
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1878
            ),
1879
        ]
1880
    )
1881

  
1882
    # reverse relation of items
1883
    cell2.related_card_path = 'slugb/reverse:cardsb'
1884
    cell2.save()
1885
    multiple(
1886
        urls=[
1887
            # get first cell data
1888
            '/api/cards/card_b/1/',
1889
            # get list of card_a with cardsb=1
1890
            '/api/cards/card_a/list?orig=combo&filter-cardsb=1',
1891
            # and follow carda reverse relation
1892
            # check user access
1893
            (
1894
                '/api/cards/card_a/list',
1895
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1896
            ),
1897
            # get card
1898
            (
1899
                '/api/cards/card_a/list',
1900
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1901
            ),
1902
        ]
1903
    )
1904

  
1905
    # reverse relation of item through a block
1906
    cell2.related_card_path = 'slugb/reverse:blockb_cardb'
1907
    cell2.save()
1908
    multiple(
1909
        urls=[
1910
            # get first cell data
1911
            '/api/cards/card_b/1/',
1912
            # get list of card_a with cardsb=1
1913
            '/api/cards/card_a/list?orig=combo&filter-blockb_cardb=1',
1914
            # and follow carda reverse relation
1915
            # check user access
1916
            (
1917
                '/api/cards/card_a/list',
1918
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1919
            ),
1920
            # get card
1921
            (
1922
                '/api/cards/card_a/list',
1923
                '&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
1924
            ),
1925
        ]
1926
    )
1927

  
1928
    # unknown part in related_card_path
1929
    cell2.related_card_path = 'slugb/foobar'
1930
    cell2.save()
1931
    failing(
1932
        urls=[
1933
            # get first cell data
1934
            '/api/cards/card_b/1/',
1935
        ]
1936
    )
1937

  
1938
    # multiple relation of multiple relation
1939
    cell2.related_card_path = 'slugb/reverse:cardb/cardsb'
1940
    cell2.save()
1941
    failing(
1942
        urls=[
1943
            # get first cell data
1944
            '/api/cards/card_b/1/',
1945
        ]
1946
    )
1947

  
1948
    # reverse relation with many models using the same varname
1949
    cell.carddef_reference = 'default:card_h'
1950
    cell.slug = 'slugh'
1951
    cell.card_ids = '42'
1952
    cell.related_card_path = ''
1953
    cell.save()
1954
    cell2.carddef_reference = 'default:card_f'
1955
    cell2.slug = 'slugf'
1956
    cell2.card_ids = ''
1957
    cell2.related_card_path = 'slugh/reverse:cardh'
1958
    cell2.save()
1959
    multiple(
1960
        urls=[
1961
            # get first cell data
1962
            '/api/cards/card_h/42/',
1963
            # get list of card_f with cardf=42
1964
            '/api/cards/card_f/list?orig=combo&filter-cardh=42',
1965
            # and follow cardf reverse relation
1966
            '/api/cards/card_f/41/',  # check user access
1967
            '/api/cards/card_f/41/',  # get card
1968
        ]
1969
    )
1970

  
1971
    cell.card_ids = '44'
1972
    cell.related_card_path = ''
1973
    cell.save()
1974
    cell2.carddef_reference = 'default:card_g'
1975
    cell2.slug = 'slugg'
1976
    cell2.card_ids = ''
1977
    cell2.related_card_path = 'slugh/reverse:cardh'
1978
    cell2.save()
1979
    multiple(
1980
        urls=[
1981
            # get first cell data
1982
            '/api/cards/card_h/44/',
1983
            # get list of card_g with cardf=44
1984
            '/api/cards/card_g/list?orig=combo&filter-cardh=44',
1985
            # and follow cardf reverse relation
1986
            '/api/cards/card_g/43/',  # check user access
1987
            '/api/cards/card_g/43/',  # get card
1988
        ]
1989
    )
1990

  
1991

  
1992
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
1993
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1994
def test_card_cell_only_for_user(mock_send, context, carddef_reference):
1995
    page = Page.objects.create(title='xxx', template_name='standard')
1996
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
1997
    cell.carddef_reference = carddef_reference
1998
    cell.only_for_user = False
1999
    cell.save()
2000

  
2001
    context['card_model_1_id'] = 11
2002
    request = RequestFactory().get('/')
2003
    cell.modify_global_context(context, request)
2004
    cell.repeat_index = 0
2005

  
2006
    assert cell.is_visible(request=context['request']) is True
2007
    context['request'].user = MockUserWithNameId()
2008
    assert cell.is_visible(request=context['request']) is True
2009

  
2010
    cell.only_for_user = True
2011
    cell.save()
2012
    context['request'].user = None
2013
    assert cell.is_visible(request=context['request']) is False
2014
    context['request'].user = MockUserWithNameId()
2015
    assert cell.is_visible(request=context['request']) is True
2016

  
2017
    cache.clear()
2018
    context['synchronous'] = True  # to get fresh content
2019
    context['request'].user = None
2020

  
2021
    mock_send.reset_mock()
2022
    cell.render(context)
2023
    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
2024

  
2025
    context['request'].user = MockUser()
2026
    mock_send.reset_mock()
2027
    cell.render(context)
2028
    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
2029

  
2030
    context['request'].user = MockUserWithNameId()
2031
    mock_send.reset_mock()
2032
    cell.render(context)
2033
    assert 'filter-user-uuid=xyz' in mock_send.call_args_list[0][0][0].url
2034

  
2035

  
2036
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
2037
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
2038
def test_card_cell_render_user(mock_send, context, nocache, carddef_reference):
2039
    page = Page.objects.create(title='xxx', template_name='standard')
2040
    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
2041
    cell.carddef_reference = carddef_reference
2042
    cell.save()
2043

  
2044
    context['card_model_1_id'] = 11
2045
    request = RequestFactory().get('/')
2046
    cell.modify_global_context(context, request)
2047
    cell.repeat_index = 0
2048
    context['synchronous'] = True  # to get fresh content
2049

  
2050
    assert context['request'].user is None
2051
    mock_send.reset_mock()
2052
    cell.render(context)
2053
    assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
2054
    assert 'email=&' in mock_send.call_args_list[0][0][0].url
2055

  
2056
    context['request'].user = AnonymousUser()
2057
    mock_send.reset_mock()
2058
    cell.render(context)
2059
    assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
2060
    assert 'email=&' in mock_send.call_args_list[0][0][0].url
2061

  
2062
    context['request'].user = MockUser()
2063
    mock_send.reset_mock()
2064
    cell.render(context)
2065
    assert 'email=foo%40example.net' in mock_send.call_args_list[0][0][0].url
2066

  
2067
    context['request'].user = MockUserWithNameId()
2068
    mock_send.reset_mock()
2069
    cell.render(context)
2070
    assert 'NameID=xyz' in mock_send.call_args_list[0][0][0].url
2071

  
2072
    cell.without_user = True
2073
    cell.save()
2074

  
2075
    context['request'].user = None
2076
    mock_send.reset_mock()
2077
    cell.render(context)
2078
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
2079
    assert 'email' not in mock_send.call_args_list[0][0][0].url
2080

  
2081
    context['request'].user = MockUser()
2082
    mock_send.reset_mock()
2083
    cell.render(context)
2084
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
2085
    assert 'email' not in mock_send.call_args_list[0][0][0].url
2086

  
2087
    context['request'].user = MockUserWithNameId()
2088
    mock_send.reset_mock()
2089
    cell.render(context)
2090
    assert 'NameID' not in mock_send.call_args_list[0][0][0].url
2091
    assert 'email' not in mock_send.call_args_list[0][0][0].url
tests/wcs/utils.py
1
import copy
2
import json
3
import re
4
import urllib.parse
5
from unittest import mock
6

  
7
WCS_FORMDEFS_DATA = [
8
    {'slug': 'a-private-form', 'title': 'a private form', 'url': '/a-private-form/'},
9
    {'slug': 'a-second-form-title', 'title': 'a second form title', 'url': '/a-second-form-title/'},
10
    {'slug': 'form-title', 'title': 'form title', 'url': '/form-title/', 'keywords': ['foo', 'bar']},
11
    {'slug': 'third-form-title', 'title': 'Third form title', 'url': '/third-form-title/'},
12
]
13

  
14
WCS_CATEGORIES_DATA = [
15
    {'slug': 'test-%s' % i, 'title': 'Test %s' % i, 'url': '/test-%s/' % i} for i in [3, 9]
16
]
17

  
18
WCS_CATEGORIES_FORMDEFS_DATA = [
19
    {
20
        'slug': 'form-title',
21
        'title': 'form title',
22
        'url': '/form-title/',
23
        'keywords': ['foo', 'bar'],
24
        'count': 42,
25
    },
26
    {
27
        'slug': 'a-second-form-title',
28
        'title': 'a second form title',
29
        'url': '/a-second-form-title/',
30
        'count': 35,
31
    },
32
]
33

  
34
WCS_USER_FORMS_DATA = [
35
    {
36
        'name': 'name',
37
        'title': 'Title',
38
        'url': '/form/1/',
39
        'form_receipt_datetime': '2015-01-01T00:00:00',
40
        'readable': True,
41
        'category_slug': 'test-9',
42
    },
43
    {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True},
44
    {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
45
]
46

  
47
WCS_FORMS_DATA = [
48
    {
49
        'form_receipt_datetime': '2019-10-17T16:46:03',
50
        'form_url': '/foobar/1',
51
        'form_url_backoffice': '/backoffice/management/foobar/1/',
52
    },
53
    {
54
        'form_receipt_datetime': '2019-10-17T16:46:04',
55
        'form_url': '/foobar/2',
56
        'form_url_backoffice': '/backoffice/management/foobar/2/',
57
    },
58
]
59

  
60
WCS_USER_DRAFTS_DATA = [
61
    {
62
        'name': 'name',
63
        'title': 'Title',
64
        'url': '/form/1/',
65
        'form_receipt_datetime': '2015-01-01T00:00:00',
66
        'category_slug': 'test-9',
67
    },
68
    {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
69
    {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
70
    {
71
        'name': 'name',
72
        'title': 'Title',
73
        'url': '/form/4/',
74
        'form_receipt_datetime': '2015-01-01T00:00:00',
75
        'form_status_is_endpoint': True,
76
        'category_slug': 'test-9',
77
    },
78
]
79

  
80
WCS_CARDDEFS_DATA = [
81
    {'title': 'Card Model 1', 'slug': 'card_model_1', 'custom_views': [{'id': 'foo', 'text': 'bar'}]},
82
    {'title': 'Card Model 2', 'slug': 'card_model_2'},
83
    {'title': 'Card Model 3', 'slug': 'card_model_3'},
84
    {'title': 'Card A', 'slug': 'card_a'},
85
    {'title': 'Card B', 'slug': 'card_b', 'custom_views': [{'id': 'a-custom-view', 'text': 'foo bar'}]},
86
    {'title': 'Card C', 'slug': 'card_c'},
87
    {'title': 'Card D', 'slug': 'card_d'},
88
    {'title': 'Card E', 'slug': 'card_e'},
89
]
90

  
91
WCS_CARDS_DATA = {
92
    'card_model_1': [
93
        {
94
            'id': 11,
95
            'display_id': '10-11',
96
            'display_name': 'Card Model 1 - n°10-11',
97
            'digest': 'a a a',
98
            'text': 'aa',
99
            'url': '/backoffice/data/card_model_1/11/',
100
            'fields': {
101
                'fielda': '<i>a</i>',
102
                'fieldb': True,
103
                'fieldc': '2020-09-28',
104
                'fieldd': {'filename': 'file.pdf', 'url': 'http://127.0.0.1:8999/download?f=42'},
105
                'fielde': "lorem<strong>ipsum\n\nhello'world",
106
                'fieldf': 'lorem<strong>ipsum\n\nhello world',
107
                'fieldg': 'test@localhost',
108
                'fieldh': 'https://www.example.net/',
109
                'related': 'Foo Bar',
110
                'related_raw': 42,
111
                'related_structured': {'id': 42, 'text': 'blah'},
112
            },
113
        },
114
        {
115
            'id': 12,
116
            'display_id': '10-12',
117
            'display_name': 'Card Model 1 - n°10-12',
118
            'digest': 'b b b',
119
            'text': 'bb',
120
            'url': '/backoffice/data/card_model_1/12/',
121
        },
122
        {
123
            'id': 13,
124
            'display_id': '10-13',
125
            'display_name': 'Card Model 1 - n°10-13',
126
            'digest': 'c c c',
127
            'text': 'cc',
128
            'url': '/backoffice/data/card_model_1/13/',
129
        },
130
    ],
131
    'card_a': [
132
        {
133
            'id': 1,
134
            'fields': {
135
                'cardb_raw': 1,
136
                'cardsb_raw': [2, 3],
137
                'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
138
                'cardc_raw': 6,
139
                'cardz_raw': 42,
140
            },
141
        },
142
        {
143
            'id': 2,
144
            'fields': {
145
                'cardb_raw': 1,
146
                'cardsb_raw': [2, 3],
147
                'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
148
                'cardc_raw': 61,  # unknown card_c
149
            },
150
        },
151
        {
152
            'id': 3,
153
            'fields': {
154
                # some missing fields
155
                'blockb_raw': [{}],
156
            },
157
        },
158
        {
159
            'id': 4,
160
            'fields': {
161
                # some empty fields
162
                'cardb_raw': None,
163
                'cardsb_raw': None,
164
                'blockb_raw': [{'cardb_raw': None}],
165
                'cardc_raw': 7,
166
            },
167
        },
168
    ],
169
    'card_b': [{'id': i, 'fields': []} for i in range(1, 12) if i != 6],
170
    'card_c': [
171
        {
172
            'id': 6,
173
            'fields': {
174
                'cardb_raw': 7,
175
                'cardsb_raw': [8, 9],
176
                'blockb_raw': [{'cardb_raw': 10}, {'cardb_raw': 11}],
177
            },
178
        },
179
        {
180
            'id': 7,
181
            'fields': {},
182
        },
183
    ],
184
    'card_f': [
185
        {'id': 41, 'fields': {'cardh_raw': 42}},
186
    ],
187
    'card_g': [
188
        {'id': 43, 'fields': {'cardh_raw': 44}},
189
    ],
190
    'card_h': [
191
        {'id': 42, 'fields': {}},
192
        {'id': 44, 'fields': {}},
193
    ],
194
}
195

  
196
WCS_CARDS_CUSTOM_VIEW_DATA = [
197
    {
198
        'id': 11,
199
        'display_id': '10-11',
200
        'display_name': 'Card Model 1 - n°10-11',
201
        'digest': 'a a a',
202
        'text': 'aa',
203
        'url': '/backoffice/data/card_model_1/11/',
204
    },
205
    {
206
        'id': 12,
207
        'display_id': '10-12',
208
        'display_name': 'Card Model 1 - n°10-12',
209
        'digest': 'b b b',
210
        'text': 'bb',
211
        'url': '/backoffice/data/card_model_1/12/',
212
    },
213
]
214

  
215
WCS_CARDDEF_SCHEMAS = {
216
    'card_model_1': {
217
        'name': 'Card Model 1',
218
        'fields': [
219
            {'label': 'Field A', 'varname': 'fielda', 'type': 'string'},
220
            {'label': 'Field B', 'varname': 'fieldb', 'type': 'bool'},
221
            {'label': 'Field C', 'varname': 'fieldc', 'type': 'date'},
222
            {'label': 'Field D', 'varname': 'fieldd', 'type': 'file'},
223
            {'label': 'Field E', 'varname': 'fielde', 'type': 'text'},
224
            {'label': 'Field F', 'varname': 'fieldf', 'type': 'text', 'pre': True},
225
            {'label': 'Field G', 'varname': 'fieldg', 'type': 'email'},
226
            {'label': 'Field H', 'varname': 'fieldh', 'type': 'string'},
227
            {'label': 'Empty', 'varname': 'empty', 'type': 'string'},
228
            {'label': 'Related', 'varname': 'related', 'type': 'item'},
229
            {'label': 'Page', 'type': 'page'},
230
            {'label': 'Comment', 'type': 'comment'},
231
            {'label': 'Title', 'type': 'title'},
232
            {'label': 'Subtitle', 'type': 'subtitle'},
233
            {'label': 'Empty', 'varname': None, 'type': 'string'},
234
        ],
235
    },
236
    'card_a': {
237
        'name': 'Card A',
238
        'fields': [
239
            {'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
240
            {'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
241
            {'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
242
            {'label': 'Card C', 'varname': 'cardc', 'type': 'item'},
243
        ],
244
        'relations': [
245
            {'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
246
            {'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
247
            {'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
248
            {'obj': 'carddef:card_c', 'varname': 'cardc', 'type': 'item', 'reverse': False},
249
            {
250
                'obj': 'carddef:card_z',  # unknown card model
251
                'varname': 'cardz',
252
                'type': 'item',
253
                'reverse': False,
254
            },
255
        ],
256
    },
257
    'card_b': {
258
        'name': 'Card B',
259
        'fields': [],
260
        'relations': [
261
            {'obj': 'carddef:card_a', 'varname': 'cardb', 'type': 'item', 'reverse': True},
262
            {'obj': 'carddef:card_a', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
263
            {'obj': 'carddef:card_a', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
264
            {'obj': 'carddef:card_c', 'varname': 'cardb', 'type': 'item', 'reverse': True},
265
            {'obj': 'carddef:card_c', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
266
            {'obj': 'carddef:card_c', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
267
        ],
268
    },
269
    'card_c': {
270
        'name': 'Card C',
271
        'fields': [
272
            {'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
273
            {'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
274
            {'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
275
        ],
276
        'relations': [
277
            {'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
278
            {'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
279
            {'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
280
            {'obj': 'carddef:card_a', 'varname': 'cardc', 'type': 'item', 'reverse': True},
281
        ],
282
    },
283
    'card_d': {
284
        'name': 'Card D',
285
        'fields': [
286
            {'label': 'Card D', 'varname': 'cardd-foo', 'type': 'item'},
287
            {'label': 'Card E', 'varname': 'carde-foo', 'type': 'item'},
288
        ],
289
        'relations': [
290
            {'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': False},
291
            {'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': True},
292
            {'obj': 'carddef:card_e', 'varname': 'carde-foo', 'type': 'item', 'reverse': False},
293
        ],
294
    },
295
    'card_e': {
296
        'name': 'Card E',
297
        'fields': [
298
            {'label': 'Card D', 'varname': 'cardd-bar', 'type': 'item'},
299
        ],
300
        'relations': [
301
            {'obj': 'carddef:card_d', 'varname': 'cardd-bar', 'type': 'item', 'reverse': False},
302
            {'obj': 'carddef:card_d', 'varname': 'carde-foo', 'type': 'item', 'reverse': True},
303
        ],
304
    },
305
    'card_f': {
306
        'name': 'Card F',
307
        'fields': [
308
            {'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
309
        ],
310
        'relations': [
311
            {'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
312
        ],
313
    },
314
    'card_g': {
315
        'name': 'Card G',
316
        'fields': [
317
            {'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
318
        ],
319
        'relations': [
320
            {'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
321
        ],
322
    },
323
    'card_h': {
324
        'name': 'Card H',
325
        'fields': [],
326
        'relations': [
327
            {'obj': 'carddef:card_f', 'varname': 'cardh', 'type': 'item', 'reverse': True},
328
            {'obj': 'carddef:card_g', 'varname': 'cardh', 'type': 'item', 'reverse': True},
329
        ],
330
    },
331
}
332

  
333

  
334
class MockUser:
335
    email = 'foo@example.net'
336
    is_authenticated = True
337
    is_anonymous = False
338

  
339
    def get_name_id(self):
340
        return None
341

  
342

  
343
class MockUserWithNameId:
344
    email = 'foo@example.net'
345
    is_authenticated = True
346
    is_anonymous = False
347

  
348
    def get_name_id(self):
349
        return 'xyz'
350

  
351

  
352
class MockedRequestResponse(mock.Mock):
353
    status_code = 200
354

  
355
    def json(self):
356
        return json.loads(self.content)
357

  
358

  
359
def get_data_from_url(url):
360
    if '/api/formdefs/' in url:
361
        return WCS_FORMDEFS_DATA
362
    if '/api/categories/' in url:
363
        if '/formdefs/' in url:
364
            return WCS_CATEGORIES_FORMDEFS_DATA
365
        return WCS_CATEGORIES_DATA
366
    if '/api/user/forms' in url:
367
        return WCS_USER_FORMS_DATA
368
    if '/api/forms' in url:
369
        return WCS_FORMS_DATA
370
    if '/api/user/drafts' in url:
371
        return WCS_USER_DRAFTS_DATA
372
    if '/api/cards/@list' in url:
373
        return WCS_CARDDEFS_DATA
374
    m_schema = re.match(r'/api/cards/([a-z0-9_]+)/@schema', url)
375
    if m_schema:
376
        return WCS_CARDDEF_SCHEMAS.get(m_schema.group(1)) or {}
377
    m_card = re.match(r'/api/cards/([a-z0-9_]+)/(\d+)/', url)
378
    if m_card:
379
        try:
380
            return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(2))][0]
381
        except IndexError:
382
            return {}
383
    m_card = re.match(r'/api/cards/([a-z0-9_]+)/([a-z0-9_]+)/(\d+)/', url)  # model/custom-view/id
384
    if m_card:
385
        try:
386
            return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(3))][0]
387
        except IndexError:
388
            return {}
389
    if 'api/cards/card_model_1/list/foo' in url:
390
        return WCS_CARDS_CUSTOM_VIEW_DATA
391
    m_list = re.match(r'/api/cards/([a-z0-9_]+)/list', url)
392
    if m_list:
393
        return WCS_CARDS_DATA.get(m_list.group(1)) or []
394
    return []
395

  
396

  
397
def mocked_requests_send(request, **kwargs):
398
    request_url = urllib.parse.urlparse(request.url)
399
    data = copy.deepcopy(get_data_from_url(request_url.path))
400

  
401
    if not isinstance(data, list):
402
        return MockedRequestResponse(content=json.dumps(data))
403

  
404
    for elem in data:
405
        for key in ['url', 'form_url', 'form_url_backoffice']:
406
            if key not in elem:
407
                continue
408
            elem_url = elem[key]
409
            elem[key] = '{scheme}://{netloc}{url}'.format(
410
                scheme=request_url.scheme, netloc=request_url.netloc, url=elem_url
411
            )
412

  
413
    return MockedRequestResponse(content=json.dumps({'data': data}))
0
-