applications: search cell dependencies to pages and card models (#86520)

This commit is contained in:
Lauréline Guérin 2024-02-05 17:43:38 +01:00
parent 8f6ab11272
commit ea3d41d222
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 102 additions and 8 deletions

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import hashlib
from django import template
from django.contrib.auth.models import Group
from django.contrib.contenttypes import fields
@ -25,10 +27,12 @@ from django.db.models import JSONField
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from django.template import RequestContext, Template
from django.utils.encoding import force_bytes
from django.utils.functional import cached_property
from django.utils.http import quote
from django.utils.translation import gettext_lazy as _
from combo.apps.wcs.utils import get_wcs_dependency_from_carddef_reference, get_wcs_json, get_wcs_services
from combo.data.library import register_cell_class
from combo.data.models import CellBase, Page
from combo.utils import get_templated_url, requests
@ -328,6 +332,37 @@ class SearchCell(CellBase):
def missing_index(self):
return IndexedCell.objects.all().count() == 0
def get_dependencies(self):
yield from super().get_dependencies()
page_slugs = [
e['slug'].replace('_text_page_', '')
for e in self.search_services
if e['slug'].startswith('_text_page_')
]
yield from Page.objects.filter(sub_slug='', slug__in=page_slugs)
page_ids = [
e['options']['target_page']
for e in self.search_services
if (e.get('options') or {}).get('target_page')
]
yield from Page.objects.filter(pk__in=page_ids)
card_services = [
e['slug'].replace('__without-user__', '')
for e in self.search_services
if e['slug'].startswith('cards:')
]
for key, service in get_wcs_services().items():
card_models = get_wcs_json(service, 'api/cards/@list')
for card_model in card_models.get('data') or []:
service_key = 'cards:%s:%s' % (
hashlib.md5(force_bytes(key)).hexdigest()[:8],
card_model['id'],
)
if service_key in card_services:
yield get_wcs_dependency_from_carddef_reference(
'%s:%s' % (key, card_model['id']), card_model['text']
)
class IndexedCell(models.Model):
cell_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)

View File

@ -15,6 +15,7 @@ from django.core.files import File
from django.core.files.storage import default_storage
from combo.apps.export_import.models import Application, ApplicationAsyncJob, ApplicationElement
from combo.apps.search.models import SearchCell
from combo.apps.wcs.models import WcsCardCell, WcsCategoryCell, WcsFormCell
from combo.data.models import LinkCell, LinkListCell, Page, PageSnapshot, TextCell
@ -755,6 +756,52 @@ def test_page_dependencies_category_cell(mock_send):
} not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_search_cell(mock_send):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
page2 = Page.objects.create(title='second page', slug='second-page')
cell = SearchCell.objects.create(
page=page,
placeholder='content',
_search_services={'data': ['_text_page_second-page']},
order=0,
)
assert page2 in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page.get_dependencies()
cell.mark_as_valid()
cell._search_services = {'data': ['_text'], 'options': {'_text': {'target_page': page2.pk}}}
cell.save()
assert page2 in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page.get_dependencies()
cell.mark_as_valid()
Page.objects.create(slug='foo', title='Foo', sub_slug='card_model_1_id')
cell._search_services = {'data': ['cards:c21f969b:card_model_1']}
cell.save()
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell._search_services = {'data': ['cards:c21f969b:card_model_1__without-user__']}
cell.save()
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
def test_hourly(freezer):
job = ApplicationAsyncJob.objects.create(action='foo', bundle=File(io.BytesIO(b'test'), 'test.tar'))
ApplicationAsyncJob.objects.create(

View File

@ -91,14 +91,26 @@ WCS_USER_DRAFTS_DATA = [
]
WCS_CARDDEFS_DATA = [
{'title': 'Card Model 1', 'slug': 'card_model_1', 'custom_views': [{'id': 'foo', 'text': 'bar'}]},
{'title': 'Card Model 2', 'slug': 'card_model_2'},
{'title': 'Card Model 3', 'slug': 'card_model_3'},
{'title': 'Card A', 'slug': 'card_a'},
{'title': 'Card B', 'slug': 'card_b', 'custom_views': [{'id': 'a-custom-view', 'text': 'foo bar'}]},
{'title': 'Card C', 'slug': 'card_c'},
{'title': 'Card D', 'slug': 'card_d'},
{'title': 'Card E', 'slug': 'card-e'},
{
'title': 'Card Model 1',
'text': 'Card Model 1',
'slug': 'card_model_1',
'id': 'card_model_1',
'custom_views': [{'id': 'foo', 'text': 'bar'}],
},
{'title': 'Card Model 2', 'text': 'Card Model 2', 'slug': 'card_model_2', 'id': 'card_model_2'},
{'title': 'Card Model 3', 'text': 'Card Model 3', 'slug': 'card_model_3', 'id': 'card_model_3'},
{'title': 'Card A', 'text': 'Card A', 'slug': 'card_a', 'id': 'card_a'},
{
'title': 'Card B',
'text': 'Card B',
'slug': 'card_b',
'id': 'card_b',
'custom_views': [{'id': 'a-custom-view', 'text': 'foo bar'}],
},
{'title': 'Card C', 'text': 'Card C', 'slug': 'card_c', 'id': 'card_c'},
{'title': 'Card D', 'text': 'Card D', 'slug': 'card_d', 'id': 'card_d'},
{'title': 'Card E', 'text': 'Card E', 'slug': 'card-e', 'id': 'card_e'},
]
WCS_CARDS_DATA = {