From d814e53d77299cc8971bcf810ac3de27f9f7bbb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 12 Aug 2022 13:49:40 +0200
Subject: [PATCH 3/5] wcs: delete old card cell models (#68140)

---
 combo/apps/wcs/__init__.py                    |  11 +-
 combo/apps/wcs/forms.py                       |  37 +-
 .../apps/wcs/migrations/0053_new_card_cell.py |  25 ++
 combo/apps/wcs/models.py                      | 196 +---------
 .../manager/card-cell-form-appearance.html    |  26 ++
 ...splay.html => card-cell-form-display.html} |  14 +-
 .../card-infos-cell-form-appearance.html      |  26 --
 combo/manager/static/js/combo.manager.js      |   4 +-
 tests/test_manager.py                         |   8 +-
 tests/test_search.py                          |   2 +-
 tests/wcs/test_all.py                         | 336 +-----------------
 tests/wcs/test_card.py                        | 102 +++---
 12 files changed, 143 insertions(+), 644 deletions(-)
 create mode 100644 combo/apps/wcs/migrations/0053_new_card_cell.py
 create mode 100644 combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-appearance.html
 rename combo/apps/wcs/templates/combo/wcs/manager/{card-infos-cell-form-display.html => card-cell-form-display.html} (90%)
 delete mode 100644 combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-appearance.html

diff --git a/combo/apps/wcs/__init__.py b/combo/apps/wcs/__init__.py
index 7a2ca1d9..a041a970 100644
--- a/combo/apps/wcs/__init__.py
+++ b/combo/apps/wcs/__init__.py
@@ -128,20 +128,13 @@ class AppConfig(django.apps.AppConfig):
     def update_db_cache(self):
         from combo.data.models import CellBase
 
-        from .models import (
-            WcsCardInfosCell,
-            WcsCardsCell,
-            WcsCategoryCell,
-            WcsFormCell,
-            WcsFormsOfCategoryCell,
-        )
+        from .models import WcsCardCell, WcsCategoryCell, WcsFormCell, WcsFormsOfCategoryCell
 
         models_to_update = [
             WcsFormCell,
             WcsCategoryCell,
             WcsFormsOfCategoryCell,
-            WcsCardsCell,
-            WcsCardInfosCell,
+            WcsCardCell,
         ]
         for cell in CellBase.get_cells(cell_filter=lambda x: x in models_to_update):
             cell.save()
