Adds owner and original name to the possible naming schemes

This commit is contained in:
Trenton Holmes 2023-03-11 17:43:58 -08:00 committed by Trenton H
parent ef6c4e6789
commit 97ff2e126c
5 changed files with 121 additions and 7 deletions

View File

@ -309,6 +309,8 @@ Paperless provides the following placeholders within filenames:
- `{added_month_name_short}`: Month added abbreviated name, as per
locale
- `{added_day}`: Day added only (number 01-31).
- `{owner_username}`: Username of document owner, if any, or "none"
- `{original_name}`: Document original filename, minus the extension, if any, or "none"
Paperless will try to conserve the information from your database as
much as possible. However, some characters that you can use in document

View File

@ -1,12 +1,13 @@
import logging
import os
from collections import defaultdict
from pathlib import PurePath
import pathvalidate
from django.conf import settings
from django.template.defaultfilters import slugify
from django.utils import timezone
from documents.models import Document
logger = logging.getLogger("paperless.filehandling")
@ -125,7 +126,12 @@ def generate_unique_filename(doc, archive_filename=False):
return new_filename
def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
def generate_filename(
doc: Document,
counter=0,
append_gpg=True,
archive_filename=False,
):
path = ""
filename_format = settings.FILENAME_FORMAT
@ -150,13 +156,15 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
replacement_text="-",
)
no_value_default = "-none-"
if doc.correspondent:
correspondent = pathvalidate.sanitize_filename(
doc.correspondent.name,
replacement_text="-",
)
else:
correspondent = "-none-"
correspondent = no_value_default
if doc.document_type:
document_type = pathvalidate.sanitize_filename(
@ -164,12 +172,23 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
replacement_text="-",
)
else:
document_type = "-none-"
document_type = no_value_default
if doc.archive_serial_number:
asn = str(doc.archive_serial_number)
else:
asn = "-none-"
asn = no_value_default
if doc.owner is not None:
owner_username_str = str(doc.owner.username)
else:
owner_username_str = no_value_default
if doc.original_filename is not None:
# No extension
original_name = PurePath(doc.original_filename).with_suffix("").name
else:
original_name = no_value_default
# Convert UTC database datetime to localized date
local_added = timezone.localdate(doc.added)
@ -196,6 +215,8 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
asn=asn,
tags=tags,
tag_list=tag_list,
owner_username=owner_username_str,
original_name=original_name,
).strip()
if settings.FILENAME_FORMAT_REMOVE_NONE:

View File

@ -818,6 +818,8 @@ class StoragePathSerializer(MatchingModelSerializer, OwnedObjectSerializer):
asn="asn",
tags="tags",
tag_list="tag_list",
owner_username="someone",
original_name="testfile",
)
except (KeyError):

View File

@ -20,8 +20,6 @@ except ImportError:
import backports.zoneinfo as zoneinfo
import pytest
from django.db import transaction
from django.db.utils import IntegrityError
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.auth.models import Permission

View File

@ -5,6 +5,7 @@ from pathlib import Path
from unittest import mock
from django.conf import settings
from django.contrib.auth.models import User
from django.db import DatabaseError
from django.test import override_settings
from django.test import TestCase
@ -1059,3 +1060,93 @@ class TestFilenameGeneration(DirectoriesMixin, TestCase):
checksum="2",
)
self.assertEqual(generate_filename(doc), "84/August/Aug/The Title.pdf")
@override_settings(
FILENAME_FORMAT="{owner_username}/{title}",
)
def test_document_owner_string(self):
"""
GIVEN:
- Document with an other
- Document without an owner
- Filename format string includes owner
WHEN:
- Filename is generated for each document
THEN:
- Owned document includes username
- Document without owner returns "none"
"""
u1 = User.objects.create_user("user1")
owned_doc = Document.objects.create(
title="The Title",
mime_type="application/pdf",
checksum="2",
owner=u1,
)
no_owner_doc = Document.objects.create(
title="does matter",
mime_type="application/pdf",
checksum="3",
)
self.assertEqual(generate_filename(owned_doc), "user1/The Title.pdf")
self.assertEqual(generate_filename(no_owner_doc), "none/does matter.pdf")
@override_settings(
FILENAME_FORMAT="{original_name}",
)
def test_document_original_filename(self):
"""
GIVEN:
- Document with an original filename
- Document without an original filename
- Document which was plain text document
- Filename format string includes original filename
WHEN:
- Filename is generated for each document
THEN:
- Document with original name uses it, dropping suffix
- Document without original name returns "none"
- Text document returns extension of .txt
- Text document archive returns extension of .pdf
- No extensions are doubled
"""
doc_with_original = Document.objects.create(
title="does matter",
mime_type="application/pdf",
checksum="3",
original_filename="someepdf.pdf",
)
tricky_with_original = Document.objects.create(
title="does matter",
mime_type="application/pdf",
checksum="1",
original_filename="some pdf with spaces and stuff.pdf",
)
no_original = Document.objects.create(
title="does matter",
mime_type="application/pdf",
checksum="2",
)
text_doc = Document.objects.create(
title="does matter",
mime_type="text/plain",
checksum="4",
original_filename="logs.txt",
)
self.assertEqual(generate_filename(doc_with_original), "someepdf.pdf")
self.assertEqual(
generate_filename(tricky_with_original),
"some pdf with spaces and stuff.pdf",
)
self.assertEqual(generate_filename(no_original), "none.pdf")
self.assertEqual(generate_filename(text_doc), "logs.txt")
self.assertEqual(generate_filename(text_doc, archive_filename=True), "logs.pdf")