Support title assignment in consumption templates

This commit is contained in:
shamoon 2023-09-16 23:38:29 -07:00
parent c12e1f8732
commit 1aa0792b88
7 changed files with 78 additions and 22 deletions

View File

@ -15,6 +15,7 @@
<pngx-input-text i18n-title title="Filter path" formControlName="filter_path" i18n-hint hint="Apply template to documents that match this path. Wildcards specified as * are allowed. Case insensitive." [error]="error?.filter_path"></pngx-input-text>
</div>
<div class="col">
<pngx-input-text i18n-title title="Assign title" formControlName="assign_title" i18n-hint hint="Assign a document title, can include some placeholders, see documentation." [error]="error?.assign_title"></pngx-input-text>
<pngx-input-tags [allowCreate]="false" i18n-title title="Assign tags" formControlName="assign_tags"></pngx-input-tags>
<pngx-input-select i18n-title title="Assign document type" [items]="documentTypes" [allowNull]="true" formControlName="assign_document_type"></pngx-input-select>
<pngx-input-select i18n-title title="Assign correspondent" [items]="correspondents" [allowNull]="true" formControlName="assign_correspondent"></pngx-input-select>

View File

@ -86,15 +86,16 @@ export class ConsumptionTemplateEditDialogComponent extends EditDialogComponent<
filter_path: new FormControl(null),
order: new FormControl(null),
sources: new FormControl([]),
assign_title: new FormControl(null),
assign_tags: new FormControl([]),
assign_owner: new FormControl(null),
assign_document_type: new FormControl(null),
assign_correspondent: new FormControl(null),
assign_storage_path: new FormControl(null),
assign_view_users: new FormControl(null),
assign_view_groups: new FormControl(null),
assign_change_users: new FormControl(null),
assign_change_groups: new FormControl(null),
assign_view_users: new FormControl([]),
assign_view_groups: new FormControl([]),
assign_change_users: new FormControl([]),
assign_change_groups: new FormControl([]),
})
}

View File

@ -17,6 +17,8 @@ export interface PaperlessConsumptionTemplate extends ObjectWithPermissions {
filter_path: string
assign_title?: string
assign_tags?: number[] // PaperlessTag.id
assign_document_type?: number // PaperlessDocumentType.id

View File

@ -602,7 +602,7 @@ class Consumer(LoggingMixin):
for template in ConsumptionTemplate.objects.all().order_by("order"):
template_overrides = DocumentMetadataOverrides()
if int(input_doc.source) in list(template.sources) and (
if int(input_doc.source) in [int(x) for x in list(template.sources)] and (
(
template.filter_filename is not None
and fnmatch(
@ -616,6 +616,8 @@ class Consumer(LoggingMixin):
)
):
self.log.info(f"Document matched consumption template {template.name}")
if template.assign_title is not None:
template_overrides.title = template.assign_title
if template.assign_tags is not None:
template_overrides.tag_ids = [
tag.pk for tag in template.assign_tags.all()
@ -654,6 +656,38 @@ class Consumer(LoggingMixin):
)
return overrides
def _parse_title_placeholders(self, title: str) -> str:
local_added = timezone.now()
correspondent_name = (
Correspondent.objects.get(pk=self.override_correspondent_id).name
if self.override_correspondent_id is not None
else None
)
doc_type_name = (
DocumentType.objects.get(pk=self.override_document_type_id).name
if self.override_correspondent_id is not None
else None
)
owner_username = (
User.objects.get(pk=self.override_owner_id).username
if self.override_owner_id is not None
else None
)
return title.format(
correspondent=correspondent_name or None,
document_type=doc_type_name or None,
added=local_added.isoformat(),
added_year=local_added.strftime("%Y"),
added_year_short=local_added.strftime("%y"),
added_month=local_added.strftime("%m"),
added_month_name=local_added.strftime("%B"),
added_month_name_short=local_added.strftime("%b"),
added_day=local_added.strftime("%d"),
owner_username=owner_username or None,
).strip()
def _store(
self,
text: str,
@ -686,9 +720,15 @@ class Consumer(LoggingMixin):
storage_type = Document.STORAGE_TYPE_UNENCRYPTED
print("override_title", self.override_title)
with open(self.path, "rb") as f:
document = Document.objects.create(
title=(self.override_title or file_info.title)[:127],
title=(
self._parse_title_placeholders(self.override_title)
if self.override_title is not None
else file_info.title
)[:127],
content=text,
mime_type=mime_type,
checksum=hashlib.md5(f.read()).hexdigest(),
@ -800,6 +840,8 @@ def merge_overrides(
overridesA: DocumentMetadataOverrides,
overridesB: DocumentMetadataOverrides,
) -> DocumentMetadataOverrides:
if overridesA.title is None:
overridesA.title = overridesB.title
if overridesA.tag_ids is None:
overridesA.tag_ids = overridesB.tag_ids
if overridesA.correspondent_id is None:

View File

@ -167,6 +167,16 @@ class Migration(migrations.Migration):
verbose_name="assign this tag",
),
),
(
"assign_title",
models.CharField(
blank=True,
help_text="Assign a document title, can include some placeholders, see documentation.",
max_length=256,
null=True,
verbose_name="assign title",
),
),
(
"assign_view_groups",
models.ManyToManyField(

View File

@ -786,6 +786,17 @@ class ConsumptionTemplate(ModelWithOwner):
),
)
assign_title = models.CharField(
_("assign title"),
max_length=256,
null=True,
blank=True,
help_text=_(
"Assign a document title, can include some placeholders,"
"see documentation.",
),
)
assign_tags = models.ManyToManyField(
Tag,
blank=True,

View File

@ -1066,6 +1066,7 @@ class ConsumptionTemplateSerializer(OwnedObjectSerializer):
"sources",
"filter_path",
"filter_filename",
"assign_title",
"assign_tags",
"assign_correspondent",
"assign_document_type",
@ -1085,20 +1086,8 @@ class ConsumptionTemplateSerializer(OwnedObjectSerializer):
super().update(instance, validated_data)
return instance
# def create(self, validated_data):
# if "assign_tags" in validated_data:
# assign_tags = validated_data.pop("assign_tags")
# mail_rule = super().create(validated_data)
# if assign_tags:
# mail_rule.assign_tags.set(assign_tags)
# return mail_rule
def validate(self, attrs):
if len(attrs["filter_filename"]) == 0 and len(attrs["filter_path"]) == 0:
raise serializers.ValidationError("File name or path filter are required")
# def validate(self, attrs):
# TODO: require path or filename filter
# if (
# attrs["action"] == ConsumptionTemplate.MailAction.TAG
# or attrs["action"] == ConsumptionTemplate.MailAction.MOVE
# ) and attrs["action_parameter"] is None:
# raise serializers.ValidationError("An action parameter is required.")
# return attrs
return attrs