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 django.db.utils import ProgrammingError
|
||||||
|
|
||||||
from documents.signals import document_consumer_declaration
|
from documents.signals import document_consumer_declaration
|
||||||
|
from documents.templatetags import convert_to_django_template_format
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
@ -69,3 +70,17 @@ def parser_check(app_configs, **kwargs):
|
|||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
return []
|
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 DocumentType
|
||||||
from documents.models import StoragePath
|
from documents.models import StoragePath
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
|
from documents.templatetags import convert_to_django_template_format
|
||||||
|
|
||||||
logger = logging.getLogger("paperless.filehandling")
|
logger = logging.getLogger("paperless.filehandling")
|
||||||
|
|
||||||
@ -112,29 +113,6 @@ def generate_unique_filename(doc, archive_filename=False):
|
|||||||
return new_filename
|
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():
|
def create_dummy_document():
|
||||||
"""
|
"""
|
||||||
Create a dummy Document instance with all possible fields filled
|
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(
|
def get_custom_fields_context(
|
||||||
custom_fields: Iterable[CustomFieldInstance],
|
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
|
Given an Iterable of CustomFieldInstance, builds a dictionary mapping the field name
|
||||||
to its type and value
|
to its type and value
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
pathvalidate.sanitize_filename(
|
"custom_fields": {
|
||||||
field_instance.field.name,
|
pathvalidate.sanitize_filename(
|
||||||
replacement_text="-",
|
field_instance.field.name,
|
||||||
): {
|
|
||||||
"type": pathvalidate.sanitize_filename(
|
|
||||||
field_instance.field.data_type,
|
|
||||||
replacement_text="-",
|
replacement_text="-",
|
||||||
),
|
): {
|
||||||
"value": pathvalidate.sanitize_filename(
|
"type": pathvalidate.sanitize_filename(
|
||||||
str(field_instance.value),
|
field_instance.field.data_type,
|
||||||
replacement_text="-",
|
replacement_text="-",
|
||||||
),
|
),
|
||||||
}
|
"value": pathvalidate.sanitize_filename(
|
||||||
for field_instance in custom_fields
|
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(
|
filename_format = convert_to_django_template_format(
|
||||||
settings.FILENAME_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:
|
else:
|
||||||
filename_format = None
|
filename_format = None
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ def convert_from_format_to_template(apps, schema_editor):
|
|||||||
|
|
||||||
StoragePath = apps.get_model("documents", "StoragePath")
|
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():
|
with transaction.atomic():
|
||||||
for storage_path in StoragePath.objects.all():
|
for storage_path in StoragePath.objects.all():
|
||||||
|
@ -29,8 +29,6 @@ from rest_framework import fields
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.fields import SerializerMethodField
|
from rest_framework.fields import SerializerMethodField
|
||||||
|
|
||||||
from documents.file_handling import convert_to_django_template_format
|
|
||||||
|
|
||||||
if settings.AUDIT_LOG_ENABLED:
|
if settings.AUDIT_LOG_ENABLED:
|
||||||
from auditlog.context import set_actor
|
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.parsers import is_mime_type_supported
|
||||||
from documents.permissions import get_groups_with_only_permission
|
from documents.permissions import get_groups_with_only_permission
|
||||||
from documents.permissions import set_permissions_for_object
|
from documents.permissions import set_permissions_for_object
|
||||||
|
from documents.templatetags import convert_to_django_template_format
|
||||||
from documents.validators import uri_validator
|
from documents.validators import uri_validator
|
||||||
|
|
||||||
logger = logging.getLogger("paperless.serializers")
|
logger = logging.getLogger("paperless.serializers")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
@ -26,7 +27,10 @@ class FilePathNode(template.Node):
|
|||||||
"""
|
"""
|
||||||
value = value.replace("\n", "").replace("\r", "")
|
value = value.replace("\n", "").replace("\r", "")
|
||||||
value = re.sub(r"\s*/\s*", "/", value)
|
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)
|
output = self.nodelist.render(context)
|
||||||
return clean_filepath(output)
|
return clean_filepath(output)
|
||||||
@ -41,3 +45,26 @@ def construct_filepath(parser, token):
|
|||||||
nodelist = parser.parse(("endfilepath",))
|
nodelist = parser.parse(("endfilepath",))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
return FilePathNode(nodelist)
|
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_year_short}/{created_month}/{created_month_name}"
|
||||||
"/{created_month_name_short}/{created_day}/{added}/{added_year}"
|
"/{created_month_name_short}/{created_day}/{added}/{added_year}"
|
||||||
"/{added_year_short}/{added_month}/{added_month_name}"
|
"/{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}/",
|
"/{tag_list}/{owner_username}/{original_name}/{doc_pk}/",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -6,6 +6,7 @@ from django.test import TestCase
|
|||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from documents.checks import changed_password_check
|
from documents.checks import changed_password_check
|
||||||
|
from documents.checks import filename_format_check
|
||||||
from documents.checks import parser_check
|
from documents.checks import parser_check
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
from documents.tests.factories import DocumentFactory
|
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