diff --git a/combo/apps/wcs/forms.py b/combo/apps/wcs/forms.py
index a6b7f9cf..7d9d8f10 100644
--- a/combo/apps/wcs/forms.py
+++ b/combo/apps/wcs/forms.py
@@ -20,8 +20,7 @@ from django.utils.translation import ugettext_lazy as _
 from combo.utils.forms import MultiSortWidget
 
 from .models import (
-    WcsCardInfosCell,
-    WcsCardsCell,
+    WcsCardCell,
     WcsCareFormsCell,
     WcsCategoryCell,
     WcsCurrentDraftsCell,
@@ -49,38 +48,14 @@ class WcsFormForLinkListCellForm(WcsFormCellForm):
         fields = ('formdef_reference', 'extra_css_class')
 
 
-class WcsCardsCellForm(forms.ModelForm):
-    with_user = forms.BooleanField(
-        label=_('Restrict to cards accessible to the user'), required=False, initial=True
-    )
-
-    class Meta:
-        model = WcsCardsCell
-        fields = ('carddef_reference', 'limit', 'only_for_user')
-
-    def __init__(self, *args, **kwargs):
-        instance = kwargs['instance']
-        initial = kwargs.pop('initial', {})
-        initial['with_user'] = not instance.without_user
-        super().__init__(initial=initial, *args, **kwargs)
-        card_models = get_wcs_options('/api/cards/@list', include_custom_views=True)
-        self.fields['carddef_reference'].widget = forms.Select(choices=card_models)
-
-    def save(self, *args, **kwargs):
-        super().save(*args, **kwargs)
-        self.instance.without_user = not self.cleaned_data['with_user']
-        self.instance.save()
-        return self.instance
-
-
-class WcsCardInfoCellForm(forms.ModelForm):
+class WcsCardCellForm(forms.ModelForm):
     with_user = forms.BooleanField(
         label=_('Restrict to cards accessible to the user'), required=False, initial=True
     )
     related_card_path = forms.ChoiceField(label=_('Card Identifier'), required=False)
 
     class Meta:
-        model = WcsCardInfosCell
+        model = WcsCardCell
         fields = (
             'carddef_reference',
             'related_card_path',
@@ -132,7 +107,7 @@ class WcsCardInfoCellForm(forms.ModelForm):
         return cleaned_data
 
 
-class WcsCardInfoCellAppearanceBaseForm(forms.ModelForm):
+class WcsCardCellAppearanceBaseForm(forms.ModelForm):
     def save(self, *args, **kwargs):
         super().save(*args, **kwargs)
         if self.instance.title_type != 'manual':
@@ -141,11 +116,11 @@ class WcsCardInfoCellAppearanceBaseForm(forms.ModelForm):
         return self.instance
 
 
-class WcsCardInfoCellDisplayForm(forms.ModelForm):
+class WcsCardCellDisplayForm(forms.ModelForm):
     customize_display = forms.BooleanField(label=_('Customize display'), required=False)
 
     class Meta:
-        model = WcsCardInfosCell
+        model = WcsCardCell
         fields = (
             'limit',
             'display_mode',
diff --git a/combo/apps/wcs/migrations/0053_new_card_cell.py b/combo/apps/wcs/migrations/0053_new_card_cell.py
new file mode 100644
index 00000000..170d1e2c
--- /dev/null
+++ b/combo/apps/wcs/migrations/0053_new_card_cell.py
@@ -0,0 +1,25 @@
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('wcs', '0052_new_card_cell'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='wcscardscell',
+            name='groups',
+        ),
+        migrations.RemoveField(
+            model_name='wcscardscell',
+            name='page',
+        ),
+        migrations.DeleteModel(
+            name='WcsCardInfosCell',
+        ),
+        migrations.DeleteModel(
+            name='WcsCardsCell',
+        ),
+    ]
diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py
index 7f26fca2..be3cdf15 100644
--- a/combo/apps/wcs/models.py
+++ b/combo/apps/wcs/models.py
@@ -816,125 +816,6 @@ class CardMixin:
         return escape(self.custom_title) or self.cached_title or None
 
 
-@register_cell_class
-class WcsCardsCell(CardMixin, WcsBlurpMixin, CellBase):
-    carddef_reference = models.CharField(_('Card Model'), max_length=150)
-    cached_title = models.CharField(_('Title'), max_length=150)
-    custom_title = models.CharField(_('Custom Title'), max_length=150, blank=True)
-    only_for_user = models.BooleanField(_('Limit to cards linked to the logged-in user'), default=False)
-    without_user = models.BooleanField(_('Ignore the logged-in user'), default=False)
-    limit = models.PositiveSmallIntegerField(
-        _('Number of cards per page (default 10)'), null=True, blank=True
-    )
-
-    default_template_name = 'combo/wcs/cards.html'
-    variable_name = 'card_objects'
-
-    class Meta:
-        verbose_name = _('Cards')
-
-    def save(self, *args, **kwargs):
-        super().save(*args, **kwargs)
-
-        if 'update_fields' in kwargs:
-            # don't populate the cache
-            return
-
-        def populate_cache():
-            if self.carddef_reference:
-                parts = self.carddef_reference.split(':')
-                wcs_key, card_slug = parts[:2]
-                wcs_site = get_wcs_services().get(wcs_key)
-                card_models = get_wcs_json(wcs_site, 'api/cards/@list')
-
-                if not card_models or card_models.get('err') == 1:
-                    # can not retrieve data, don't report cell as invalid
-                    self.mark_as_valid()
-                    return
-
-                card_found = False
-                for card in card_models.get('data') or []:
-                    slug = card['slug']
-
-                    if slug != card_slug:
-                        continue
-
-                    card_title = card['title']
-
-                    if len(parts) > 2:
-                        custom_view = None
-
-                        for v in card.get('custom_views') or []:
-                            if v['id'] == parts[2]:
-                                custom_view = v
-                                break
-
-                        if custom_view is None:
-                            continue
-
-                        card_title = '%s - %s' % (card_title, custom_view['text'])
-
-                    self.cached_title = card_title
-                    self.save(update_fields=['cached_title'])
-                    card_found = True
-                    break
-                if card_found:
-                    self.mark_as_valid()
-                    return
-                else:
-                    return self.mark_as_invalid('wcs_card_not_found')
-            else:
-                return self.mark_as_invalid('wcs_card_not_defined')
-
-        populate_cache()
-
-    def is_visible(self, request, **kwargs):
-        user = getattr(request, 'user', None)
-        if self.only_for_user and (not user or user.is_anonymous):
-            return False
-        return super().is_visible(request, **kwargs)
-
-    def get_api_url(self, context):
-        parts = self.carddef_reference.split(':')
-        url = '/api/cards/%s/list' % parts[1]
-        if len(parts) > 2:
-            url = '%s/%s' % (url, parts[2])
-        user = self.get_concerned_user(context)
-        if self.only_for_user and user and not user.is_anonymous and user.get_name_id():
-            url = '%s?filter-user-uuid=%s' % (url, user.get_name_id())
-        return url
-
-    def get_cell_extra_context(self, context):
-        extra_context = super().get_cell_extra_context(context)
-        extra_context['paginate_by'] = self.limit or 10
-        extra_context['title'] = self.custom_title or self.cached_title
-
-        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()
-
-        try:
-            extra_context['card_objects'] = list(extra_context['card_objects'][self.wcs_site]['data'])
-        except (KeyError, TypeError):
-            # an error occured when getting the data
-            extra_context['card_objects'] = []
-
-        return extra_context
-
-    def get_default_form_class(self):
-        from .forms import WcsCardsCellForm
-
-        return WcsCardsCellForm
-
-    def render_for_search(self):
-        return ''
-
-
 @register_cell_class
 class WcsCardCell(CardMixin, CellBase):
     carddef_reference = models.CharField(_('Card Model'), max_length=150)
@@ -972,53 +853,12 @@ class WcsCardCell(CardMixin, CellBase):
     cached_title = models.CharField(_('Title'), max_length=150)
     cached_json = JSONField(blank=True, default=dict)
 
-    class Meta:
-        verbose_name = _('Card(s)')
-
-
-@register_cell_class
-class WcsCardInfosCell(CardMixin, CellBase):
-    carddef_reference = models.CharField(_('Card Model'), max_length=150)
-    related_card_path = models.CharField(_('Card Identifier'), max_length=1000, blank=True)
-    card_ids = models.CharField(_('Other Card Identifiers'), max_length=1000, blank=True)
-    only_for_user = models.BooleanField(_('Limit to cards linked to the logged-in user'), default=False)
-    without_user = models.BooleanField(_('Ignore the logged-in user'), default=False)
-    limit = models.PositiveSmallIntegerField(
-        _('Number of cards per page (default 10)'), null=True, blank=True
-    )
-    custom_schema = JSONField(blank=True, default=dict)
-    display_mode = models.CharField(
-        _('Display mode'),
-        max_length=10,
-        default='card',
-        choices=[
-            ('card', _('Card')),
-            ('table', _('Table')),
-        ],
-    )
-
-    title_type = models.CharField(
-        _('Title'),
-        max_length=20,
-        default='auto',
-        blank=False,
-        choices=[
-            ('auto', _('Default Title (Card Label)')),
-            ('manual', _('Custom Title')),
-            ('empty', _('No Title')),
-        ],
-    )
-    custom_title = models.CharField(_('Custom Title'), max_length=150, blank=True)
-
-    cached_title = models.CharField(_('Title'), max_length=150)
-    cached_json = JSONField(blank=True, default=dict)
-
     is_enabled = classmethod(is_wcs_enabled)
 
-    manager_appearance_template = 'combo/wcs/manager/card-infos-cell-form-appearance.html'
+    manager_appearance_template = 'combo/wcs/manager/card-cell-form-appearance.html'
 
     class Meta:
-        verbose_name = _('Card Information Cell')
+        verbose_name = _('Card(s)')
 
     def save(self, *args, **kwargs):
         super().save(*args, **kwargs)
@@ -1260,7 +1100,7 @@ class WcsCardInfosCell(CardMixin, CellBase):
 
         # get cells with explicit ids
         results = []
-        for cell in WcsCardInfosCell.objects.filter(page=self.page_id).exclude(pk=self.pk):
+        for cell in WcsCardCell.objects.filter(page=self.page_id).exclude(pk=self.pk):
             if not cell.slug:
                 # no slug
                 continue
@@ -1386,8 +1226,8 @@ class WcsCardInfosCell(CardMixin, CellBase):
 
         first_cell_slug = self.get_related_card_path().split('/', maxsplit=1)[0]
         try:
-            first_cell = WcsCardInfosCell.objects.get(page=self.page_id, slug=first_cell_slug)
-        except (WcsCardInfosCell.DoesNotExist, WcsCardInfosCell.MultipleObjectsReturned):
+            first_cell = WcsCardCell.objects.get(page=self.page_id, slug=first_cell_slug)
+        except (WcsCardCell.DoesNotExist, WcsCardCell.MultipleObjectsReturned):
             return []
         if first_cell.related_card_path:
             # no explicit ids
@@ -1594,28 +1434,28 @@ class WcsCardInfosCell(CardMixin, CellBase):
         return extra_context
 
     def get_default_form_class(self):
-        from .forms import WcsCardInfoCellForm
+        from .forms import WcsCardCellForm
 
-        return WcsCardInfoCellForm
+        return WcsCardCellForm
 
     def get_appearance_fields(self):
         return ['title_type', 'custom_title']
 
     def get_appearance_form_class(self):
-        from .forms import WcsCardInfoCellAppearanceBaseForm
+        from .forms import WcsCardCellAppearanceBaseForm
 
-        return super().get_appearance_form_class(base_options_form_class=WcsCardInfoCellAppearanceBaseForm)
+        return super().get_appearance_form_class(base_options_form_class=WcsCardCellAppearanceBaseForm)
 
     def get_manager_tabs(self):
-        from .forms import WcsCardInfoCellDisplayForm
+        from .forms import WcsCardCellDisplayForm
 
         tabs = super().get_manager_tabs()
         tabs.append(
             {
                 'slug': 'display',
                 'name': _('Display'),
-                'template': 'combo/wcs/manager/card-infos-cell-form-display.html',
-                'form': WcsCardInfoCellDisplayForm,
+                'template': 'combo/wcs/manager/card-cell-form-display.html',
+                'form': WcsCardCellDisplayForm,
             },
         )
         return tabs
@@ -1642,16 +1482,16 @@ class WcsCardInfosCell(CardMixin, CellBase):
         return custom_schema
 
     def get_asset_slot_key(self, key):
+        # for legacy
         if self.display_mode == 'table':
-            # for legacy: card cell with table mode should use assets of old cards cell
             return 'cell:wcs_wcscardscell:%s:%s' % (key, self.get_slug_for_asset())
-        return super().get_asset_slot_key(key)
+        return 'cell:wcs_wcscardinfoscell:%s:%s' % (key, self.get_slug_for_asset())
 
     def get_asset_slot_templates(self):
-        if self.display_mode == 'table' and settings.COMBO_CELL_ASSET_SLOTS.get('wcs_wcscardscell'):
-            # for legacy: card cell with table mode should use assets of old cards cell
-            return settings.COMBO_CELL_ASSET_SLOTS['wcs_wcscardscell']
-        return super().get_asset_slot_templates()
+        # for legacy
+        if self.display_mode == 'table':
+            return settings.COMBO_CELL_ASSET_SLOTS.get('wcs_wcscardscell')
+        return settings.COMBO_CELL_ASSET_SLOTS.get('wcs_wcscardinfoscell')
 
 
 @register_cell_class
diff --git a/combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-appearance.html b/combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-appearance.html
new file mode 100644
index 00000000..431b1ad9
--- /dev/null
+++ b/combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-appearance.html
@@ -0,0 +1,26 @@
+{% extends "combo/cell_appearance.html" %}
+
+{% block cell-form-appearance %}
+  {{ block.super }}
+  <script>
+    {# display/hide custom_title field #}
+    $('#id_cwcs_wcscardcell-{{ cell.pk }}-title_type').on('change', function() {
+      if ($(this).val() == 'manual') {
+        $('#id_cwcs_wcscardcell-{{ cell.pk }}-custom_title').parent().show();
+      } else {
+        $('#id_cwcs_wcscardcell-{{ cell.pk }}-custom_title').parent().hide();
+      }
+    });
+    $('#id_cwcs_wcscardcell-{{ cell.pk }}-title_type').change();
+
+    {# display/hide card_ids field #}
+    $('#id_cwcs_wcscardcell-{{ cell.pk }}-related_card_path').on('change', function() {
+      if (!$(this).val()) {
+        $('#id_cwcs_wcscardcell-{{ cell.pk }}-card_ids').parent().show();
+      } else {
+        $('#id_cwcs_wcscardcell-{{ cell.pk }}-card_ids').parent().hide();
+      }
+    });
+    $('#id_cwcs_wcscardcell-{{ cell.pk }}-related_card_path').change();
+  </script>
+{% endblock %}
diff --git a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-display.html b/combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-display.html
similarity index 90%
rename from combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-display.html
rename to combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-display.html
index 37998c9a..4cbbe086 100644
--- a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-display.html
+++ b/combo/apps/wcs/templates/combo/wcs/manager/card-cell-form-display.html
@@ -3,18 +3,18 @@
 {{ display_form.as_p }}
 <script>
   {# display/hide custom_schema fields #}
-  $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-display_mode').on('change', function() {
+  $('#id_cwcs_wcscardcell-{{ cell.pk }}-display_mode').on('change', function() {
     if ($(this).val() == 'card') {
-      $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-customize_display').parent().show();
-      if ($('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-customize_display').val()) {
-        $('.wcs-cards-cell--grid', $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-customize_display').parents('.cell')).show();
+      $('#id_cwcs_wcscardcell-{{ cell.pk }}-customize_display').parent().show();
+      if ($('#id_cwcs_wcscardcell-{{ cell.pk }}-customize_display').val()) {
+        $('.wcs-cards-cell--grid', $('#id_cwcs_wcscardcell-{{ cell.pk }}-customize_display').parents('.cell')).show();
       }
     } else {
-      $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-customize_display').parent().hide();
-      $('.wcs-cards-cell--grid', $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-customize_display').parents('.cell')).hide();
+      $('#id_cwcs_wcscardcell-{{ cell.pk }}-customize_display').parent().hide();
+      $('.wcs-cards-cell--grid', $('#id_cwcs_wcscardcell-{{ cell.pk }}-customize_display').parents('.cell')).hide();
     }
   });
-  $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-display_mode').change();
+  $('#id_cwcs_wcscardcell-{{ cell.pk }}-display_mode').change();
 </script>
 
 {% if card_schema %}
diff --git a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-appearance.html b/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-appearance.html
deleted file mode 100644
index 932974f7..00000000
--- a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form-appearance.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends "combo/cell_appearance.html" %}
-
-{% block cell-form-appearance %}
-  {{ block.super }}
-  <script>
-    {# display/hide custom_title field #}
-    $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-title_type').on('change', function() {
-      if ($(this).val() == 'manual') {
-        $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-custom_title').parent().show();
-      } else {
-        $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-custom_title').parent().hide();
-      }
-    });
-    $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-title_type').change();
-
-    {# display/hide card_ids field #}
-    $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-related_card_path').on('change', function() {
-      if (!$(this).val()) {
-        $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-card_ids').parent().show();
-      } else {
-        $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-card_ids').parent().hide();
-      }
-    });
-    $('#id_cwcs_wcscardinfoscell-{{ cell.pk }}-related_card_path').change();
-  </script>
-{% endblock %}
diff --git a/combo/manager/static/js/combo.manager.js b/combo/manager/static/js/combo.manager.js
index 00a44cc4..528a2308 100644
--- a/combo/manager/static/js/combo.manager.js
+++ b/combo/manager/static/js/combo.manager.js
@@ -455,7 +455,7 @@ $(function() {
 });
 
 
-// UI to customize the layout of the content of a wcs-card-infos-cell
+// UI to customize the layout of the content of a wcs-card-cell
 const Card_cell_custom = function(cell) {
   this.cell = cell;
   this.gridSchema_default = {
@@ -845,7 +845,7 @@ Card_cell_custom.prototype = {
 
 // Active custom card UI for each card cell
 $(function() {
-  $('.wcs-card-infos-cell').each(function(i, el) {
+  $('.wcs-card-cell').each(function(i, el) {
     const custom_card = new Card_cell_custom(el);
     $(el).on('combo:cellform-reloaded', function() {
       custom_card.init();
diff --git a/tests/test_manager.py b/tests/test_manager.py
index d5ce7d50..9440f3b6 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -1040,7 +1040,7 @@ def test_site_export_import_json(app, admin_user):
     resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json')
     with CaptureQueriesContext(connection) as ctx:
         resp = resp.form.submit()
-        assert len(ctx.captured_queries) in [314, 315]
+        assert len(ctx.captured_queries) in [304, 305]
     assert Page.objects.count() == 4
     assert PageSnapshot.objects.all().count() == 4
 
@@ -1051,7 +1051,7 @@ def test_site_export_import_json(app, admin_user):
     resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json')
     with CaptureQueriesContext(connection) as ctx:
         resp = resp.form.submit()
-        assert len(ctx.captured_queries) == 282
+        assert len(ctx.captured_queries) == 274
     assert set(Page.objects.get(slug='one').related_cells['cell_types']) == {'data_textcell', 'data_linkcell'}
     assert Page.objects.count() == 4
     assert LinkCell.objects.count() == 2
@@ -2447,7 +2447,7 @@ def test_page_versionning(app, admin_user):
 
     with CaptureQueriesContext(connection) as ctx:
         resp2 = resp.click('view', index=1)
-        assert len(ctx.captured_queries) == 72
+        assert len(ctx.captured_queries) == 70
     assert Page.snapshots.latest('pk').related_cells == {'cell_types': ['data_textcell']}
     assert resp2.text.index('Hello world') < resp2.text.index('Foobar3')
 
@@ -2508,7 +2508,7 @@ def test_page_versionning(app, admin_user):
     resp = resp.click('restore', index=6)
     with CaptureQueriesContext(connection) as ctx:
         resp = resp.form.submit().follow()
-        assert len(ctx.captured_queries) == 157
+        assert len(ctx.captured_queries) == 153
 
     resp2 = resp.click('See online')
     assert resp2.text.index('Foobar1') < resp2.text.index('Foobar2') < resp2.text.index('Foobar3')
diff --git a/tests/test_search.py b/tests/test_search.py
index bcd1cc5e..300ee521 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -1432,7 +1432,7 @@ def test_index_site_num_queries(settings, app):
     assert IndexedCell.objects.count() == 50
     with CaptureQueriesContext(connection) as ctx:
         index_site()
-        assert len(ctx.captured_queries) in (176, 226)  # (3.2, 2.2)
+        assert len(ctx.captured_queries) in (174, 224)  # (3.2, 2.2)
 
     SearchCell.objects.create(
         page=page, placeholder='content', order=0, _search_services={'data': ['search1']}
diff --git a/tests/wcs/test_all.py b/tests/wcs/test_all.py
index e363d6c2..57cff872 100644
--- a/tests/wcs/test_all.py
+++ b/tests/wcs/test_all.py
@@ -22,8 +22,7 @@ from combo.apps.wcs.models import (
     BackofficeSubmissionCell,
     CategoriesCell,
     TrackingCodeInputCell,
-    WcsCardInfosCell,
-    WcsCardsCell,
+    WcsCardCell,
     WcsCareFormsCell,
     WcsCategoryCell,
     WcsCurrentDraftsCell,
@@ -1234,337 +1233,6 @@ def test_manager_current_forms_tabs(app, admin_user):
     assert resp.pyquery('[data-tab-slug="appearance"] input[name$="custom_title"]')
 
 
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_manager_cards_cell(mock_send, app, admin_user):
-    page = Page.objects.create(title='xxx', slug='test_cards_cell_save_cache', template_name='standard')
-    cell = WcsCardsCell.objects.create(page=page, placeholder='content', order=0)
-    app = login(app)
-
-    resp = app.get('/manage/pages/%s/' % page.pk)
-    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
-
-
-def test_manager_cards_cell_tabs(app, admin_user):
-    page = Page.objects.create(title='xxx', slug='test_cards_cell_save_cache', template_name='standard')
-    cell = WcsCardsCell.objects.create(page=page, placeholder='content', order=0)
-    login(app)
-
-    resp = app.get('/manage/pages/%s/' % page.pk)
-
-    assert not resp.pyquery('[data-tab-slug="general"] input[name$="custom_title"]')
-    assert not resp.pyquery('#tab-%s-general.pk-tabs--button-marker' % cell.get_reference())
-    assert resp.pyquery('[data-tab-slug="appearance"] input[name$="custom_title"]')
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_setup(mock_send):
-    cell = WcsCardsCell()
-    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'),
-    ]
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_save_cache(mock_send):
-    page = Page.objects.create(title='xxx', slug='test_cards_cell_save_cache', template_name='standard')
-    cell = WcsCardsCell(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.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())
-
-    cell.carddef_reference = 'default:card_model_1:foo'
-    cell.save()
-    assert cell.cached_title == 'Card Model 1 - bar'
-    assert cell.get_additional_label() == 'Card Model 1 - bar'
-
-    # check content provided to search engine
-    assert cell.render_for_search() == ''
-
-    # artificially change title
-    WcsCardsCell.objects.filter(pk=cell.pk).update(cached_title='XXX')
-    assert WcsCardsCell.objects.get(pk=cell.pk).cached_title == 'XXX'
-    # run update db cache
-    appconfig = apps.get_app_config('wcs')
-    appconfig.update_db_cache()
-    assert WcsCardsCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1 - bar'
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_validity(mock_send):
-    page = Page.objects.create(title='xxx', template_name='standard')
-    cell = WcsCardsCell.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
-
-    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
-
-    cell.carddef_reference = 'default:card_model_1:foo'
-    cell.save()
-    assert ValidityInfo.objects.exists() is False
-
-    cell.carddef_reference = 'default:card_model_1:bar'
-    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_cards_cell_load(mock_send):
-    page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
-    cell = WcsCardsCell(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'
-
-    cell.carddef_reference = 'default:card_model_1:foo'
-    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 - bar'
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_render(mock_send, context):
-    page = Page.objects.create(title='xxx', template_name='standard')
-    cell = WcsCardsCell(page=page, placeholder='content', order=0)
-    cell.carddef_reference = 'default:card_model_1'
-    cell.save()
-
-    # query should fail as nothing is cached
-    cache.clear()
-    with pytest.raises(NothingInCacheException):
-        result = cell.render(context)
-
-    context['synchronous'] = True  # to get fresh content
-    context['cell'] = cell
-
-    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 - bar</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:
-        mock_json = mock.Mock(status_code=200)
-        requests_get.return_value = mock_json
-        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'
-    assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
-
-    cell.custom_title = 'Foo bar'
-    cell.save()
-    result = cell.render(context)
-    assert '<h2>Card Model 1 - bar</h2>' not in result
-    assert '<h2>Foo bar</h2>' in result
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_only_for_user(mock_send, context):
-    page = Page.objects.create(title='xxx', template_name='standard')
-    cell = WcsCardsCell(page=page, placeholder='content', order=0)
-    cell.carddef_reference = 'default:card_model_1'
-    cell.only_for_user = False
-    cell.save()
-
-    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
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_cards_cell_render_user(mock_send, context, nocache):
-    page = Page.objects.create(title='xxx', template_name='standard')
-    cell = WcsCardsCell(page=page, placeholder='content', order=0)
-    cell.carddef_reference = 'default:card_model_1'
-    cell.save()
-
-    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 = AnonymousUser()
-    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
-
-
 def test_tracking_code_cell(app, nocache):
     page = Page(title='One', slug='index', template_name='standard')
     page.save()
@@ -2177,7 +1845,7 @@ def test_hourly():
             WcsCurrentFormsCell,
             WcsCurrentDraftsCell,
             WcsFormsOfCategoryCell,
-            WcsCardInfosCell,
+            WcsCardCell,
             BackofficeSubmissionCell,
             CategoriesCell,
             TrackingCodeInputCell,
diff --git a/tests/wcs/test_card.py b/tests/wcs/test_card.py
index 8b9f4854..6dc79936 100644
--- a/tests/wcs/test_card.py
+++ b/tests/wcs/test_card.py
@@ -12,8 +12,8 @@ from pyquery import PyQuery
 from requests.exceptions import ConnectionError
 from requests.models import Response
 
-from combo.apps.wcs.forms import WcsCardInfoCellDisplayForm
-from combo.apps.wcs.models import WcsCardInfosCell
+from combo.apps.wcs.forms import WcsCardCellDisplayForm
+from combo.apps.wcs.models import WcsCardCell
 from combo.data.models import Page, TextCell, ValidityInfo
 from tests.test_manager import login
 from tests.utils import manager_submit_cell
@@ -28,7 +28,7 @@ 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 = WcsCardInfosCell(page=page, placeholder='content', order=0)
+    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 == [
@@ -54,7 +54,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
         ('other:card_e', 'test2 : Card E'),
     ]
 
-    form_display = WcsCardInfoCellDisplayForm(instance=cell)
+    form_display = WcsCardCellDisplayForm(instance=cell)
     assert 'customize_display' not in form_display.fields
     assert 'custom_schema' not in form_display.fields
 
@@ -64,7 +64,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
 
     cell.carddef_reference = 'default:card_model_1'
     cell.save()
-    form_display = WcsCardInfoCellDisplayForm(instance=cell)
+    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
@@ -72,7 +72,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
 
     cell.carddef_reference = 'default:card_model_1:foo'
     cell.save()
-    form_display = WcsCardInfoCellDisplayForm(instance=cell)
+    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
@@ -83,7 +83,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
 
     cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
     cell.save()
-    form_display = WcsCardInfoCellDisplayForm(instance=cell)
+    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
@@ -93,16 +93,14 @@ def test_card_cell_setup(mock_send, app, admin_user):
         ]
     }
 
-    WcsCardInfosCell.objects.all().delete()
+    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 Information Cell'][0].get(
-        'data-add-url'
-    )
+    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 = WcsCardInfosCell.objects.all().first()
+    cell = WcsCardCell.objects.all().first()
     manager_submit_cell(resp.forms[0])  # will save card model
     cell.refresh_from_db()
 
@@ -188,7 +186,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
 
 
 def test_card_cell_custom_schema_migration():
-    cell = WcsCardInfosCell()
+    cell = WcsCardCell()
 
     cell.custom_schema = {
         'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
@@ -261,7 +259,7 @@ def test_card_cell_custom_schema_migration():
 @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 = WcsCardInfosCell(page=page, placeholder='content', order=0)
+    cell = WcsCardCell(page=page, placeholder='content', order=0)
     assert cell.get_additional_label() is None
     cell.carddef_reference = 'default:card_model_1'
     cell.save()
@@ -272,20 +270,20 @@ def test_card_cell_save_cache(mock_send):
     assert 'cached_' not in json.dumps(page.get_serialized_page())
 
     # artificially change title and json
-    WcsCardInfosCell.objects.filter(pk=cell.pk).update(cached_title='XXX', cached_json={})
-    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'XXX'
-    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_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 WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1'
-    assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json != {}
+    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 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
+    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
@@ -329,14 +327,14 @@ def test_card_cell_validity(mock_send):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
         carddef_reference='default:card_a',
         card_ids='1',
     )
-    cell2 = WcsCardInfosCell.objects.create(
+    cell2 = WcsCardCell.objects.create(
         page=page, placeholder='content', order=1, carddef_reference='default:card_b'
     )
 
@@ -370,7 +368,7 @@ def test_card_cell_check_validity(mock_send):
 @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 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
+    cell = WcsCardCell.objects.create(page=page, placeholder='content', order=0)
 
     app = login(app)
     resp = app.get('/manage/pages/%s/' % page.pk)
@@ -414,7 +412,7 @@ def test_manager_card_cell(mock_send, app, admin_user):
     # add a second cell, related to the first card model
     cell.related_card_path = ''
     cell.save()
-    cell2 = WcsCardInfosCell.objects.create(
+    cell2 = WcsCardCell.objects.create(
         page=page, placeholder='content', order=1, carddef_reference='default:card_b'
     )
     resp = app.get('/manage/pages/%s/' % page.pk)
@@ -606,7 +604,7 @@ def test_manager_card_cell(mock_send, app, admin_user):
 @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 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
+    cell = WcsCardCell.objects.create(page=page, placeholder='content', order=0)
 
     app = login(app)
     resp = app.get('/manage/pages/%s/' % page.pk)
@@ -629,7 +627,7 @@ def test_manager_card_cell_tabs(mock_send, app, admin_user):
 @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 = WcsCardInfosCell(page=page, placeholder='content', order=0)
+    cell = WcsCardCell(page=page, placeholder='content', order=0)
     cell.carddef_reference = 'default:card_model_1'
     cell.save()
     site_export = [page.get_serialized_page()]
@@ -646,7 +644,7 @@ def test_card_cell_load(mock_send):
 @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(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -712,7 +710,7 @@ def test_card_cell_table_mode_render(mock_send, context, app):
 @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(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -743,7 +741,7 @@ 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(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -817,7 +815,7 @@ def test_card_cell_table_mode_render_identifier(mock_send, nocache, app):
 @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(
+    WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -826,7 +824,7 @@ def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache,
         carddef_reference='default:card_a',
         card_ids='1',
     )
-    cell2 = WcsCardInfosCell.objects.create(
+    cell2 = WcsCardCell.objects.create(
         page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
     )
 
@@ -876,7 +874,7 @@ def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache,
 @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(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -911,7 +909,7 @@ def test_card_cell_table_mode_render_title(mock_send, context):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1057,7 +1055,7 @@ def test_card_cell_card_mode_render(mock_send, context, app):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1093,7 +1091,7 @@ def test_card_cell_card_mode_render_text_field(mock_send, context):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1119,7 +1117,7 @@ def test_card_cell_card_mode_render_email_field(mock_send, context):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1147,7 +1145,7 @@ def test_card_cell_card_mode_render_string_with_url_field(mock_send, context):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1297,7 +1295,7 @@ def test_card_cell_card_mode_render_custom_schema_card_field(mock_send, context)
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1398,7 +1396,7 @@ def test_card_cell_card_mode_render_custom_schema_card_empty_field(mock_send, co
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1515,7 +1513,7 @@ def test_card_cell_card_mode_render_custom_schema_custom_entry(mock_send, contex
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1573,7 +1571,7 @@ def test_card_cell_card_mode_render_custom_schema_link_entry(mock_send, context,
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1611,7 +1609,7 @@ 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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page, placeholder='content', order=0, carddef_reference='default:card_model_1'
     )
 
@@ -1746,7 +1744,7 @@ def test_card_cell_card_mode_render_identifier(mock_send, nocache, app):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -1755,7 +1753,7 @@ def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache,
         carddef_reference='default:card_a',
         card_ids='1',
     )
-    cell2 = WcsCardInfosCell.objects.create(
+    cell2 = WcsCardCell.objects.create(
         page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
     )
 
@@ -1819,7 +1817,7 @@ def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache,
     failing(urls=[])
 
     # another cell with the same slug
-    cell3 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
+    cell3 = WcsCardCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
     cell2.related_card_path = 'sluga/foo'
     cell2.save()
     failing(urls=[])
@@ -1850,7 +1848,7 @@ def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache,
     cell.related_path = ''
     cell.save()
 
-    # another cell as the same slug, but not a WcsCardInfosCell
+    # 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)
@@ -2285,7 +2283,7 @@ def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache,
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -2332,7 +2330,7 @@ def test_card_cell_only_for_user(mock_send, context, carddef_reference):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -2392,7 +2390,7 @@ def test_card_cell_render_user(mock_send, context, nocache, carddef_reference):
 @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 = WcsCardInfosCell.objects.create(
+    cell = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -2453,7 +2451,7 @@ def test_cell_condition(mock_send, nocache, app):
 def test_card_file_redirection(mock_send, app):
     page = Page(title='One', slug='one', template_name='standard')
     page.save()
-    cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
+    cell = WcsCardCell(page=page, placeholder='content', order=0)
     cell.carddef_reference = 'default:card_model_1'
     cell.card_ids = '11'
     cell.save()
@@ -2476,7 +2474,7 @@ def test_card_file_redirection(mock_send, app):
 @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 = WcsCardInfosCell.objects.create(
+    cell1 = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
@@ -2484,7 +2482,7 @@ def test_card_cell_assets(mock_send, settings, app, admin_user):
         display_mode='card',
         slug='slug1',
     )
-    cell2 = WcsCardInfosCell.objects.create(
+    cell2 = WcsCardCell.objects.create(
         page=page,
         placeholder='content',
         order=0,
-- 
2.35.1

