Projet

Général

Profil

0006-wcs-render-card-cell-with-table-mode-68063.patch

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

Télécharger (16,2 ko)

Voir les différences:

Subject: [PATCH 6/8] wcs: render card cell with table mode (#68063)

 combo/apps/wcs/models.py                      |  55 +++-
 combo/apps/wcs/templates/combo/wcs/cards.html |   2 +-
 tests/wcs/test_card.py                        | 267 +++++++++++++++++-
 3 files changed, 317 insertions(+), 7 deletions(-)
combo/apps/wcs/models.py
34 34

  
35 35
from combo.data.library import register_cell_class
36 36
from combo.data.models import CellBase, Page
37
from combo.utils import requests
37
from combo.utils import NothingInCacheException, requests
38 38
from combo.utils.misc import is_portal_agent
39 39

  
40 40
from .utils import get_wcs_json, get_wcs_services, is_wcs_enabled
......
974 974

  
975 975
    is_enabled = classmethod(is_wcs_enabled)
976 976

  
977
    default_template_name = 'combo/wcs/card.html'
978 977
    manager_appearance_template = 'combo/wcs/manager/card-infos-cell-form-appearance.html'
979 978

  
980 979
    class Meta:
......
1030 1029

  
1031 1030
        self.mark_as_valid()
1032 1031

  
1032
    @property
1033
    def default_template_name(self):
1034
        if self.display_mode == 'table':
1035
            return 'combo/wcs/cards.html'
1036
        return 'combo/wcs/card.html'
1037

  
1033 1038
    @property
1034 1039
    def global_context_key(self):
1035 1040
        return '%s-card-ids' % self.get_reference()
1036 1041

  
1037 1042
    def modify_global_context(self, context, request):
1043
        if self.display_mode == 'table' and not context.get('synchronous'):
1044
            # don't call wcs on page loading
1045
            return
1038 1046
        if self.carddef_reference and self.global_context_key not in context:
1039 1047
            card_ids = self.get_card_ids(context, request)
1040 1048
            context[self.global_context_key] = card_ids
1041 1049

  
1042 1050
    def get_repeat_template(self, context):
1051
        if self.display_mode == 'table':
1052
            # don't repeat cell if table display mode
1053
            return []
1043 1054
        return len(context.get(self.global_context_key) or [])
1044 1055

  
1045 1056
    def get_related_card_path(self):
......
1401 1412
                return self.filter_card_ids(card_ids, original_context)
1402 1413

  
1403 1414
        if self.get_all():
1415
            if self.display_mode == 'table':
1416
                # don't call wcs if table mode with all cards
1417
                return []
1404 1418
            # get all cards
1405 1419
            return [c['id'] for c in self.get_cards_from_ids([], original_context, synchronous=True)]
1406 1420

  
......
1437 1451

  
1438 1452
    def get_cell_extra_context(self, context):
1439 1453
        extra_context = super().get_cell_extra_context(context)
1454
        if self.title_type in ['auto', 'manual']:
1455
            # card mode: default value used if card is not found
1456
            extra_context['title'] = self.cached_title
1457
        return getattr(self, 'get_cell_extra_context_%s_mode' % self.display_mode)(context, extra_context)
1458

  
1459
    def get_cell_extra_context_table_mode(self, context, extra_context):
1460
        if not context.get('synchronous'):
1461
            raise NothingInCacheException()
1462

  
1463
        extra_context['paginate_by'] = self.limit or 10
1464
        if self.title_type == 'manual':
1465
            extra_context['title'] = self.custom_title or extra_context['title']
1466
        if not self.carddef_reference:
1467
            # not configured
1468
            return extra_context
1469

  
1470
        pages_with_sub_slug = Page.objects.exclude(sub_slug='')
1471
        card_id = '%s_id' % self.carddef_reference.split(':')[1]
1472
        matching_pages = [
1473
            p for p in pages_with_sub_slug if '<%s>' % card_id in p.sub_slug or p.sub_slug == card_id
1474
        ]
1475
        if matching_pages:
1476
            card_page = matching_pages[0]
1477
            extra_context['card_page_base_url'] = card_page.get_online_url()
1478

  
1479
        card_ids = context.get(self.global_context_key)
1480
        if not card_ids and self.related_card_path != '__all__':
1481
            extra_context['card_objects'] = []
1482
        else:
1483
            extra_context['card_objects'] = self.get_cards_from_ids(card_ids, context)
1484

  
1485
        return extra_context
1486

  
1487
    def get_cell_extra_context_card_mode(self, context, extra_context):
1440 1488
        extra_context['schema'] = self.cached_json
1441 1489
        extra_context['fields_by_varnames'] = {
1442 1490
            i['varname']: i for i in (self.cached_json.get('fields') or []) if i.get('varname')
1443 1491
        }
1444
        # default value used if card is not found
1445
        if self.title_type in ['auto', 'manual']:
1446
            extra_context['title'] = self.cached_title
1447 1492

  
1448 1493
        card_id = self.get_card_id(context)
1449 1494
        if not card_id:
combo/apps/wcs/templates/combo/wcs/cards.html
3 3
{% block cell-content %}
4 4

  
5 5
{% block cell-header %}
6
<h2>{{ title }}</h2>
6
{% if title %}<h2>{{ title|force_escape }}</h2>{% endif %}
7 7
{% include "combo/asset_picture_fragment.html" %}
8 8
{% endblock %}
9 9

  
tests/wcs/test_card.py
18 18
from tests.test_manager import login
19 19
from tests.utils import manager_submit_cell
20 20

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

  
23 23
pytestmark = pytest.mark.django_db
24 24

  
......
633 633
    assert cell.cached_title == 'Card Model 1'
634 634

  
635 635

  
636
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
637
def test_card_cell_table_mode_render(mock_send, context, app):
638
    page = Page.objects.create(title='xxx', template_name='standard')
639
    cell = WcsCardInfosCell.objects.create(
640
        page=page,
641
        placeholder='content',
642
        order=0,
643
        display_mode='table',
644
        carddef_reference='default:card_model_1',
645
    )
646

  
647
    context['card_model_1_id'] = 11
648
    request = RequestFactory().get('/')
649
    context['synchronous'] = True  # to get fresh content
650
    cell.modify_global_context(context, request)
651

  
652
    result = cell.render(context)
653
    assert '<h2>Card Model 1</h2>' in result
654
    assert 'cards-card_model_1' in result
655
    assert (
656
        '<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/11/"><span class="card-title">aa</span></a>'
657
        in result
658
    )
659
    assert (
660
        '<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/12/"><span class="card-title">bb</span></a>'
661
        in result
662
    )
663
    assert (
664
        '<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/13/"><span class="card-title">cc</span></a>'
665
        in result
666
    )
667
    assert 'data-paginate-by="10"' in result
668

  
669
    # create a page with the correct subslug
670
    page = Page.objects.create(slug='foo', title='Foo', sub_slug='(?P<card_model_1_id>[a-z0-9]+)')
671

  
672
    result = cell.render(context)
673
    assert '<h2>Card Model 1</h2>' in result
674
    assert '<a href="/foo/11"><span class="card-title">aa</span></a>' in result
675
    assert '<a href="/foo/12"><span class="card-title">bb</span></a>' in result
676
    assert '<a href="/foo/13"><span class="card-title">cc</span></a>' in result
677

  
678
    cell.carddef_reference = 'default:card_model_1:foo'
679
    cell.limit = 42
680
    cell.save()
681
    page.sub_slug = 'card_model_1_id'
682
    page.save()
683

  
684
    result = cell.render(context)
685
    assert '<h2>Card Model 1</h2>' in result
686
    assert '<a href="/foo/11"><span class="card-title">aa</span></a>' in result
687
    assert '<a href="/foo/12"><span class="card-title">bb</span></a>' in result
688
    assert '<a href="/foo/13"><span class="card-title">cc</span></a>' not in result
689
    assert 'data-paginate-by="42"' in result
690

  
691
    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
692
        requests_get.return_value = MockedRequestResponse(content=json.dumps({'data': []}))
693
        cell.render(context)
694
    assert len(requests_get.call_args_list) == 1
695
    assert (
696
        requests_get.call_args_list[0][0][0]
697
        == '/api/cards/card_model_1/list/foo?full=on&filter-internal-id=11'
698
    )
699
    assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
700

  
701

  
702
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
703
def test_card_cell_table_mode_render_all_cards(mock_send, nocache, app):
704
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
705
    cell = WcsCardInfosCell.objects.create(
706
        page=page,
707
        placeholder='content',
708
        order=0,
709
        display_mode='table',
710
        carddef_reference='default:card_model_1',
711
        related_card_path='__all__',
712
    )
713

  
714
    cell_url = reverse(
715
        'combo-public-ajax-page-cell',
716
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
717
    )
718

  
719
    # check url called
720
    mock_send.reset_mock()
721
    resp = app.get(page.get_online_url())
722
    assert len(resp.context['cells']) == 1
723
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
724
    app.get(cell_url + '?ctx=' + extra_ctx[0])
725
    assert len(mock_send.call_args_list) == 1
726
    # cell rendering
727
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
728
    assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url
729

  
730

  
731
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
732
def test_card_cell_table_mode_render_identifier(mock_send, nocache, app):
733
    page = Page.objects.create(
734
        title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
735
    )
736
    cell = WcsCardInfosCell.objects.create(
737
        page=page,
738
        placeholder='content',
739
        order=0,
740
        display_mode='table',
741
        carddef_reference='default:card_model_1',
742
    )
743

  
744
    cell_url = reverse(
745
        'combo-public-ajax-page-cell',
746
        kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
747
    )
748

  
749
    # check url called
750
    mock_send.reset_mock()
751
    resp = app.get(page.get_online_url() + '11/')
752
    assert len(resp.context['cells']) == 1
753
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
754
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
755
    assert len(mock_send.call_args_list) == 1
756
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
757
    assert '&filter-internal-id=11&' in mock_send.call_args_list[0][0][0].url
758

  
759
    # with identifiers
760
    page.sub_slug = ''
761
    page.save()
762
    cell.card_ids = '42'
763
    cell.save()
764
    mock_send.reset_mock()
765
    resp = app.get(page.get_online_url())
766
    assert len(resp.context['cells']) == 1
767
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
768
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
769
    assert len(mock_send.call_args_list) == 1
770
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
771
    assert '&filter-internal-id=42&' in mock_send.call_args_list[0][0][0].url
772

  
773
    cell.card_ids = '42, , 35'
774
    cell.save()
775
    mock_send.reset_mock()
776
    resp = app.get(page.get_online_url())
777
    assert len(resp.context['cells']) == 1
778
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
779
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
780
    assert len(mock_send.call_args_list) == 1
781
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
782
    assert '&filter-internal-id=42&filter-internal-id=35&' in mock_send.call_args_list[0][0][0].url
783

  
784
    cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}'  # syntax error
