From b4d9d2bbf3c3a3f081ab1c35e6caf291705370e7 Mon Sep 17 00:00:00 2001 From: Fabre Florian Date: Fri, 26 Sep 2025 14:30:59 +0200 Subject: [PATCH] WIP --- src/backend/core/apps.py | 19 ------------ src/backend/core/models.py | 20 ++++++++++++ src/backend/core/signals.py | 31 ------------------- src/backend/core/tasks/find.py | 12 +++---- .../core/tests/test_models_documents.py | 28 ++++++----------- 5 files changed, 36 insertions(+), 74 deletions(-) delete mode 100644 src/backend/core/apps.py delete mode 100644 src/backend/core/signals.py diff --git a/src/backend/core/apps.py b/src/backend/core/apps.py deleted file mode 100644 index b8ce64883..000000000 --- a/src/backend/core/apps.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Impress Core application""" - -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class CoreConfig(AppConfig): - """Configuration class for the impress core app.""" - - name = "core" - app_label = "core" - verbose_name = _("Impress core application") - - def ready(self): - """ - Import signals when the app is ready. - """ - # pylint: disable=import-outside-toplevel, unused-import - from . import signals # noqa: PLC0415 diff --git a/src/backend/core/models.py b/src/backend/core/models.py index e6e8f8442..67c3ab616 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -7,6 +7,7 @@ import hashlib import smtplib import uuid from datetime import timedelta +from functools import partial from logging import getLogger from django.conf import settings @@ -433,6 +434,8 @@ class Document(MP_Node, BaseModel): if self._content: self.save_content(self._content) + self.trigger_indexer() + def save_content(self, content): """Save content to object storage.""" @@ -460,6 +463,18 @@ class Document(MP_Node, BaseModel): content_file = ContentFile(bytes_content) default_storage.save(file_key, content_file) + def trigger_indexer(self): + """ + Asynchronously call to the document indexer at the end of the transaction. + Note : Within the transaction we can have an empty content and a serialization + error. + """ + # Prevents some circular imports + # pylint: disable=import-outside-toplevel + from core.tasks.find import trigger_document_indexer # noqa: PLC0415 + + transaction.on_commit(partial(trigger_document_indexer, self)) + def is_leaf(self): """ :returns: True if the node is has no children @@ -1051,9 +1066,14 @@ class DocumentAccess(BaseAccess): def save(self, *args, **kwargs): """Override save to clear the document's cache for number of accesses.""" + created = self.pk is None + super().save(*args, **kwargs) self.document.invalidate_nb_accesses_cache() + if not created: + self.document.trigger_indexer() + @property def target_key(self): """Get a unique key for the actor targeted by the access, without possible conflict.""" diff --git a/src/backend/core/signals.py b/src/backend/core/signals.py deleted file mode 100644 index 112a42f5b..000000000 --- a/src/backend/core/signals.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Declare and configure the signals for the impress core application -""" - -from functools import partial - -from django.db import transaction -from django.db.models import signals -from django.dispatch import receiver - -from . import models -from .tasks.find import trigger_document_indexer - - -@receiver(signals.post_save, sender=models.Document) -def document_post_save(sender, instance, **kwargs): # pylint: disable=unused-argument - """ - Asynchronous call to the document indexer at the end of the transaction. - Note : Within the transaction we can have an empty content and a serialization - error. - """ - transaction.on_commit(partial(trigger_document_indexer, instance)) - - -@receiver(signals.post_save, sender=models.DocumentAccess) -def document_access_post_save(sender, instance, created, **kwargs): # pylint: disable=unused-argument - """ - Asynchronous call to the document indexer at the end of the transaction. - """ - if not created: - transaction.on_commit(partial(trigger_document_indexer, instance.document)) diff --git a/src/backend/core/tasks/find.py b/src/backend/core/tasks/find.py index c9d36b157..611ca9b0f 100644 --- a/src/backend/core/tasks/find.py +++ b/src/backend/core/tasks/find.py @@ -3,7 +3,7 @@ from logging import getLogger from django.conf import settings -from django.core.cache import cache +from django.core.cache import cache as django_cache from impress.celery_app import app @@ -15,9 +15,9 @@ def indexer_debounce_lock(document_id): key = f"doc-indexer-debounce-{document_id}" try: - return cache.incr(key) + return django_cache.incr(key) except ValueError: - cache.set(key, 1) + django_cache.set(key, 1) return 1 @@ -26,9 +26,9 @@ def indexer_debounce_release(document_id): key = f"doc-indexer-debounce-{document_id}" try: - return cache.decr(key) + return django_cache.decr(key) except ValueError: - cache.set(key, 0) + django_cache.set(key, 0) return 0 @@ -37,7 +37,7 @@ def document_indexer_task(document_id): """Celery Task : Sends indexation query for a document.""" # Prevents some circular imports # pylint: disable=import-outside-toplevel - from core import models # noqa : PLC0415 + from core import models from core.services.search_indexers import ( # noqa : PLC0415 get_batch_accesses_by_users_and_teams, get_document_indexer, diff --git a/src/backend/core/tests/test_models_documents.py b/src/backend/core/tests/test_models_documents.py index 983b795cc..f459ae2c1 100644 --- a/src/backend/core/tests/test_models_documents.py +++ b/src/backend/core/tests/test_models_documents.py @@ -1488,6 +1488,10 @@ def test_models_documents_post_save_indexer_with_accesses(mock_push, indexer_set indexer.serialize_document(doc1, accesses), indexer.serialize_document(doc2, accesses), indexer.serialize_document(doc3, accesses), + # Called twice : one for the document.save(), one for the documentaccess.save() + indexer.serialize_document(doc1, accesses), + indexer.serialize_document(doc2, accesses), + indexer.serialize_document(doc3, accesses), ], key=itemgetter("id"), ) @@ -1504,8 +1508,6 @@ def test_models_documents_post_save_indexer_deleted(mock_push, indexer_settings) """Indexation task on deleted or ancestor_deleted documents""" indexer_settings.SEARCH_INDEXER_COUNTDOWN = 0 - user = factories.UserFactory() - with transaction.atomic(): doc = factories.DocumentFactory( link_reach=models.LinkReachChoices.AUTHENTICATED @@ -1520,10 +1522,6 @@ def test_models_documents_post_save_indexer_deleted(mock_push, indexer_settings) doc_deleted.soft_delete() doc_ancestor_deleted.ancestors_deleted_at = doc_deleted.deleted_at - factories.UserDocumentAccessFactory(document=doc, user=user) - factories.UserDocumentAccessFactory(document=doc_deleted, user=user) - factories.UserDocumentAccessFactory(document=doc_ancestor_deleted, user=user) - doc_deleted.refresh_from_db() doc_ancestor_deleted.refresh_from_db() @@ -1534,9 +1532,9 @@ def test_models_documents_post_save_indexer_deleted(mock_push, indexer_settings) assert doc_ancestor_deleted.ancestors_deleted_at is not None accesses = { - str(doc.path): {"users": [user.sub]}, - str(doc_deleted.path): {"users": [user.sub]}, - str(doc_ancestor_deleted.path): {"users": [user.sub]}, + str(doc.path): {"users": []}, + str(doc_deleted.path): {"users": []}, + str(doc_ancestor_deleted.path): {"users": []}, } data = [call.args[0] for call in mock_push.call_args_list] @@ -1566,8 +1564,6 @@ def test_models_documents_post_save_indexer_restored(mock_push, indexer_settings """Restart indexation task on restored documents""" indexer_settings.SEARCH_INDEXER_COUNTDOWN = 0 - user = factories.UserFactory() - with transaction.atomic(): doc = factories.DocumentFactory( link_reach=models.LinkReachChoices.AUTHENTICATED @@ -1582,10 +1578,6 @@ def test_models_documents_post_save_indexer_restored(mock_push, indexer_settings doc_deleted.soft_delete() doc_ancestor_deleted.ancestors_deleted_at = doc_deleted.deleted_at - factories.UserDocumentAccessFactory(document=doc, user=user) - factories.UserDocumentAccessFactory(document=doc_deleted, user=user) - factories.UserDocumentAccessFactory(document=doc_ancestor_deleted, user=user) - doc_deleted.refresh_from_db() doc_ancestor_deleted.refresh_from_db() @@ -1607,9 +1599,9 @@ def test_models_documents_post_save_indexer_restored(mock_push, indexer_settings assert doc_ancestor_restored.ancestors_deleted_at is None accesses = { - str(doc.path): {"users": [user.sub]}, - str(doc_deleted.path): {"users": [user.sub]}, - str(doc_ancestor_deleted.path): {"users": [user.sub]}, + str(doc.path): {"users": []}, + str(doc_deleted.path): {"users": []}, + str(doc_ancestor_deleted.path): {"users": []}, } data = [call.args[0] for call in mock_push.call_args_list]