mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-10 01:01:17 -06:00
Compare commits
1 Commits
dependabot
...
feature/cf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30dec919fb |
@@ -32,7 +32,7 @@ RUN set -eux \
|
|||||||
# Purpose: Installs s6-overlay and rootfs
|
# Purpose: Installs s6-overlay and rootfs
|
||||||
# Comments:
|
# Comments:
|
||||||
# - Don't leave anything extra in here either
|
# - Don't leave anything extra in here either
|
||||||
FROM ghcr.io/astral-sh/uv:0.9.16-python3.12-trixie-slim AS s6-overlay-base
|
FROM ghcr.io/astral-sh/uv:0.9.15-python3.12-trixie-slim AS s6-overlay-base
|
||||||
|
|
||||||
WORKDIR /usr/src/s6
|
WORKDIR /usr/src/s6
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ from documents.models import WorkflowRun
|
|||||||
from documents.models import WorkflowTrigger
|
from documents.models import WorkflowTrigger
|
||||||
from documents.permissions import get_objects_for_user_owner_aware
|
from documents.permissions import get_objects_for_user_owner_aware
|
||||||
from documents.permissions import set_permissions_for_object
|
from documents.permissions import set_permissions_for_object
|
||||||
|
from documents.templating.utils import convert_format_str_to_template_format
|
||||||
from documents.templating.workflows import parse_w_workflow_placeholders
|
from documents.templating.workflows import parse_w_workflow_placeholders
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -392,6 +393,19 @@ class CannotMoveFilesException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _filename_template_uses_custom_fields(doc: Document) -> bool:
|
||||||
|
template = None
|
||||||
|
if doc.storage_path is not None:
|
||||||
|
template = doc.storage_path.path
|
||||||
|
elif settings.FILENAME_FORMAT is not None:
|
||||||
|
template = convert_format_str_to_template_format(settings.FILENAME_FORMAT)
|
||||||
|
|
||||||
|
if not template:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return "custom_fields" in template
|
||||||
|
|
||||||
|
|
||||||
# should be disabled in /src/documents/management/commands/document_importer.py handle
|
# should be disabled in /src/documents/management/commands/document_importer.py handle
|
||||||
@receiver(models.signals.post_save, sender=CustomFieldInstance, weak=False)
|
@receiver(models.signals.post_save, sender=CustomFieldInstance, weak=False)
|
||||||
@receiver(models.signals.m2m_changed, sender=Document.tags.through, weak=False)
|
@receiver(models.signals.m2m_changed, sender=Document.tags.through, weak=False)
|
||||||
@@ -402,6 +416,8 @@ def update_filename_and_move_files(
|
|||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
if isinstance(instance, CustomFieldInstance):
|
if isinstance(instance, CustomFieldInstance):
|
||||||
|
if not _filename_template_uses_custom_fields(instance.document):
|
||||||
|
return
|
||||||
instance = instance.document
|
instance = instance.document
|
||||||
|
|
||||||
def validate_move(instance, old_path: Path, new_path: Path):
|
def validate_move(instance, old_path: Path, new_path: Path):
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from django.utils import timezone
|
|||||||
from documents.file_handling import create_source_path_directory
|
from documents.file_handling import create_source_path_directory
|
||||||
from documents.file_handling import delete_empty_directories
|
from documents.file_handling import delete_empty_directories
|
||||||
from documents.file_handling import generate_filename
|
from documents.file_handling import generate_filename
|
||||||
|
from documents.file_handling import generate_unique_filename
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
from documents.models import CustomField
|
from documents.models import CustomField
|
||||||
from documents.models import CustomFieldInstance
|
from documents.models import CustomFieldInstance
|
||||||
@@ -1632,6 +1633,73 @@ class TestFilenameGeneration(DirectoriesMixin, TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCustomFieldFilenameUpdates(
|
||||||
|
DirectoriesMixin,
|
||||||
|
FileSystemAssertsMixin,
|
||||||
|
TestCase,
|
||||||
|
):
|
||||||
|
def setUp(self):
|
||||||
|
self.cf = CustomField.objects.create(
|
||||||
|
name="flavor",
|
||||||
|
data_type=CustomField.FieldDataType.STRING,
|
||||||
|
)
|
||||||
|
self.doc = Document.objects.create(
|
||||||
|
title="document",
|
||||||
|
mime_type="application/pdf",
|
||||||
|
checksum="abc123",
|
||||||
|
)
|
||||||
|
self.cfi = CustomFieldInstance.objects.create(
|
||||||
|
field=self.cf,
|
||||||
|
document=self.doc,
|
||||||
|
value_text="initial",
|
||||||
|
)
|
||||||
|
return super().setUp()
|
||||||
|
|
||||||
|
@override_settings(FILENAME_FORMAT=None)
|
||||||
|
def test_custom_field_not_in_template_skips_filename_work(self):
|
||||||
|
storage_path = StoragePath.objects.create(path="{{created}}/{{ title }}")
|
||||||
|
self.doc.storage_path = storage_path
|
||||||
|
self.doc.save()
|
||||||
|
initial_filename = generate_filename(self.doc)
|
||||||
|
Document.objects.filter(pk=self.doc.pk).update(filename=str(initial_filename))
|
||||||
|
self.doc.refresh_from_db()
|
||||||
|
Path(self.doc.source_path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
Path(self.doc.source_path).touch()
|
||||||
|
|
||||||
|
with mock.patch("documents.signals.handlers.generate_unique_filename") as m:
|
||||||
|
m.side_effect = generate_unique_filename
|
||||||
|
self.cfi.value_text = "updated"
|
||||||
|
self.cfi.save()
|
||||||
|
|
||||||
|
self.doc.refresh_from_db()
|
||||||
|
self.assertEqual(Path(self.doc.filename), initial_filename)
|
||||||
|
self.assertEqual(m.call_count, 0)
|
||||||
|
|
||||||
|
@override_settings(FILENAME_FORMAT=None)
|
||||||
|
def test_custom_field_in_template_triggers_filename_update(self):
|
||||||
|
storage_path = StoragePath.objects.create(
|
||||||
|
path="{{ custom_fields|get_cf_value('flavor') }}/{{ title }}",
|
||||||
|
)
|
||||||
|
self.doc.storage_path = storage_path
|
||||||
|
self.doc.save()
|
||||||
|
initial_filename = generate_filename(self.doc)
|
||||||
|
Document.objects.filter(pk=self.doc.pk).update(filename=str(initial_filename))
|
||||||
|
self.doc.refresh_from_db()
|
||||||
|
Path(self.doc.source_path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
Path(self.doc.source_path).touch()
|
||||||
|
|
||||||
|
with mock.patch("documents.signals.handlers.generate_unique_filename") as m:
|
||||||
|
m.side_effect = generate_unique_filename
|
||||||
|
self.cfi.value_text = "updated"
|
||||||
|
self.cfi.save()
|
||||||
|
|
||||||
|
self.doc.refresh_from_db()
|
||||||
|
expected_filename = Path("updated/document.pdf")
|
||||||
|
self.assertEqual(Path(self.doc.filename), expected_filename)
|
||||||
|
self.assertTrue(Path(self.doc.source_path).is_file())
|
||||||
|
self.assertGreater(m.call_count, 0)
|
||||||
|
|
||||||
|
|
||||||
class TestPathDateLocalization:
|
class TestPathDateLocalization:
|
||||||
"""
|
"""
|
||||||
Groups all tests related to the `localize_date` function.
|
Groups all tests related to the `localize_date` function.
|
||||||
|
|||||||
Reference in New Issue
Block a user