(backend) refactor indexation signals and fix circular import issues

Signed-off-by: Fabre Florian <ffabre@hybird.org>
This commit is contained in:
Fabre Florian
2025-09-12 14:11:23 +02:00
committed by Quentin BEY
parent 24460ffc3a
commit bf978b5376
7 changed files with 57 additions and 39 deletions

View File

@@ -9,6 +9,9 @@ and this project adheres to
### Added
- ✨(backend) allow to create a new user in a marketing system
- ✨(backend) add async indexation of documents on save (or access save) #1276
- ✨(backend) add debounce mechanism to limit indexation jobs #1276
- ✨(api) add API route to search for indexed documents in Find #1276
### Changed

View File

@@ -1,11 +1,19 @@
"""Impress Core application"""
# from django.apps import AppConfig
# from django.utils.translation import gettext_lazy as _
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
# class CoreConfig(AppConfig):
# """Configuration class for the impress core app."""
class CoreConfig(AppConfig):
"""Configuration class for the impress core app."""
# name = "core"
# app_label = "core"
# verbose_name = _("impress core application")
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

View File

@@ -20,9 +20,7 @@ from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.core.mail import send_mail
from django.db import models, transaction
from django.db.models import signals
from django.db.models.functions import Left, Length
from django.dispatch import receiver
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.functional import cached_property
@@ -41,7 +39,6 @@ from .choices import (
RoleChoices,
get_equivalent_link_definition,
)
from .tasks.find import trigger_document_indexer
from .validators import sub_validator
logger = getLogger(__name__)
@@ -955,16 +952,6 @@ class Document(MP_Node, BaseModel):
)
@receiver(signals.post_save, sender=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.
"""
trigger_document_indexer(instance, on_commit=True)
class LinkTrace(BaseModel):
"""
Relation model to trace accesses to a document via a link by a logged-in user.
@@ -1195,15 +1182,6 @@ class DocumentAccess(BaseAccess):
}
@receiver(signals.post_save, sender=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:
trigger_document_indexer(instance.document, on_commit=True)
class DocumentAskForAccess(BaseModel):
"""Relation model to ask for access to a document."""

View File

@@ -0,0 +1,28 @@
"""
Declare and configure the signals for the impress core application
"""
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.
"""
trigger_document_indexer(instance, on_commit=True)
@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:
trigger_document_indexer(instance.document, on_commit=True)

View File

@@ -7,12 +7,6 @@ from django.conf import settings
from django.core.cache import cache
from django.db import transaction
from core import models
from core.services.search_indexers import (
get_batch_accesses_by_users_and_teams,
get_document_indexer_class,
)
from impress.celery_app import app
logger = getLogger(__file__)
@@ -52,6 +46,13 @@ def document_indexer_task(document_id):
logger.info("Skip document %s indexation", document_id)
return
# pylint: disable=import-outside-toplevel
from core import models # noqa: PLC0415
from core.services.search_indexers import ( # noqa: PLC0415
get_batch_accesses_by_users_and_teams,
get_document_indexer_class,
)
doc = models.Document.objects.get(pk=document_id)
indexer = get_document_indexer_class()()
accesses = get_batch_accesses_by_users_and_teams((doc.path,))

View File

@@ -3,11 +3,11 @@ Unit tests for the Document model
"""
# pylint: disable=too-many-lines
from operator import itemgetter
import random
import smtplib
import time
from logging import Logger
from operator import itemgetter
from unittest import mock
from django.contrib.auth.models import AnonymousUser
@@ -1651,13 +1651,13 @@ def test_models_documents_post_save_indexer(mock_push, settings):
indexer = FindDocumentIndexer()
assert sorted(data, key=itemgetter('id')) == sorted(
assert sorted(data, key=itemgetter("id")) == sorted(
[
indexer.serialize_document(doc1, accesses),
indexer.serialize_document(doc2, accesses),
indexer.serialize_document(doc3, accesses),
],
key=itemgetter('id'),
key=itemgetter("id"),
)
# The debounce counters should be reset

View File

@@ -36,7 +36,6 @@ class FakeDocumentIndexer(BaseDocumentIndexer):
return {}
@pytest.fixture(name="fake_indexer_settings")
def fake_indexer_settings_fixture(settings):
"""Fixture to switch the indexer to the FakeDocumentIndexer."""
@@ -103,6 +102,7 @@ def test_services_search_indexer_class(fake_indexer_settings):
"core.tests.test_services_search_indexers.FakeDocumentIndexer"
)
def test_services_search_indexer_url_is_none(settings):
"""
Indexer should raise RuntimeError if SEARCH_INDEXER_URL is None or empty.