moves to system check, fixes issue with not being a relative path
This commit is contained in:
parent
825f3d6380
commit
7189cec0be
@ -8,6 +8,7 @@ from django.db.utils import OperationalError
|
||||
from django.db.utils import ProgrammingError
|
||||
|
||||
from documents.signals import document_consumer_declaration
|
||||
from documents.templatetags import convert_to_django_template_format
|
||||
|
||||
|
||||
@register()
|
||||
@ -69,3 +70,17 @@ def parser_check(app_configs, **kwargs):
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
@register()
|
||||
def filename_format_check(app_configs, **kwargs):
|
||||
if settings.FILENAME_FORMAT:
|
||||
converted_format = convert_to_django_template_format(settings.FILENAME_FORMAT)
|
||||
if converted_format != settings.FILENAME_FORMAT:
|
||||
return [
|
||||
Error(
|
||||
f"Filename format {settings.FILENAME_FORMAT} is using the old style, please update to use double curly brackets",
|
||||
hint=converted_format,
|
||||
),
|
||||
]
|
||||
return []
|
||||
|
@ -17,6 +17,7 @@ from documents.models import Document
|
||||
from documents.models import DocumentType
|
||||
from documents.models import StoragePath
|
||||
from documents.models import Tag
|
||||
from documents.templatetags import convert_to_django_template_format
|
||||
|
||||
logger = logging.getLogger("paperless.filehandling")
|
||||
|
||||
@ -112,29 +113,6 @@ def generate_unique_filename(doc, archive_filename=False):
|
||||
return new_filename
|
||||
|
||||
|
||||
def convert_to_django_template_format(old_format: str) -> str:
|
||||
"""
|
||||
Converts old Python string format (with {}) to Django template style (with {{ }}),
|
||||
while ignoring existing {{ ... }} placeholders.
|
||||
|
||||
:param old_format: The old style format string (e.g., "{title} by {author}")
|
||||
:return: Converted string in Django Template style (e.g., "{{ title }} by {{ author }}")
|
||||
"""
|
||||
|
||||
# Step 1: Match placeholders with single curly braces but not those with double braces
|
||||
pattern = r"(?<!\{)\{(\w*)\}(?!\})" # Matches {var} but not {{var}}
|
||||
|
||||
# Step 2: Replace the placeholders with {{ var }} or {{ }}
|
||||
def replace_with_django(match):
|
||||
variable = match.group(1) # The variable inside the braces
|
||||
return f"{{{{ {variable} }}}}" # Convert to {{ variable }}
|
||||
|
||||
# Apply the substitution
|
||||
converted_format = re.sub(pattern, replace_with_django, old_format)
|
||||
|
||||
return converted_format
|
||||
|
||||
|
||||
def create_dummy_document():
|
||||
"""
|
||||
Create a dummy Document instance with all possible fields filled
|
||||
@ -258,26 +236,28 @@ def get_tags_context(tags: Iterable[Tag]) -> dict[str, str | list[str]]:
|
||||
|
||||
def get_custom_fields_context(
|
||||
custom_fields: Iterable[CustomFieldInstance],
|
||||
) -> dict[str, dict[str, str]]:
|
||||
) -> dict[str, dict[str, dict[str, str]]]:
|
||||
"""
|
||||
Given an Iterable of CustomFieldInstance, builds a dictionary mapping the field name
|
||||
to its type and value
|
||||
"""
|
||||
return {
|
||||
pathvalidate.sanitize_filename(
|
||||
field_instance.field.name,
|
||||
replacement_text="-",
|
||||
): {
|
||||
"type": pathvalidate.sanitize_filename(
|
||||
field_instance.field.data_type,
|
||||
"custom_fields": {
|
||||
pathvalidate.sanitize_filename(
|
||||
field_instance.field.name,
|
||||
replacement_text="-",
|
||||
),
|
||||
"value": pathvalidate.sanitize_filename(
|
||||
str(field_instance.value),
|
||||
replacement_text="-",
|
||||
),
|
||||
}
|
||||
for field_instance in custom_fields
|
||||
): {
|
||||
"type": pathvalidate.sanitize_filename(
|
||||
field_instance.field.data_type,
|
||||
replacement_text="-",
|
||||
),
|
||||
"value": pathvalidate.sanitize_filename(
|
||||
str(field_instance.value),
|
||||
replacement_text="-",
|
||||
),
|
||||
}
|
||||
for field_instance in custom_fields
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -401,14 +381,6 @@ def generate_filename(
|
||||
filename_format = convert_to_django_template_format(
|
||||
settings.FILENAME_FORMAT,
|
||||
)
|
||||
|
||||
# Warn the user they should update
|
||||
# TODO: Move this to system check
|
||||
if filename_format != settings.FILENAME_FORMAT:
|
||||
logger.warning(
|
||||
f"Filename format {settings.FILENAME_FORMAT} is using the old style, please update to use double curly brackets",
|
||||
)
|
||||
logger.info(filename_format)
|
||||
else:
|
||||
filename_format = None
|
||||
|
||||
|
@ -10,7 +10,7 @@ def convert_from_format_to_template(apps, schema_editor):
|
||||
|
||||
StoragePath = apps.get_model("documents", "StoragePath")
|
||||
|
||||
from documents.file_handling import convert_to_django_template_format
|
||||
from documents.templatetags import convert_to_django_template_format
|
||||
|
||||
with transaction.atomic():
|
||||
for storage_path in StoragePath.objects.all():
|
||||
|
@ -29,8 +29,6 @@ from rest_framework import fields
|
||||
from rest_framework import serializers
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
|
||||
from documents.file_handling import convert_to_django_template_format
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
from auditlog.context import set_actor
|
||||
|
||||
@ -56,6 +54,7 @@ from documents.models import WorkflowTrigger
|
||||
from documents.parsers import is_mime_type_supported
|
||||
from documents.permissions import get_groups_with_only_permission
|
||||
from documents.permissions import set_permissions_for_object
|
||||
from documents.templatetags import convert_to_django_template_format
|
||||
from documents.validators import uri_validator
|
||||
|
||||
logger = logging.getLogger("paperless.serializers")
|
||||
|
@ -1,3 +1,4 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from django import template
|
||||
@ -26,7 +27,10 @@ class FilePathNode(template.Node):
|
||||
"""
|
||||
value = value.replace("\n", "").replace("\r", "")
|
||||
value = re.sub(r"\s*/\s*", "/", value)
|
||||
return value.strip()
|
||||
|
||||
# We remove trailing and leading separators, as these are always relative paths, not absolute, even if the user
|
||||
# tries
|
||||
return value.strip().strip(os.sep)
|
||||
|
||||
output = self.nodelist.render(context)
|
||||
return clean_filepath(output)
|
||||
@ -41,3 +45,26 @@ def construct_filepath(parser, token):
|
||||
nodelist = parser.parse(("endfilepath",))
|
||||
parser.delete_first_token()
|
||||
return FilePathNode(nodelist)
|
||||
|
||||
|
||||
def convert_to_django_template_format(old_format: str) -> str:
|
||||
"""
|
||||
Converts old Python string format (with {}) to Django template style (with {{ }}),
|
||||
while ignoring existing {{ ... }} placeholders.
|
||||
|
||||
:param old_format: The old style format string (e.g., "{title} by {author}")
|
||||
:return: Converted string in Django Template style (e.g., "{{ title }} by {{ author }}")
|
||||
"""
|
||||
|
||||
# Step 1: Match placeholders with single curly braces but not those with double braces
|
||||
pattern = r"(?<!\{)\{(\w*)\}(?!\})" # Matches {var} but not {{var}}
|
||||
|
||||
# Step 2: Replace the placeholders with {{ var }} or {{ }}
|
||||
def replace_with_django(match):
|
||||
variable = match.group(1) # The variable inside the braces
|
||||
return f"{{{{ {variable} }}}}" # Convert to {{ variable }}
|
||||
|
||||
# Apply the substitution
|
||||
converted_format = re.sub(pattern, replace_with_django, old_format)
|
||||
|
||||
return converted_format
|
||||
|
@ -239,7 +239,7 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
|
||||
"/{created_year_short}/{created_month}/{created_month_name}"
|
||||
"/{created_month_name_short}/{created_day}/{added}/{added_year}"
|
||||
"/{added_year_short}/{added_month}/{added_month_name}"
|
||||
"/{added_month_name_short}/{added_day}/{asn}/{tags}"
|
||||
"/{added_month_name_short}/{added_day}/{asn}"
|
||||
"/{tag_list}/{owner_username}/{original_name}/{doc_pk}/",
|
||||
},
|
||||
),
|
||||
|
@ -6,6 +6,7 @@ from django.test import TestCase
|
||||
from django.test import override_settings
|
||||
|
||||
from documents.checks import changed_password_check
|
||||
from documents.checks import filename_format_check
|
||||
from documents.checks import parser_check
|
||||
from documents.models import Document
|
||||
from documents.tests.factories import DocumentFactory
|
||||
@ -73,3 +74,17 @@ class TestDocumentChecks(TestCase):
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
def test_filename_format_check(self):
|
||||
self.assertEqual(filename_format_check(None), [])
|
||||
|
||||
with override_settings(FILENAME_FORMAT="{created}/{title}"):
|
||||
self.assertEqual(
|
||||
filename_format_check(None),
|
||||
[
|
||||
Error(
|
||||
"Filename format {created}/{title} is using the old style, please update to use double curly brackets",
|
||||
hint="{{ created }}/{{ title }}",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user