785
    cell.save()
786
    mock_send.reset_mock()
787
    resp = app.get(page.get_online_url())
788
    assert len(resp.context['cells']) == 1
789
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
790
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
791
    assert 'empty-message' in cell_resp
792

  
793
    cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
794
    cell.save()
795
    mock_send.reset_mock()
796
    resp = app.get(page.get_online_url())
797
    assert len(resp.context['cells']) == 1
798
    extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
799
    cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
800
    assert len(mock_send.call_args_list) == 2
801
    # cell rendering
802
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
803
    assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
804
    assert '&filter-internal-id=13&' in mock_send.call_args_list[1][0][0].url
805

  
806

  
807
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
808
def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache, app):
809
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
810
    WcsCardInfosCell.objects.create(
811
        page=page,
812
        placeholder='content',
813
        order=0,
814
        display_mode='table',
815
        slug='sluga',
816
        carddef_reference='default:card_a',
817
        card_ids='1',
818
    )
819
    cell2 = WcsCardInfosCell.objects.create(
820
        page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
821
    )
822

  
823
    cell2_url = reverse(
824
        'combo-public-ajax-page-cell',
825
        kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
826
    )
827

  
828
    # just do a simple test to check url calls
829
    def check(urls):
830
        resp = app.get(page.get_online_url())
