combo/tests/wcs/test_card.py

3462 lines
127 KiB
Python

import json
import re
import sys
from io import StringIO
from unittest import mock
import pytest
from django.apps import apps
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.core.management import call_command
from django.test.client import RequestFactory
from django.urls import reverse
from pyquery import PyQuery
from requests.exceptions import ConnectionError
from requests.models import Response
from combo.apps.wcs.forms import WcsCardCellDisplayForm
from combo.apps.wcs.models import WcsCardCell
from combo.data.models import Page, PageSnapshot, TextCell, ValidityInfo
from combo.data.utils import import_site
from tests.test_manager import login
from tests.utils import manager_submit_cell
from .utils import WCS_CARDS_DATA, MockedRequestResponse, MockUser, MockUserWithNameId, mocked_requests_send
pytestmark = pytest.mark.django_db
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_setup(mock_send, app, admin_user):
page = Page.objects.create(
title='xxx', slug='test_card_cell_save_cache', template_name='standard', sub_slug='foobar'
)
cell = WcsCardCell(page=page, placeholder='content', order=0)
form_class = cell.get_default_form_class()
form = form_class(instance=cell)
assert form.fields['carddef_reference'].widget.choices == [
('default:card_model_1', 'test : Card Model 1'),
('default:card_model_1:foo', 'test : Card Model 1 - bar'),
('default:card_model_2', 'test : Card Model 2'),
('default:card_model_3', 'test : Card Model 3'),
('default:card_a', 'test : Card A'),
('default:card_b', 'test : Card B'),
('default:card_b:a-custom-view', 'test : Card B - foo bar'),
('default:card_c', 'test : Card C'),
('default:card_d', 'test : Card D'),
('default:card_e', 'test : Card E'),
('other:card_model_1', 'test2 : Card Model 1'),
('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
('other:card_model_2', 'test2 : Card Model 2'),
('other:card_model_3', 'test2 : Card Model 3'),
('other:card_a', 'test2 : Card A'),
('other:card_b', 'test2 : Card B'),
('other:card_b:a-custom-view', 'test2 : Card B - foo bar'),
('other:card_c', 'test2 : Card C'),
('other:card_d', 'test2 : Card D'),
('other:card_e', 'test2 : Card E'),
]
form_display = WcsCardCellDisplayForm(instance=cell)
assert 'customize_display' not in form_display.fields
assert 'custom_schema' not in form_display.fields
cell.save()
assert 'customize_display' not in form_display.fields
assert 'custom_schema' not in form_display.fields
cell.carddef_reference = 'default:card_model_1'
cell.save()
form_display = WcsCardCellDisplayForm(instance=cell)
assert 'customize_display' in form_display.fields
assert 'custom_schema' in form_display.fields
assert 'customize_display' not in form_display.initial
assert form_display.initial['custom_schema'] == {}
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
form_display = WcsCardCellDisplayForm(instance=cell)
assert 'customize_display' in form_display.fields
assert 'custom_schema' in form_display.fields
assert 'customize_display' not in form_display.initial
assert form_display.initial['custom_schema'] == {}
cell.carddef_reference = 'default:card_model_1'
cell.save()
cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
cell.save()
form_display = WcsCardCellDisplayForm(instance=cell)
assert 'customize_display' in form_display.fields
assert 'custom_schema' in form_display.fields
assert form_display.initial['customize_display'] is True
assert form_display.initial['custom_schema'] == {
'grid_class': 'fx-grid--auto',
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
],
}
WcsCardCell.objects.all().delete()
# check adding a cell from the UI
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
cell_add_url = [x for x in resp.html.find_all('option') if x.text == 'Card(s)'][0].get('data-add-url')
resp = app.get(cell_add_url).follow()
cell = WcsCardCell.objects.all().first()
manager_submit_cell(resp.forms[0]) # will save card model
cell.refresh_from_db()
# check getting back to uncustomized display reset the schema
cell.custom_schema = {
'grid_class': 'fx-grid--auto',
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
],
}
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-customize_display' % cell.get_reference()].value == 'on'
resp.forms[0]['c%s-customize_display' % cell.get_reference()].value = False
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.custom_schema == {}
cell.custom_schema = {
'grid_class': 'fx-grid--auto',
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
],
}
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-display_mode' % cell.get_reference()].value == 'card'
resp.forms[0]['c%s-display_mode' % cell.get_reference()].value = 'table'
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.custom_schema == {
'grid_class': 'fx-grid--auto',
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
],
}
assert cell.related_card_path == '__all__'
assert cell.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '__all__'
resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value = '--'
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.related_card_path == ''
assert cell.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value = ''
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.related_card_path == ''
assert cell.card_ids == '42'
# current page has a sub_slug, '--' option is present
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
# current_page has no sub_slug, but parent page has one
parent_page = Page.objects.create(
title='parent', slug='parent', template_name='standard', sub_slug='foobar'
)
page.parent = parent_page
page.sub_slug = ''
page.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
# no sub_slug
parent_page.sub_slug = ''
parent_page.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' not in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == ''
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = ''
resp = resp.forms[0].submit()
assert resp.context['form'].errors == {'card_ids': ['This field is required.']}
# check custom_title
for title_type in ['auto', 'empty']:
cell.custom_title = 'foo bar'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
resp.forms[0]['c%s-title_type' % cell.get_reference()].value = title_type
resp = resp.forms[0].submit()
cell.refresh_from_db()
assert cell.custom_title == ''
def test_card_cell_custom_schema_migration():
cell = WcsCardCell(display_mode='table')
cell.custom_schema = {'cells': [{'varname': 'some-field', 'empty_value': '@empty@'}]}
assert cell.get_custom_schema() == {
'grid_headers': False,
'cells': [
{
'varname': 'some-field',
'empty_value': '',
}
],
}
cell.custom_schema = {
'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
}
assert cell.get_custom_schema() == {
'grid_headers': False,
'cells': [
{
'varname': 'some-field',
'display_mode': 'label',
'cell_size': 'foobar',
}
],
}
cell.display_mode = 'card'
cell.custom_schema = {
'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{
'varname': 'some-field',
'field_content': 'label',
'display_mode': 'text',
'empty_value': '@empty@',
'cell_size': 'foobar',
}
],
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'value'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{
'varname': 'some-field',
'field_content': 'value',
'display_mode': 'text',
'empty_value': '@empty@',
}
],
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'label-and-value'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{
'varname': 'some-field',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@empty@',
}
],
}
cell.custom_schema = {'cells': [{'varname': 'some-field'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{
'varname': 'some-field',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@empty@',
}
],
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'title'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{
'varname': 'some-field',
'field_content': 'value',
'display_mode': 'title',
'empty_value': '@empty@',
}
],
}
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
]
}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [
{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
],
}
cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'value'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'text'}],
}
cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]}
assert cell.get_custom_schema() == {
'grid_class': 'fx-grid--auto',
'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}],
}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_save_cache(mock_send):
page = Page.objects.create(title='xxx', slug='test_card_cell_save_cache', template_name='standard')
cell = WcsCardCell(page=page, placeholder='content', order=0)
assert cell.get_additional_label() is None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert cell.cached_title == 'Card Model 1'
assert cell.cached_json != {}
assert cell.get_additional_label() == 'Card Model 1'
# make sure cached attributes are removed from serialized pages
assert 'cached_' not in json.dumps(page.get_serialized_page())
# artificially change title and json
WcsCardCell.objects.filter(pk=cell.pk).update(cached_title='XXX', cached_json={})
assert WcsCardCell.objects.get(pk=cell.pk).cached_title == 'XXX'
assert WcsCardCell.objects.get(pk=cell.pk).cached_json == {}
# run update db cache
appconfig = apps.get_app_config('wcs')
appconfig.update_db_cache()
assert WcsCardCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1'
assert WcsCardCell.objects.get(pk=cell.pk).cached_json != {}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_validity(mock_send):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_defined'
assert validity_info.invalid_since is not None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve carddefs, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.json = lambda *a, **k: {'err': 1, 'err_class': 'Page not found'}
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.carddef_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_check_validity(mock_send):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_a',
related_card_path='',
card_ids='1',
)
cell2 = WcsCardCell.objects.create(
page=page, placeholder='content', order=1, carddef_reference='default:card_b'
)
# no related_card_path
cell2.check_validity()
assert ValidityInfo.objects.exists() is False
# correct related_card_path but sluga is not defined
cell2.related_card_path = 'sluga/cardb'
cell2.save()
cell2.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
assert validity_info.invalid_since is not None
# sluga is now defined
cell.slug = 'sluga'
cell.save()
cell2.check_validity()
assert ValidityInfo.objects.exists() is False
# bad related_card_path
cell2.related_card_path = 'sluga/foobar'
cell2.save()
cell2.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_card_cell(mock_send, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
related_card_path='',
)
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
assert 'application/json' not in resp
cell.carddef_reference = 'default:card_model_1'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '<script id="cell-%s-card-schema-default:card_model_1" type="application/json">' % cell.pk in resp
assert ('data-cell-reference="%s"' % cell.get_reference()) in resp.text
assert cell.without_user is False
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value == 'on'
resp.forms[0]['c%s-with_user' % cell.get_reference()].value = False
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.without_user is True
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value is None
# card with relations
cell.carddef_reference = 'default:card_a'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# but only one cell on the page, no relations to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# all cards
cell.related_card_path = '__all__'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', True, 'All cards'),
('--', False, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# add a second cell, related to the first card model
cell.related_card_path = ''
cell.save()
cell2 = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=1,
carddef_reference='default:card_b',
related_card_path='',
)
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# no cell with id and slug
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# set a slug on first cell
cell.slug = 'sluga'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluga/cardb', False, 'Linked card: "Card B"'),
('sluga/cardsb', False, 'Linked cards: "Cards B"'),
('sluga/blockb_cardb', False, 'Linked card: "Block B - Card B"'),
('sluga/cardc/cardb', False, 'Linked card: "Card C" -> "Card B"'),
('sluga/cardc/cardsb', False, 'Linked cards: "Card C" -> "Cards B"'),
('sluga/cardc/blockb_cardb', False, 'Linked card: "Card C" -> "Block B - Card B"'),
('', False, 'Template'),
]
# set a list of ids on first cell
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', False, 'Card whose identifier is in the URL'),
('', True, 'Template'),
]
# can not user cell with multiple ids as reference
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# define a slug on second cell
cell.card_ids = ''
cell.save()
cell2.slug = 'slugb'
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# multiple relations to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('slugb/reverse:cardb', False, 'Linked cards: "Card B" (reverse relation)'),
('slugb/reverse:cardsb', False, 'Linked cards: "Cards B" (reverse relation)'),
('slugb/reverse:blockb_cardb', False, 'Linked cards: "Block B - Card B" (reverse relation)'),
('', False, 'Template'),
]
# still multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluga/cardb', False, 'Linked card: "Card B"'),
('sluga/cardsb', False, 'Linked cards: "Cards B"'),
('sluga/blockb_cardb', False, 'Linked card: "Block B - Card B"'),
('sluga/cardc/cardb', False, 'Linked card: "Card C" -> "Card B"'),
('sluga/cardc/cardsb', False, 'Linked cards: "Card C" -> "Cards B"'),
('sluga/cardc/blockb_cardb', False, 'Linked card: "Card C" -> "Block B - Card B"'),
('', False, 'Template'),
]
# set a related_path on cell2
resp.forms[1]['c%s-related_card_path' % cell2.get_reference()] = 'sluga/cardb'
resp.forms[1]['c%s-card_ids' % cell2.get_reference()] = 'foobar'
resp = resp.forms[1].submit()
cell2.refresh_from_db()
assert cell2.related_card_path == 'sluga/cardb'
assert cell2.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
# no more relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('', False, 'Template'),
]
# still multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', False, 'Card whose identifier is in the URL'),
('sluga/cardb', True, 'Linked card: "Card B"'),
('sluga/cardsb', False, 'Linked cards: "Cards B"'),
('sluga/blockb_cardb', False, 'Linked card: "Block B - Card B"'),
('sluga/cardc/cardb', False, 'Linked card: "Card C" -> "Card B"'),
('sluga/cardc/cardsb', False, 'Linked cards: "Card C" -> "Cards B"'),
('sluga/cardc/blockb_cardb', False, 'Linked card: "Card C" -> "Block B - Card B"'),
('', False, 'Template'),
]
resp.forms[1].submit()
cell2.refresh_from_db()
assert cell2.related_card_path == 'sluga/cardb'
assert cell2.card_ids == ''
# check circular relations
cell.slug = 'sluge'
cell.carddef_reference = 'default:card_e'
cell.save()
cell2.carddef_reference = 'default:card_d'
cell2.slug = 'slugd'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('slugd/cardd-foo/carde-foo', False, 'Linked card: "Card D" -> "Card E"'),
('slugd/carde-foo', False, 'Linked card: "Card E"'),
('', False, 'Template'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluge/cardd-bar', False, 'Linked card: "Card D"'),
('sluge/reverse:carde-foo', False, 'Linked cards: "Card E" (reverse relation)'),
('', False, 'Template'),
]
cell.slug = 'slugd'
cell.carddef_reference = 'default:card_d'
cell.save()
cell2.carddef_reference = 'default:card_d'
cell2.slug = 'slugd-bis'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('slugd-bis/cardd-foo', False, 'Linked card: "Card D"'),
('slugd-bis/reverse:cardd-foo', False, 'Linked cards: "Card D" (reverse relation)'),
('slugd-bis/carde-foo/cardd-bar', False, 'Linked card: "Card E" -> "Card D"'),
(
'slugd-bis/carde-foo/reverse:carde-foo',
False,
'Linked cards: "Card E" -> "Card E" (reverse relation)',
),
('', False, 'Template'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('slugd/cardd-foo', False, 'Linked card: "Card D"'),
('slugd/reverse:cardd-foo', False, 'Linked cards: "Card D" (reverse relation)'),
('slugd/carde-foo/cardd-bar', False, 'Linked card: "Card E" -> "Card D"'),
('slugd/carde-foo/reverse:carde-foo', False, 'Linked cards: "Card E" -> "Card E" (reverse relation)'),
('', False, 'Template'),
]
cell.slug = 'sluge'
cell.carddef_reference = 'default:card_e'
cell.save()
cell2.carddef_reference = 'default:card_e'
cell2.slug = 'sluge-bis'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluge-bis/cardd-bar/carde-foo', False, 'Linked card: "Card D" -> "Card E"'),
('', False, 'Template'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluge/cardd-bar/carde-foo', False, 'Linked card: "Card D" -> "Card E"'),
('', False, 'Template'),
]
# many cells with slug
WcsCardCell.objects.create(
page=page,
placeholder='content',
order=2,
carddef_reference='default:card_e',
slug="sluge-again",
card_ids="42",
related_card_path='',
)
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluge-bis/cardd-bar/carde-foo', False, 'Linked card (From cell sluge-bis): "Card D" -> "Card E"'),
(
'sluge-again/cardd-bar/carde-foo',
False,
'Linked card (From cell sluge-again): "Card D" -> "Card E"',
),
('', False, 'Template'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('__all__', False, 'All cards'),
('--', True, 'Card whose identifier is in the URL'),
('sluge/cardd-bar/carde-foo', False, 'Linked card (From cell sluge): "Card D" -> "Card E"'),
(
'sluge-again/cardd-bar/carde-foo',
False,
'Linked card (From cell sluge-again): "Card D" -> "Card E"',
),
('', False, 'Template'),
]
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_card_cell_tabs(mock_send, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
cell = WcsCardCell.objects.create(page=page, placeholder='content', order=0)
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
assert not resp.pyquery('[data-tab-slug="general"] select[name$="title_type"]')
assert not resp.pyquery('[data-tab-slug="general"] input[name$="custom_title"]')
assert not resp.pyquery('[data-tab-slug="general"] input[name$="limit"]')
assert not resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
assert resp.pyquery('[data-tab-slug="appearance"] select[name$="title_type"]')
assert resp.pyquery('[data-tab-slug="appearance"] input[name$="custom_title"]')
assert not resp.pyquery('[data-tab-slug="appearance"] input[name$="customize_display"]')
assert resp.pyquery('[data-tab-slug="display"] input[name$="limit"]')
cell.carddef_reference = 'default:card_model_1'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
assert resp.pyquery('[data-tab-slug="display"] input[name$="customize_display"]')
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_load(mock_send):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
cell = WcsCardCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
site_export = [page.get_serialized_page()]
cell.delete()
assert not Page.objects.get(pk=page.pk).get_cells()
Page.load_serialized_pages(site_export)
page = Page.objects.get(slug='test_cards')
cells = page.get_cells()
assert len(cells) == 1
cell = cells[0]
assert cell.cached_title == 'Card Model 1'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
related_card_path='',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
context['synchronous'] = True # to get fresh content
cell.modify_global_context(context, request)
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
assert 'cards-card_model_1' in result
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/11/"><span class="card-title">aa</span></a>'
in result
)
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/12/"><span class="card-title">bb</span></a>'
in result
)
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/13/"><span class="card-title">cc</span></a>'
in result
)
assert 'data-paginate-by="10"' in result
# create a page with the correct subslug
page = Page.objects.create(slug='foo', title='Foo', sub_slug='(?P<card_model_1_id>[a-z0-9]+)')
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
assert '<a href="/foo/11/"><span class="card-title">aa</span></a>' in result
assert '<a href="/foo/12/"><span class="card-title">bb</span></a>' in result
assert '<a href="/foo/13/"><span class="card-title">cc</span></a>' in result
cell.carddef_reference = 'default:card_model_1:foo'
cell.limit = 42
cell.save()
page.sub_slug = 'card_model_1_id'
page.save()
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
assert '<a href="/foo/11/"><span class="card-title">aa</span></a>' in result
assert '<a href="/foo/12/"><span class="card-title">bb</span></a>' in result
assert '<a href="/foo/13/"><span class="card-title">cc</span></a>' not in result
assert 'data-paginate-by="42"' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps({'data': []}))
cell.render(context)
assert len(requests_get.call_args_list) == 1
assert (
requests_get.call_args_list[0][0][0]
== '/api/cards/card_model_1/list/foo?include-fields=on&include-submission=on&include-workflow=on&filter-internal-id=11'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
cell.carddef_reference = 'default:card_model_1'
cell.save()
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps({'data': []}))
cell.render(context)
assert len(requests_get.call_args_list) == 1
assert (
requests_get.call_args_list[0][0][0]
== '/api/cards/card_model_1/list?include-fields=on&include-submission=on&include-workflow=on&filter-internal-id=11'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_custom_schema_card_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={'cells': [{'varname': 'fielda'}]},
display_mode='table',
related_card_path='__all__',
)
request = RequestFactory().get('/')
context['synchronous'] = True # to get fresh content
cell.modify_global_context(context, request)
# only one cell, render as ul/li
result = cell.render(context)
assert PyQuery(result).find('table tr td') == []
assert len(PyQuery(result).find('ul li')) == 3
assert [PyQuery(li).text() for li in PyQuery(result).find('ul li')[:1]] == ['<i>a</i>']
# more than one cell, render as table
cell.custom_schema['cells'] += [
{'varname': 'fieldb'},
]
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li') == []
assert len(PyQuery(result).find('table tr td')) == 2 * 3
assert [PyQuery(td).text() for td in PyQuery(result).find('table tr td')[:2]] == ['<i>a</i>', 'yes']
cell.custom_schema['cells'] += [
{'varname': 'fieldc'},
{'varname': 'related'},
{'varname': 'fieldd'},
{'varname': 'fielde'},
{'varname': 'fieldf'},
{'varname': 'fieldg'},
{'varname': 'fieldh'},
{'varname': 'fieldi'},
{'varname': 'unknown'},
{'varname': 'user:name'},
{'varname': 'user:email'},
{'varname': 'user:first_name'},
{'varname': 'user:last_name'},
{'varname': 'user:unknown'},
{}, # missing varname
]
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li') == []
assert len(PyQuery(result).find('table tr td')) == 14 * 3
assert [PyQuery(td).text() for td in PyQuery(result).find('table tr:first-child td')] == [
'<i>a</i>',
'yes',
'Sept. 28, 2020',
'Foo Bar',
'file.pdf',
"lorem<strong>ipsum hello'world", # no multiline support for now
"lorem<strong>ipsum hello world",
'test@localhost',
'https://www.example.net/',
"loremipsum\nhello'world",
'User Foo Bar',
'foo@bar.com',
'User',
'Foo Bar',
]
assert PyQuery(result).find('table tr:first-child td:nth-child(8) a').text().strip() == 'test@localhost'
assert (
PyQuery(result).find('table tr:first-child td:nth-child(8) a').attr['href'] == 'mailto:test@localhost'
)
assert (
PyQuery(result).find('table tr:first-child td:nth-child(9) a').text().strip()
== 'https://www.example.net/'
)
assert (
PyQuery(result).find('table tr:first-child td:nth-child(9) a').attr['href']
== 'https://www.example.net/'
)
assert PyQuery(result).find('table tr:first-child td:nth-child(10) p:first-child').text() == 'loremipsum'
assert (
PyQuery(result).find('table tr:first-child td:nth-child(10) p:first-child strong').text() == 'ipsum'
)
assert PyQuery(result).find('table tr:first-child td:nth-child(10) p:last-child').text() == "hello'world"
assert PyQuery(result).find('table tr:first-child td:nth-child(12) a').text().strip() == 'foo@bar.com'
assert (
PyQuery(result).find('table tr:first-child td:nth-child(12) a').attr['href'] == 'mailto:foo@bar.com'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
@pytest.mark.parametrize('nb_cells', [1, 2])
def test_card_cell_table_mode_render_custom_schema_card_empty_field(mock_send, context, nb_cells):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={'cells': [{'varname': 'empty', 'empty_value': ''}]},
display_mode='table',
related_card_path='__all__',
)
if nb_cells > 1:
cell.custom_schema['cells'] += [
{'varname': 'fieldb'},
]
cell.save()
request = RequestFactory().get('/')
context['synchronous'] = True # to get fresh content
cell.modify_global_context(context, request)
def test(value):
result = cell.render(context)
if nb_cells > 1:
assert PyQuery(result).find('ul li') == []
assert PyQuery(result).find('table tr:first-child td:first-child').text() == value
else:
assert PyQuery(result).find('table tr td') == []
assert PyQuery(result).find('ul li:first-child').text() == value
return result
test('')
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'empty_value': 'Custom text',
}
cell.save()
test('Custom text')
cell.custom_schema['cells'][0] = {
'varname': 'empty_email',
'empty_value': '',
}
cell.save()
result = test('')
assert PyQuery(result).find('table tr:first-child td:first-child a') == []
assert PyQuery(result).find('ul li:first-child a') == []
cell.custom_schema['cells'][0] = {
'varname': 'empty_email',
'empty_value': 'Custom text',
}
cell.save()
result = test('Custom text')
assert PyQuery(result).find('table tr:first-child td:first-child a') == []
assert PyQuery(result).find('ul li:first-child a') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
@pytest.mark.parametrize('nb_cells', [1, 2])
def test_card_cell_table_mode_render_custom_schema_custom_entry(mock_send, context, nb_cells):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{'varname': '@custom@', 'template': "<b>Foo</b> bar'baz {{ card.fields.fielde }}"},
]
},
display_mode='table',
related_card_path='__all__',
)
if nb_cells > 1:
cell.custom_schema['cells'] += [
{'varname': 'fieldb'},
]
cell.save()
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
context['synchronous'] = True # to get fresh content
def test(value):
result = cell.render(context)
if nb_cells > 1:
assert PyQuery(result).find('ul li') == []
assert PyQuery(result).find('table tr:first-child td:first-child').text() == value
else:
assert PyQuery(result).find('table tr td') == []
assert PyQuery(result).find('ul li:first-child').text() == value
test("<b>Foo</b> bar'baz lorem<strong>ipsum hello'world")
# test context
cell.custom_schema['cells'][0][
'template'
] = '{{ card.fields.fielda }} - {{ card.fields.related }} ({{ card.fields.related_structured.id }})'
cell.save()
test('<i>a</i> - Foo Bar (42)')
# test filters in template
cell.custom_schema['cells'][0]['template'] = '{{ card.fields.related|split:" "|join:"," }}'
cell.save()
test('Foo,Bar')
# test available context
cell.custom_schema['cells'][0][
'template'
] = 'Foo bar baz {% make_public_url url="http://127.0.0.1:8999/" %}'
cell.save()
result = cell.render(context)
if nb_cells > 1:
assert '/api/wcs/file/' in PyQuery(result).find('table tr:first-child td:first-child').text()
else:
assert '/api/wcs/file/' in PyQuery(result).find('ul li:first-child').text()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
@pytest.mark.parametrize('nb_cells', [1, 2])
def test_card_cell_table_mode_render_custom_schema_link_entry(mock_send, context, nb_cells):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@link@',
'url_template': '/foo/bar/{{ card.fields.related_structured.id }}/',
'template': '{{ card.fields.fielda }} - {{ card.fields.related }}',
'display_mode': 'link',
},
]
},
display_mode='table',
related_card_path='__all__',
)
if nb_cells > 1:
cell.custom_schema['cells'] += [
{'varname': 'fieldb'},
]
cell.save()
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
context['synchronous'] = True # to get fresh content
def test(value, href, class_name, is_file=False):
result = cell.render(context)
if nb_cells > 1:
assert PyQuery(result).find('ul li') == []
assert PyQuery(result).find('table tr:first-child td:first-child a').text() == value
if not is_file:
assert PyQuery(result).find('table tr:first-child td:first-child a').attr['href'] == href
else:
assert (
PyQuery(result)
.find('table tr:first-child td:first-child a')
.attr['href']
.startswith(href)
)
assert PyQuery(result).find('table tr:first-child td:first-child a').attr['class'] == class_name
else:
assert PyQuery(result).find('table tr td') == []
assert PyQuery(result).find('ul li:first-child a').text() == value
if not is_file:
assert PyQuery(result).find('ul li:first-child a').attr['href'] == href
else:
assert PyQuery(result).find('ul li:first-child a').attr['href'].startswith(href)
assert PyQuery(result).find('ul li:first-child a').attr['class'] == class_name
test('<i>a</i> - Foo Bar', '/foo/bar/42/', None)
cell.custom_schema['cells'][0]['display_mode'] = 'button'
cell.save()
test('<i>a</i> - Foo Bar', '/foo/bar/42/', 'pk-button')
# empty label or empty url: no link in output
cell.custom_schema['cells'][0]['url_template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
cell.custom_schema['cells'][0]['url_template'] = 'foo/bar'
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
# check with page link
root_page = Page.objects.create(title='Root', slug='root', template_name='standard')
page1 = Page.objects.create(
title='Card',
slug='card',
template_name='standard',
sub_slug='card_model_1_id',
parent=root_page,
)
other_root_page = Page.objects.create(title='Other root', slug='other-root', template_name='standard')
page2 = Page.objects.create(
title='Card (bis)',
slug='card-bis',
template_name='standard',
sub_slug='card_model_1_id',
parent=other_root_page,
)
cell.custom_schema['cells'][0]['url_template'] = ''
cell.custom_schema['cells'][0]['page'] = page1.pk
cell.custom_schema['cells'][0]['template'] = '{{ card.fields.fielda }} - {{ card.fields.related }}'
cell.save()
test('<i>a</i> - Foo Bar', '/root/card/11/', 'pk-button')
cell.custom_schema['cells'][0]['page'] = page2.pk
cell.save()
test('<i>a</i> - Foo Bar', '/other-root/card-bis/11/', 'pk-button')
# empty label or empty url: no link in output
cell.custom_schema['cells'][0]['page'] = 0
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
cell.custom_schema['cells'][0]['page'] = page1.pk
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
# check with field
cell.custom_schema['cells'][0]['page'] = ''
cell.custom_schema['cells'][0]['link_field'] = 'fieldd'
cell.custom_schema['cells'][0]['template'] = '{{ card.fields.fielda }} - {{ card.fields.related }}'
cell.save()
test('<i>a</i> - Foo Bar', '/api/wcs/file/', 'pk-button', is_file=True)
cell.custom_schema['cells'][0]['display_mode'] = 'link'
cell.save()
test('<i>a</i> - Foo Bar', '/api/wcs/file/', None, is_file=True)
# empty label or no value/no file field/unknown field: no link in output
result = cell.render(context)
assert PyQuery(result).find('ul li:last-child a') == []
assert PyQuery(result).find('table tr:last-child td a') == []
cell.custom_schema['cells'][0]['link_field'] = 'fielda'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
cell.custom_schema['cells'][0]['link_field'] = 'unknown'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
cell.custom_schema['cells'][0]['link_field'] = 'fieldd'
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('ul li a') == []
assert PyQuery(result).find('table tr td a') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
@pytest.mark.parametrize('with_headers', [True, False])
def test_card_cell_table_mode_render_with_headers(mock_send, context, with_headers):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'grid_headers': with_headers,
'cells': [
{'varname': '@custom@', 'template': "foo bar"},
{'varname': '@custom@', 'template': "foo bar bis", "header": "My Custom Header"},
{'varname': '@custom@', 'template': ""}, # not displayed
{'varname': 'fieldb'},
{'varname': 'user:name'},
{'varname': 'user:email'},
{'varname': 'user:first_name'},
{'varname': 'user:last_name'},
{'varname': '@link@', 'template': "Foo", 'url_template': 'http://foo/bar', 'header': 'Link'},
{'varname': '@link@', 'template': "Bar", 'url_template': '{# empty #}', 'header': 'Link Bis'},
{
'varname': '@link@',
'template': "",
'url_template': 'http://foo/bar',
'header': 'Link Not Displayed',
},
{
'varname': '@link@',
'template': "Bar",
'url_template': '',
'header': 'Link Bis Not Displayed',
},
{'varname': 'user:unknown'},
],
},
display_mode='table',
related_card_path='__all__',
)
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
if with_headers:
assert len(PyQuery(result).find('table thead th')) == 9
assert PyQuery(result).find('table thead th:nth-child(1)').text() == ''
assert PyQuery(result).find('table thead th:nth-child(2)').text() == 'My Custom Header'
assert PyQuery(result).find('table thead th:nth-child(3)').text() == 'Field B'
assert PyQuery(result).find('table thead th:nth-child(4)').text() == 'Name'
assert PyQuery(result).find('table thead th:nth-child(5)').text() == 'Email'
assert PyQuery(result).find('table thead th:nth-child(6)').text() == 'First name'
assert PyQuery(result).find('table thead th:nth-child(7)').text() == 'Last name'
assert PyQuery(result).find('table thead th:nth-child(8)').text() == 'Link'
assert PyQuery(result).find('table thead th:nth-child(9)').text() == 'Link Bis'
else:
assert PyQuery(result).find('table thead') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_all_cards(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
related_card_path='__all__',
)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
# check url called
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
app.get(cell_url + '?ctx=' + extra_ctx[0])
assert len(mock_send.call_args_list) == 1
# cell rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_identifier(mock_send, nocache, app):
page = Page.objects.create(
title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
)
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
related_card_path='',
)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
# check url called
mock_send.reset_mock()
resp = app.get(page.get_online_url() + '11/')
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
assert '&filter-internal-id=11&' in mock_send.call_args_list[0][0][0].url
# with identifiers
page.sub_slug = ''
page.save()
cell.card_ids = '42'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
assert '&filter-internal-id=42&' in mock_send.call_args_list[0][0][0].url
cell.card_ids = '42, , 35'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
assert '&filter-internal-id=42&filter-internal-id=35&' in mock_send.call_args_list[0][0][0].url
cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}' # syntax error
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert 'empty-message' in cell_resp
cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert len(mock_send.call_args_list) == 2
# cell rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
assert '&filter-internal-id=13&' in mock_send.call_args_list[1][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
slug='sluga',
carddef_reference='default:card_a',
card_ids='1',
related_card_path='',
)
cell2 = WcsCardCell.objects.create(
page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
)
cell2_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
)
# just do a simple test to check url calls
def check(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
app.get(cell2_url + '?ctx=' + extra_ctx[1])
assert len(mock_send.call_args_list) == len(urls)
for j, url_parts in enumerate(urls):
if not isinstance(url_parts, tuple):
url_parts = (url_parts,)
for url_part in url_parts:
assert url_part in mock_send.call_args_list[j][0][0].url
# direct and single relation (item)
cell2.related_card_path = 'sluga/cardb'
cell2.save()
urls = [
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
'/api/cards/card_b/1/', # get card
]
check(urls)
# direct and multiple relation (items)
cell2.carddef_reference = 'default:card_b' # reset
cell2.related_card_path = 'sluga/cardsb'
cell2.save()
urls = [
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'), # get cards
]
check(urls)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_title(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
title_type='auto',
)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
context.pop('title')
cell.title_type = 'empty'
cell.save()
result = cell.render(context)
assert '<h2>' not in result
cell.title_type = 'manual'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
context.pop('title')
cell.custom_title = 'Foo bar !'
cell.save()
result = cell.render(context)
assert '<h2>Foo bar !</h2>' in result
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='card',
title_type='manual',
custom_title='Foo bar {{ card.fields.title }}',
related_card_path='',
)
# carddef_reference is not defined
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert '<h2>Card Model 1</h2>' not in result
assert '<p>Unknown Card</p>' in result
# card id not in context
cell.carddef_reference = 'default:card_model_1'
cell.save()
del context['card_model_1_id']
assert 'card_model_1_id' not in context
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
context.pop('title')
cell.title_type = 'auto'
cell.save()
mock_send.reset_mock()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result
assert PyQuery(result).find('.label:contains("Field A") + .value').text() == '<i>a</i>'
assert PyQuery(result).find('.label:contains("Field B") + .value').text() == 'yes'
assert PyQuery(result).find('.label:contains("Field C") + .value').text() == 'Sept. 28, 2020'
assert PyQuery(result).find('.label:contains("Related") + .value').text() == 'Foo Bar'
assert 'related_raw' not in result
assert 'related_structured' not in result
assert PyQuery(result).find('.label:contains("Field D") + .value a').text() == 'file.pdf'
context.pop('title')
cell.title_type = 'manual'
cell.custom_title = '<b>Foo bar {{ card.fields.fielda }}</b>'
cell.save()
assert cell.get_additional_label() == '&lt;b&gt;Foo bar {{ card.fields.fielda }}&lt;/b&gt;'
result = cell.render(context)
assert '<h2>&lt;b&gt;Foo bar &lt;i&gt;a&lt;/i&gt;&lt;/b&gt;</h2>' in result
context.pop('title')
cell.custom_title = '{{ foobar }}'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result # empty value from template, default value
context.pop('title')
cell.custom_title = '{% if %}'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result # template error, default value
context.pop('title')
cell.title_type = 'empty'
cell.save()
result = cell.render(context)
assert '<h2>' not in result
# test available context
cell.title_type = 'manual'
cell.custom_title = 'X{{ site_base }}Y'
cell.card_ids = '11'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert '<h2>Xhttp://testserverY</h2>' in cell_resp
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.title_type = 'manual'
cell.custom_title = 'Foo bar X{{ repeat_index }}Y'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 3):
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert '<h2>Foo bar X%sY</h2>' % i in cell_resp
# again, without ajax: urls are already in cache
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
for i in range(0, 3):
assert '<h2>Foo bar X%sY</h2>' % i in resp
assert 'data-paginate-by="10"' in resp
cell.limit = 42
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
for i in range(0, 3):
assert '<h2>Foo bar X%sY</h2>' % i in resp
assert 'data-paginate-by="42"' in resp
# using custom view
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
result = cell.render(context)
assert 'Foo bar X0Y' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
result = cell.render(context)
# nothing, hide cell
assert not result.strip()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_text_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='card',
carddef_reference='default:card_model_1',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
# field E is split in paragraphs
assert (
PyQuery(result).find('.label:contains("Field E") + .value p:first-child').text().strip()
== 'lorem<strong>ipsum'
)
assert (
PyQuery(result).find('.label:contains("Field E") + .value p:last-child').text().strip()
== "hello'world"
)
# field F is put in a <pre>
assert (
PyQuery(result).find('.label:contains("Field F") + .value pre').text()
== 'lorem<strong>ipsum hello world'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_email_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='card',
carddef_reference='default:card_model_1',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.label:contains("Field G") + .value a').text() == 'test@localhost'
assert (
PyQuery(result).find('.label:contains("Field G") + .value a').attr['href'] == 'mailto:test@localhost'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_string_with_url_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='card',
carddef_reference='default:card_model_1',
custom_title='Foo bar {{ card.fields.title }}',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.label:contains("Field H") + .value a').text() == 'https://www.example.net/'
assert (
PyQuery(result).find('.label:contains("Field H") + .value a').attr['href']
== 'https://www.example.net/'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_custom_schema_card_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={'cells': [{'varname': 'fielda', 'field_content': 'value', 'display_mode': 'title'}]},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('h3').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'value',
'display_mode': 'subtitle',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'title'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h3').text() == 'Field A'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'label',
'display_mode': 'subtitle',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == 'Field A'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'text'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field A'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'value', 'display_mode': 'text'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field A'
assert PyQuery(result).find('.value').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fieldb',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field B'
assert PyQuery(result).find('.value').text() == 'yes'
cell.custom_schema['cells'][0] = {
'varname': 'fieldc',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field C'
assert PyQuery(result).find('.value').text() == 'Sept. 28, 2020'
cell.custom_schema['cells'][0] = {
'varname': 'related',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Related'
assert PyQuery(result).find('.value').text() == 'Foo Bar'
cell.custom_schema['cells'][0] = {
'varname': 'fieldd',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field D'
assert PyQuery(result).find('.value').text() == 'file.pdf'
cell.custom_schema['cells'][0] = {
'varname': 'fielde',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
# check multiline text field is rendered with multiple paragraphs
# (first line "lorem<strong>ipsum" and last line ("hello'world")
# and the content is kept properly escaped.
assert PyQuery(result).find('.label').text() == 'Field E'
assert PyQuery(result).find('.value p:first-child').text().strip() == 'lorem<strong>ipsum'
assert PyQuery(result).find('.value p:last-child').text().strip() == "hello'world"
cell.custom_schema['cells'][0] = {
'varname': 'fieldf',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field F'
assert PyQuery(result).find('.value pre').text() == 'lorem<strong>ipsum hello world'
cell.custom_schema['cells'][0] = {
'varname': 'fieldi',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field I'
assert PyQuery(result).find('.value p:first-child').text() == 'loremipsum'
assert PyQuery(result).find('.value p:first-child strong').text() == 'ipsum'
assert PyQuery(result).find('.value p:last-child').text() == "hello'world"
cell.custom_schema['cells'][0] = {
'varname': 'fieldi',
'field_content': 'value',
'display_mode': 'title',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h3').text() == "loremipsumhello'world"
assert PyQuery(result).find('h3 p') == [] # content was stripped
cell.custom_schema['cells'][0] = {
'varname': 'fieldg',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field G'
assert PyQuery(result).find('.value a').text() == 'test@localhost'
assert PyQuery(result).find('.value a').attr['href'] == 'mailto:test@localhost'
cell.custom_schema['cells'][0] = {
'varname': 'fieldh',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field H'
assert PyQuery(result).find('.value a').text() == 'https://www.example.net/'
assert PyQuery(result).find('.value a').attr['href'] == 'https://www.example.net/'
# wrong configuration, missing varname
cell.custom_schema['cells'][0] = {
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label') == []
assert PyQuery(result).find('.value') == []
# user fields
cell.custom_schema['cells'] = [
{
'varname': 'user:name',
'field_content': 'label-and-value',
'display_mode': 'text',
},
{
'varname': 'user:email',
'field_content': 'label-and-value',
'display_mode': 'text',
},
{
'varname': 'user:first_name',
'field_content': 'label-and-value',
'display_mode': 'text',
},
{
'varname': 'user:last_name',
'field_content': 'label-and-value',
'display_mode': 'text',
},
{
'varname': 'user:unknown',
'field_content': 'label-and-value',
'display_mode': 'text',
},
]
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 4
assert PyQuery(result).find('.cell--body > div > div:nth-child(1) .label').text() == 'Name'
assert PyQuery(result).find('.cell--body > div > div:nth-child(1) .value').text() == 'User Foo Bar'
assert PyQuery(result).find('.cell--body > div > div:nth-child(2) .label').text() == 'Email'
assert PyQuery(result).find('.cell--body > div > div:nth-child(2) .value a').text() == 'foo@bar.com'
assert (
PyQuery(result).find('.cell--body > div > div:nth-child(2) .value a').attr['href']
== 'mailto:foo@bar.com'
)
assert PyQuery(result).find('.cell--body > div > div:nth-child(3) .label').text() == 'First name'
assert PyQuery(result).find('.cell--body > div > div:nth-child(3) .value').text() == 'User'
assert PyQuery(result).find('.cell--body > div > div:nth-child(4) .label').text() == 'Last name'
assert PyQuery(result).find('.cell--body > div > div:nth-child(4) .value').text() == 'Foo Bar'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_custom_schema_card_empty_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@skip@',
}
]
},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 0
assert PyQuery(result).find('.label') == []
assert PyQuery(result).find('.value') == []
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@empty@',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 1
assert PyQuery(result).find('.label').text() == 'Empty'
assert PyQuery(result).find('.value').text() == ''
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': 'Custom text',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 1
assert PyQuery(result).find('.label').text() == 'Empty'
assert PyQuery(result).find('.value').text() == 'Custom text'
for field_content in ['label', 'value']:
for display_mode in ['text', 'title', 'subtitle']:
if display_mode == 'title':
html_tag = 'h3'
elif display_mode == 'subtitle':
html_tag = 'h4'
elif display_mode == 'text' and field_content == 'label':
html_tag = '.label'
elif display_mode == 'text' and field_content == 'value':
html_tag = '.value'
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': '@skip@',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 0
assert PyQuery(result).find(html_tag) == []
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': '@empty@',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 1
assert PyQuery(result).find(html_tag).text() == ('Empty' if field_content == 'label' else '')
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': 'Custom text',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 1
assert PyQuery(result).find(html_tag).text() == (
'Empty' if field_content == 'label' else 'Custom text'
)
cell.custom_schema['cells'][0] = {
'varname': 'empty_email',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': 'Custom text',
}
cell.save()
result = cell.render(context)
assert len(PyQuery(result).find('.cell--body > div > div')) == 1
assert PyQuery(result).find('.label').text() == 'Empty Email'
assert PyQuery(result).find('.value').text() == 'Custom text'
assert PyQuery(result).find('.value a') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_custom_schema_custom_entry(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@custom@',
'template': "<b>Foo</b> bar'baz {{ card.fields.fielde }}",
'display_mode': 'title',
},
]
},
related_card_path='',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert '&lt;b&gt;Foo&lt;/b&gt;' in result
assert PyQuery(result).find('h3').text() == "<b>Foo</b> bar'baz lorem<strong>ipsum hello'world"
# test context
cell.custom_schema['cells'][0][
'template'
] = '{{ card.fields.fielda }} - {{ card.fields.related }} ({{ card.fields.related_structured.id }})'
cell.custom_schema['cells'][0]['display_mode'] = 'subtitle'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == '<i>a</i> - Foo Bar (42)'
# test display_mode & filters in template
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz', 'display_mode': 'label'},
{
'varname': '@custom@',
'template': '{{ card.fields.related|split:" "|join:"," }}',
'display_mode': 'text',
},
]
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Foo bar baz'
assert PyQuery(result).find('.value').text() == 'Foo,Bar'
# test available context
cell.card_ids = '11'
cell.custom_schema = {
'cells': [
{
'varname': '@custom@',
'template': 'Foo bar baz {% make_public_url url="http://127.0.0.1:8999/" %}',
'display_mode': 'label',
},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert '/api/wcs/file/' in PyQuery(cell_resp.text).find('.label').text()
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz X{{ site_base }}Y', 'display_mode': 'label'},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz Xhttp://testserverY'
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz X{{ repeat_index }}Y', 'display_mode': 'label'},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
for i in range(0, 3):
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz X%sY' % i
# custom schema but empty
cell.custom_schema = {'cells': []}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('div.cell--body') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_custom_schema_link_entry(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@link@',
'url_template': '/foo/bar/{{ card.fields.related_structured.id }}/',
'template': '{{ card.fields.fielda }} - {{ card.fields.related }}',
'display_mode': 'link',
},
]
},
related_card_path='',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
assert PyQuery(result).find('.value a').attr['class'] is None
cell.custom_schema['cells'][0]['display_mode'] = 'button'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
assert PyQuery(result).find('.value a').attr['class'] == 'pk-button'
cell.custom_schema['cells'][0][
'url_template'
] = '{{ site_base }}/foo/bar/{{ card.fields.related_structured.id }}/'
cell.custom_schema['cells'][0]['template'] = '<b>{{ card.fields.fielda }}</b> - {{ card.fields.related }}'
cell.card_ids = '11'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert (
'<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>'
in cell_resp
)
# empty label or empty url: no link in output
cell.custom_schema['cells'][0]['url_template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
cell.custom_schema['cells'][0]['url_template'] = 'foo/bar'
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
# check with page link
root_page = Page.objects.create(title='Root', slug='root', template_name='standard')
page1 = Page.objects.create(
title='Card',
slug='card',
template_name='standard',
sub_slug='card_model_1_id',
parent=root_page,
)
other_root_page = Page.objects.create(title='Other root', slug='other-root', template_name='standard')
page2 = Page.objects.create(
title='Card (bis)',
slug='card-bis',
template_name='standard',
sub_slug='card_model_1_id',
parent=other_root_page,
)
cell.custom_schema['cells'][0]['url_template'] = ''
cell.custom_schema['cells'][0]['page'] = page1.pk
cell.custom_schema['cells'][0]['template'] = 'Foo'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').attr['href'] == '/root/card/11/'
cell.custom_schema['cells'][0]['page'] = page2.pk
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').attr['href'] == '/other-root/card-bis/11/'
# empty label or empty url: no link in output
cell.custom_schema['cells'][0]['page'] = 0
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
cell.custom_schema['cells'][0]['page'] = page1.pk
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
# check with field
cell.custom_schema['cells'][0]['page'] = ''
cell.custom_schema['cells'][0]['link_field'] = 'fieldd'
cell.custom_schema['cells'][0]['template'] = '{{ card.fields.fielda }} - {{ card.fields.related }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').attr['href'].startswith('/api/wcs/file/')
assert PyQuery(result).find('.value a').attr['class'] == 'pk-button'
cell.custom_schema['cells'][0]['display_mode'] = 'link'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').attr['href'].startswith('/api/wcs/file/')
assert PyQuery(result).find('.value a').attr['class'] is None
# empty label or no value/no file field/unknown field: no link in output
context[cell.global_context_key] = [12]
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
context[cell.global_context_key] = [11]
cell.modify_global_context(context, request)
cell.repeat_index = 0
cell.custom_schema['cells'][0]['link_field'] = 'fielda'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
cell.custom_schema['cells'][0]['link_field'] = 'unknown'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
cell.custom_schema['cells'][0]['link_field'] = 'fieldd'
cell.custom_schema['cells'][0]['template'] = '{{ None|default:"" }}'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_all_cards(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
related_card_path='__all__',
)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
# check url called
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 3):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][i].repeat_index == i
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert cell_resp.context['repeat_index'] == i
assert len(mock_send.call_args_list) == 7
# page rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
# cell rendering
for i in range(0, 3):
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
assert 'filter-internal-id' not in mock_send.call_args_list[i * 2 + 2][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_identifier(mock_send, nocache, app):
page = Page.objects.create(
title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
)
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
related_card_path='',
)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
# check url called
mock_send.reset_mock()
resp = app.get(page.get_online_url() + '11/')
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' not in cell_resp
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/11/' in mock_send.call_args_list[0][0][0].url
# with identifiers
page.sub_slug = ''
page.save()
cell.card_ids = '42'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' in cell_resp
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/42/' in mock_send.call_args_list[0][0][0].url
cell.card_ids = '42, , 35'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 2):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][i].repeat_index == i
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert cell_resp.context['repeat_index'] == i
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' in cell_resp
assert len(mock_send.call_args_list) == 2
for i in range(0, 2):
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i][0][0].url
assert '&filter-internal-id=42&filter-internal-id=35&' in mock_send.call_args_list[i][0][0].url
cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}' # syntax error
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.text.replace('\n', '').strip() == '' # empty-cell
cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert len(mock_send.call_args_list) == 3
# page rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
# cell rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
assert '/api/cards/card_model_1/13' in mock_send.call_args_list[2][0][0].url
def test_card_ids():
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 3):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][i].repeat_index == i
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert cell_resp.context['repeat_index'] == i
assert len(mock_send.call_args_list) == 7
# page rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
# cell rendering
card_ids = [c['id'] for c in WCS_CARDS_DATA['card_model_1']]
filters = '&%s&' % '&'.join('filter-internal-id=%s' % cid for cid in card_ids)
for i in range(0, 3):
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 2][0][0].url
assert filters in mock_send.call_args_list[i * 2 + 2][0][0].url
for card_ids in [
'{% for card in cards|objects:"card_model_1" %}{{ card.id }},{% endfor %}',
'{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}',
]:
cell.card_ids = card_ids
cell.save()
test_card_ids()
cell.card_ids = '{{ var1 }}'
cell.save()
page.extra_variables = {'var1': card_ids}
page.save()
test_card_ids()
page.extra_variables = {}
page.save()
# with a card_ids template, but result is empty
cell.card_ids = '{{ foo }}'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.text.replace('\n', '').strip() == '' # empty-cell
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='card',
slug='sluga',
carddef_reference='default:card_a',
related_card_path='',
card_ids='1',
)
cell2 = WcsCardCell.objects.create(
page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
)
cell2_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
)
def failing(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) >= 2
for i in range(0, len(resp.context['cells']) - 1):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][-1].pk == cell2.pk
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[-1])
assert cell_resp.text.replace('\n', '').strip() == '' # empty-cell
assert len(mock_send.call_args_list) == len(urls)
for j, url in enumerate(urls):
assert url in mock_send.call_args_list[j][0][0].url
def single(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][1].pk == cell2.pk
assert resp.context['cells'][1].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[1])
assert cell_resp.context['repeat_index'] == 0
assert len(mock_send.call_args_list) == len(urls)
for j, url_parts in enumerate(urls):
if not isinstance(url_parts, tuple):
url_parts = (url_parts,)
for url_part in url_parts:
assert url_part in mock_send.call_args_list[j][0][0].url
def multiple(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) >= 2
assert resp.context['cells'][0].pk == cell.pk
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, len(resp.context['cells']) - 1):
assert resp.context['cells'][i + 1].pk == cell2.pk
assert resp.context['cells'][i + 1].repeat_index == i
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[i + 1])
assert cell_resp.context['repeat_index'] == i
assert len(mock_send.call_args_list) == len(urls)
for j, url_parts in enumerate(urls):
if not isinstance(url_parts, tuple):
url_parts = (url_parts,)
for url_part in url_parts:
assert url_part in mock_send.call_args_list[j][0][0].url
# no cell with this slug
cell2.related_card_path = 'slugz/cardb'
cell2.save()
failing(urls=[])
# another cell with the same slug
cell3 = WcsCardCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
cell2.related_card_path = 'sluga/foo'
cell2.save()
failing(urls=[])
cell3.delete()
# multiple ids configured on first cell
cell.card_ids = '{{ cards|objects:"card_a"|getlist:"id"|join:"," }}'
cell.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/list',
]
)
# related_card_path configured on first cell
cell.card_ids = '1' # reset
cell.related_path = 'foobar'
cell.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# reset
cell.related_path = ''
cell.save()
# another cell as the same slug, but not a WcsCardCell
cell3 = TextCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
# direct and single relation (item)
cell2.related_card_path = 'sluga/cardb'
cell2.save()
single(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
'/api/cards/card_b/1/', # check user access
'/api/cards/card_b/1/', # get card
]
)
cell3.delete() # reset
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
single(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
'/api/cards/card_b/7/', # check user access
'/api/cards/card_b/7/', # get card
]
)
# change cell ordering - cell with slug is after cell with related
cell.order = 42
cell.save()
# no error, but it does not work as expected: both cells has slug.
app.get(page.get_online_url(), status=200)
# remove slug of second cell
cell2.slug = ''
cell2.save()
urls = [
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
'/api/cards/card_b/7/', # check user access
'/api/cards/card_b/7/', # get card
]
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
assert resp.context['cells'][0].pk == cell2.pk
assert resp.context['cells'][0].repeat_index == 0
assert resp.context['cells'][1].pk == cell.pk
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert len(mock_send.call_args_list) == len(urls)
for j, url_parts in enumerate(urls):
if not isinstance(url_parts, tuple):
url_parts = (url_parts,)
for url_part in url_parts:
assert url_part in mock_send.call_args_list[j][0][0].url
# reset
cell.order = 0 # reset
cell.save()
cell2.slug = 'slugb'
cell2.save()
# test with custom_view
cell2.carddef_reference = 'default:card_b:a-custom-view'
cell2.save()
single(
urls=[
# get first cell data
(
'/api/cards/card_a/1/',
'&include-files-content=off&include-evolution=off&include-roles=off&include-workflow-data=off',
),
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
(
'/api/cards/card_b/a-custom-view/7/',
'&include-files-content=off&include-evolution=off&include-roles=off&include-workflow-data=off',
), # check user access
(
'/api/cards/card_b/a-custom-view/7/',
'&include-files-content=off&include-evolution=off&include-roles=off&include-workflow-data=off',
), # get card
]
)
# direct and multiple relation (items)
cell2.carddef_reference = 'default:card_b' # reset
cell2.related_card_path = 'sluga/cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'), # check user access
('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'), # get card
]
)
cell2.related_card_path = 'sluga/cardc/cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'), # check user access
('/api/cards/card_b/list', '&filter-internal-id=8&filter-internal-id=9&'), # get card
]
)
# direct and multiple relation through a block
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'), # check user access
('/api/cards/card_b/list', '&filter-internal-id=4&filter-internal-id=5&'), # get card
]
)
cell2.related_card_path = 'sluga/cardc/blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'), # check user access
('/api/cards/card_b/list', '&filter-internal-id=10&filter-internal-id=11&'), # get card
]
)
# unknown part in related_card_path
cell2.related_card_path = 'sluga/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
cell2.related_card_path = 'sluga/cardc/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
]
)
# card data not found
cell.card_ids = '42'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/42/',
]
)
cell.card_ids = '2'
cell.save()
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/2/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/61/',
]
)
# reset
cell.card_ids = '1'
cell.save()
# last part has not the correct card slug
cell2.related_card_path = 'sluga/cardc'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# unknown schema
cell2.related_card_path = 'sluga/cardz/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_z schema
'/api/cards/card_z/@schema',
]
)
# multiple relation of multiple relation
cell2.related_card_path = 'sluga/cardsb/reverse:cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# field not found
cell.card_ids = '3'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
# field empty
cell.card_ids = '4'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/4/',
]
)
# field not found in block
cell.card_ids = '3'
cell.save()
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
# field empty in block
cell.card_ids = '4'
cell.save()
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/4/',
]
)
# reverse relation of item
cell.carddef_reference = 'default:card_b'
cell.slug = 'slugb'
cell.card_ids = '1'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_a'
cell2.slug = 'sluga'
cell2.card_ids = ''
cell2.related_card_path = 'slugb/reverse:cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardb=1
'/api/cards/card_a/list?orig=combo&filter-cardb=1',
# and follow carda reverse relation
# check user access
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
# get card
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
]
)
# reverse relation of items
cell2.related_card_path = 'slugb/reverse:cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardsb=1
'/api/cards/card_a/list?orig=combo&filter-cardsb=1',
# and follow carda reverse relation
# check user access
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
# get card
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
]
)
# reverse relation of item through a block
cell2.related_card_path = 'slugb/reverse:blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardsb=1
'/api/cards/card_a/list?orig=combo&filter-blockb_cardb=1',
# and follow carda reverse relation
# check user access
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
# get card
(
'/api/cards/card_a/list',
'&filter-internal-id=1&filter-internal-id=2&filter-internal-id=3&filter-internal-id=4&',
),
]
)
# unknown part in related_card_path
cell2.related_card_path = 'slugb/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_b/1/',
]
)
# multiple relation of multiple relation
cell2.related_card_path = 'slugb/reverse:cardb/cardsb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_b/1/',
]
)
# reverse relation with many models using the same varname
cell.carddef_reference = 'default:card_h'
cell.slug = 'slugh'
cell.card_ids = '42'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_f'
cell2.slug = 'slugf'
cell2.card_ids = ''
cell2.related_card_path = 'slugh/reverse:cardh'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_h/42/',
# get list of card_f with cardf=42
'/api/cards/card_f/list?orig=combo&filter-cardh=42',
# and follow cardf reverse relation
'/api/cards/card_f/41/', # check user access
'/api/cards/card_f/41/', # get card
]
)
cell.card_ids = '44'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_g'
cell2.slug = 'slugg'
cell2.card_ids = ''
cell2.related_card_path = 'slugh/reverse:cardh'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_h/44/',
# get list of card_g with cardf=44
'/api/cards/card_g/list?orig=combo&filter-cardh=44',
# and follow cardf reverse relation
'/api/cards/card_g/43/', # check user access
'/api/cards/card_g/43/', # get card
]
)
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_only_for_user(mock_send, context, carddef_reference):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference=carddef_reference,
only_for_user=False,
related_card_path='',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
assert cell.is_visible(request=context['request']) is True
context['request'].user = MockUserWithNameId()
assert cell.is_visible(request=context['request']) is True
cell.only_for_user = True
cell.save()
context['request'].user = None
assert cell.is_visible(request=context['request']) is False
context['request'].user = MockUserWithNameId()
assert cell.is_visible(request=context['request']) is True
cache.clear()
context['synchronous'] = True # to get fresh content
context['request'].user = None
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid=xyz' in mock_send.call_args_list[0][0][0].url
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_user(mock_send, context, nocache, carddef_reference):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference=carddef_reference,
related_card_path='',
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
assert context['request'].user is None
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = AnonymousUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'email=foo%40example.net' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=xyz' in mock_send.call_args_list[0][0][0].url
cell.without_user = True
cell.save()
context['request'].user = None
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cell_condition(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
related_card_path='',
card_ids='{{ cards|objects:"card_model_1"|last|get:"id" }}',
)
cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|list'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|get:42'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
page.extra_variables = {'var1': '{{ cards|objects:"card_model_1"|getlist:"id"|list }}'}
page.save()
cell.condition = 'var1'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
page.extra_variables = {'var1': '{{ cards|objects:"card_model_1"|getlist:"id"|get:42|default:"" }}'}
page.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
page.extra_variables = {
'var1': '{{ cards|objects:"unknown"|first|get:"id"|default:"" }}',
'var2': '{{ cards|objects:"card_model_1"|first|get:"id"|default:"" }}',
}
page.save()
cell.condition = 'not var1'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
cell.condition = 'var2'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
cell.condition = 'not var2'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
cell.condition = 'not var1 and not var2'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
cell.condition = 'not var1 and var2'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
# wrong condition
cell.condition = 'cards|objects:"card_model_1"|first|filter_by:"fielda"|filter_value:"foo"'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_file_redirection(mock_send, app):
page = Page(title='One', slug='one', template_name='standard')
page.save()
cell = WcsCardCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.card_ids = '11'
cell.save()
resp = app.get('/one/')
ajax_cell_url = PyQuery(resp.text).find('[data-ajax-cell-url]').attr['data-ajax-cell-url']
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
resp = app.get(ajax_cell_url + '?ctx=' + extra_ctx[0])
file_url = PyQuery(resp.text).find('[download]').attr['href']
resp = app.get(file_url)
assert 'download?f=42' in resp.location
assert '&signature=' in resp.location
# invalid crypto
resp = app.get(file_url[:-2] + 'X/', status=403)
# invalid session key
resp = app.get(file_url.replace('file/', 'file/X'), status=403)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_assets(mock_send, settings, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cell_assets', template_name='standard')
cell1 = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
display_mode='card',
slug='slug1',
)
cell2 = WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
display_mode='table',
slug='slug2',
)
app = login(app)
settings.COMBO_CELL_ASSET_SLOTS = {}
resp = app.get('/manage/assets/')
assert 'have any asset yet.' in resp.text
settings.COMBO_CELL_ASSET_SLOTS = {
'wcs_wcscardscell': {
'logo': {
'prefix': 'Logo',
},
},
'wcs_wcscardinfoscell': {
'picture': {
'prefix': 'Picture',
},
},
}
resp = app.get('/manage/assets/')
assert 'Picture — %s' % cell1.get_label_for_asset() in resp.text
assert 'Logo — %s' % cell2.get_label_for_asset() in resp.text
def test_page_snapshot_with_old_card_cells():
page = Page.objects.create(title='xxx', slug='test_snapshots', template_name='standard')
PageSnapshot.take(page)
snapshot = page.pagesnapshot_set.first()
snapshot.serialization['cells'].append(
{
'model': 'wcs.wcscardinfoscell',
'fields': {
'slug': 'my-card',
'limit': 42,
'order': 1,
'groups': [],
'public': True,
'card_ids': '42,35',
'condition': 'my-condition',
'title_type': 'manual',
'placeholder': 'content',
'custom_title': 'my-title',
'display_mode': 'card',
'without_user': True,
'custom_schema': {},
'only_for_user': True,
'template_name': None,
'extra_css_class': '',
'carddef_reference': 'default:card_model_1',
'related_card_path': '',
'last_update_timestamp': '2022-08-11T13:57:43.362Z',
'restricted_to_unlogged': False,
'page': page.pk,
},
}
)
snapshot.serialization['cells'].append(
{
'model': 'wcs.wcscardscell',
'fields': {
'slug': 'my-other-card',
'limit': 35,
'order': 2,
'groups': [],
'public': True,
'condition': '',
'placeholder': 'content',
'custom_title': 'my-other-title',
'without_user': False,
'only_for_user': False,
'template_name': None,
'extra_css_class': '',
'carddef_reference': 'default:card_model_1',
'last_update_timestamp': '2022-08-12T07:19:18.541Z',
'restricted_to_unlogged': False,
'page': page.pk,
},
}
)
old_page = snapshot.get_page()
cell1 = old_page.get_cells()[0]
assert isinstance(cell1, WcsCardCell)
assert cell1.slug == 'my-card'
assert cell1.limit == 42
assert cell1.card_ids == '42,35'
assert cell1.title_type == 'manual'
assert cell1.custom_title == 'my-title'
assert cell1.display_mode == 'card'
assert cell1.without_user is True
assert cell1.custom_schema == {}
assert cell1.only_for_user is True
assert cell1.carddef_reference == 'default:card_model_1'
assert cell1.related_card_path == ''
cell2 = old_page.get_cells()[1]
assert isinstance(cell1, WcsCardCell)
assert cell2.slug == 'my-other-card'
assert cell2.limit == 35
assert cell2.card_ids == ''
assert cell2.title_type == 'manual'
assert cell2.custom_title == 'my-other-title'
assert cell2.display_mode == 'table'
assert cell2.without_user is False
assert cell2.custom_schema == {}
assert cell2.only_for_user is False
assert cell2.carddef_reference == 'default:card_model_1'
assert cell2.related_card_path == '__all__'
def get_output_of_command(command, *args, **kwargs):
old_stdout = sys.stdout
output = sys.stdout = StringIO()
call_command(command, format_json=True, *args, **kwargs)
sys.stdout = old_stdout
return output.getvalue()
def test_export_import_card_cell_with_page_link():
root_page = Page.objects.create(title='Root', slug='root', template_name='standard')
card_page = Page.objects.create(
title='Card',
slug='card',
template_name='standard',
sub_slug='card_model_1_id',
parent=root_page,
)
page = Page.objects.create(title='xxx', template_name='standard')
WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@link@',
'page': card_page.pk,
'template': 'Foo',
'display_mode': 'link',
},
]
},
)
site_export = get_output_of_command('export_site')
site_data = json.loads(site_export)
assert len(site_data['pages']) == 3
assert site_data['pages'][-1]['cells'][0]['fields']['custom_schema']['cells'][0]['page'] == str(
card_page.uuid
)
import_site(data={}, clean=True)
assert Page.objects.all().count() == 0
import_site(data=site_data, clean=True)
new_card_page = Page.objects.get(slug='card')
new_cell = WcsCardCell.objects.get()
assert new_cell.custom_schema['cells'][0]['page'] == new_card_page.pk
# unknown target page
new_cell.custom_schema['cells'][0]['page'] = 0
new_cell.save()
site_export = get_output_of_command('export_site')
site_data = json.loads(site_export)
assert site_data['pages'][-1]['cells'][0]['fields']['custom_schema']['cells'][0]['page'] == ''
site_data['pages'][-1]['cells'][0]['fields']['custom_schema']['cells'][0]['page'] = 'unknown'
import_site(data=site_data, clean=True)
new_card_page = Page.objects.get(slug='card')
new_cell = WcsCardCell.objects.get()
assert new_cell.custom_schema['cells'][0]['page'] == ''
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_edit_linked_card(mock_send, app, admin_user):
page = Page.objects.create(title='One', slug='one', template_name='two')
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
resp = resp.click(href='.*/linked-card')
assert [o[0] for o in resp.form['carddef_reference'].options] == [
'',
'default:card_model_1',
'default:card_model_2',
'default:card_model_3',
'default:card_a',
'default:card_b',
'default:card_c',
'default:card_d',
'default:card_e',
'other:card_model_1',
'other:card_model_2',
'other:card_model_3',
'other:card_a',
'other:card_b',
'other:card_c',
'other:card_d',
'other:card_e',
]
resp.form['carddef_reference'] = 'default:card_model_3'
resp = resp.form.submit().follow()
page.refresh_from_db()
assert page.sub_slug == 'card_model_3_id'
resp = app.get('/manage/pages/%s/slug' % page.pk)
assert 'sub_slug' not in resp.context['form'].fields
resp = app.get('/manage/pages/%s/linked-card' % page.pk)
assert resp.form['carddef_reference'].value == 'default:card_model_3'
resp.form['carddef_reference'] = ''
resp = resp.form.submit().follow()
page.refresh_from_db()
assert page.sub_slug == ''
resp = app.get('/manage/pages/%s/slug' % page.pk)
assert 'sub_slug' in resp.context['form'].fields
resp.form['sub_slug'] = 'foobar'
resp = resp.form.submit().follow()
page.refresh_from_db()
assert page.sub_slug == 'foobar'