wcs: render card cell with table mode (#68063)

This commit is contained in:
Lauréline Guérin 2022-08-11 16:46:26 +02:00
parent fed5465f98
commit 7716113a51
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 317 additions and 7 deletions

View File

@ -34,7 +34,7 @@ from requests.exceptions import RequestException
from combo.data.library import register_cell_class
from combo.data.models import CellBase, Page
from combo.utils import requests
from combo.utils import NothingInCacheException, requests
from combo.utils.misc import is_portal_agent
from .utils import get_wcs_json, get_wcs_services, is_wcs_enabled
@ -979,7 +979,6 @@ class WcsCardInfosCell(CardMixin, CellBase):
is_enabled = classmethod(is_wcs_enabled)
default_template_name = 'combo/wcs/card.html'
manager_appearance_template = 'combo/wcs/manager/card-infos-cell-form-appearance.html'
class Meta:
@ -1035,16 +1034,28 @@ class WcsCardInfosCell(CardMixin, CellBase):
self.mark_as_valid()
@property
def default_template_name(self):
if self.display_mode == 'table':
return 'combo/wcs/cards.html'
return 'combo/wcs/card.html'
@property
def global_context_key(self):
return '%s-card-ids' % self.get_reference()
def modify_global_context(self, context, request):
if self.display_mode == 'table' and not context.get('synchronous'):
# don't call wcs on page loading
return
if self.carddef_reference and self.global_context_key not in context:
card_ids = self.get_card_ids(context, request)
context[self.global_context_key] = card_ids
def get_repeat_template(self, context):
if self.display_mode == 'table':
# don't repeat cell if table display mode
return []
return len(context.get(self.global_context_key) or [])
def get_related_card_path(self):
@ -1406,6 +1417,9 @@ class WcsCardInfosCell(CardMixin, CellBase):
return self.filter_card_ids(card_ids, original_context)
if self.must_get_all():
if self.display_mode == 'table':
# don't call wcs if table mode with all cards
return []
# get all cards
return [c['id'] for c in self.get_cards_from_ids([], original_context, synchronous=True)]
@ -1442,13 +1456,44 @@ class WcsCardInfosCell(CardMixin, CellBase):
def get_cell_extra_context(self, context):
extra_context = super().get_cell_extra_context(context)
if self.title_type in ['auto', 'manual']:
# card mode: default value used if card is not found
extra_context['title'] = self.cached_title
return getattr(self, 'get_cell_extra_context_%s_mode' % self.display_mode)(context, extra_context)
def get_cell_extra_context_table_mode(self, context, extra_context):
if not context.get('synchronous'):
raise NothingInCacheException()
extra_context['paginate_by'] = self.limit or 10
if self.title_type == 'manual':
extra_context['title'] = self.custom_title or extra_context['title']
if not self.carddef_reference:
# not configured
return extra_context
pages_with_sub_slug = Page.objects.exclude(sub_slug='')
card_id = '%s_id' % self.carddef_reference.split(':')[1]
matching_pages = [
p for p in pages_with_sub_slug if '<%s>' % card_id in p.sub_slug or p.sub_slug == card_id
]
if matching_pages:
card_page = matching_pages[0]
extra_context['card_page_base_url'] = card_page.get_online_url()
card_ids = context.get(self.global_context_key)
if not card_ids and self.related_card_path != '__all__':
extra_context['card_objects'] = []
else:
extra_context['card_objects'] = self.get_cards_from_ids(card_ids, context)
return extra_context
def get_cell_extra_context_card_mode(self, context, extra_context):
extra_context['schema'] = self.cached_json
extra_context['fields_by_varnames'] = {
i['varname']: i for i in (self.cached_json.get('fields') or []) if i.get('varname')
}
# default value used if card is not found
if self.title_type in ['auto', 'manual']:
extra_context['title'] = self.cached_title
card_id = self.get_card_id(context)
if not card_id:

View File

@ -3,7 +3,7 @@
{% block cell-content %}
{% block cell-header %}
<h2>{{ title }}</h2>
{% if title %}<h2>{{ title|force_escape }}</h2>{% endif %}
{% include "combo/asset_picture_fragment.html" %}
{% endblock %}

View File

@ -18,7 +18,7 @@ from combo.data.models import Page, TextCell, ValidityInfo
from tests.test_manager import login
from tests.utils import manager_submit_cell
from .utils import WCS_CARDS_DATA, MockUser, MockUserWithNameId, mocked_requests_send
from .utils import WCS_CARDS_DATA, MockedRequestResponse, MockUser, MockUserWithNameId, mocked_requests_send
pytestmark = pytest.mark.django_db
@ -633,6 +633,271 @@ def test_card_cell_load(mock_send):
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 = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
)
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?full=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_all_cards(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardInfosCell.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 = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
carddef_reference='default:card_model_1',
)
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')
WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
slug='sluga',
carddef_reference='default:card_a',
card_ids='1',
)
cell2 = WcsCardInfosCell.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 = WcsCardInfosCell.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')