831
        assert len(resp.context['cells']) == 2
832
        extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
833
        mock_send.reset_mock()
834
        app.get(cell2_url + '?ctx=' + extra_ctx[1])
835
        assert len(mock_send.call_args_list) == len(urls)
836
        for j, url_parts in enumerate(urls):
837
            if not isinstance(url_parts, tuple):
838
                url_parts = (url_parts,)
839
            for url_part in url_parts:
840
                assert url_part in mock_send.call_args_list[j][0][0].url
841

  
842
    # direct and single relation (item)
843
    cell2.related_card_path = 'sluga/cardb'
844
    cell2.save()
845
    urls = [
846
        # get first cell data
847
        '/api/cards/card_a/1/',
848
        # and follow cardb relation
849
        '/api/cards/card_b/1/',  # get card
850
    ]
851
    check(urls)
852

  
853
    # direct and multiple relation (items)
854
    cell2.carddef_reference = 'default:card_b'  # reset
855
    cell2.related_card_path = 'sluga/cardsb'
856
    cell2.save()
857
    urls = [
858
        # get first cell data
859
        '/api/cards/card_a/1/',
860
        # and follow cardb relation
861
        ('/api/cards/card_b/list', '&filter-internal-id=2&filter-internal-id=3&'),  # get cards
862
    ]
863
    check(urls)
864

  
865

  
866
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
867
def test_card_cell_table_mode_render_title(mock_send, context):
868
    page = Page.objects.create(title='xxx', template_name='standard')
869
    cell = WcsCardInfosCell.objects.create(
870
        page=page,
871
        placeholder='content',
872
        order=0,
873
        display_mode='table',
874
        carddef_reference='default:card_model_1',
875
        title_type='auto',
876
    )
877

  
878
    context['synchronous'] = True  # to get fresh content
879

  
880
    result = cell.render(context)
881
    assert '<h2>Card Model 1</h2>' in result
882

  
883
    context.pop('title')
884
    cell.title_type = 'empty'
885
    cell.save()
886
    result = cell.render(context)
887
    assert '<h2>' not in result
888

  
889
    cell.title_type = 'manual'
890
    cell.save()
891
    result = cell.render(context)
892
    assert '<h2>Card Model 1</h2>' in result
893

  
894
    context.pop('title')
895
    cell.custom_title = 'Foo bar !'
896
    cell.save()
897
    result = cell.render(context)
898
    assert '<h2>Foo bar !</h2>' in result
899

  
900

  
636 901
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
637 902
def test_card_cell_card_mode_render(mock_send, context, app):
638 903
    page = Page.objects.create(title='xxx', template_name='standard')
639
-