Support title assignment in consumption templates
This commit is contained in:
parent
c12e1f8732
commit
1aa0792b88
@ -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>
|
<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>
|
||||||
<div class="col">
|
<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-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 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>
|
<pngx-input-select i18n-title title="Assign correspondent" [items]="correspondents" [allowNull]="true" formControlName="assign_correspondent"></pngx-input-select>
|
||||||
|
@ -86,15 +86,16 @@ export class ConsumptionTemplateEditDialogComponent extends EditDialogComponent<
|
|||||||
filter_path: new FormControl(null),
|
filter_path: new FormControl(null),
|
||||||
order: new FormControl(null),
|
order: new FormControl(null),
|
||||||
sources: new FormControl([]),
|
sources: new FormControl([]),
|
||||||
|
assign_title: new FormControl(null),
|
||||||
assign_tags: new FormControl([]),
|
assign_tags: new FormControl([]),
|
||||||
assign_owner: new FormControl(null),
|
assign_owner: new FormControl(null),
|
||||||
assign_document_type: new FormControl(null),
|
assign_document_type: new FormControl(null),
|
||||||
assign_correspondent: new FormControl(null),
|
assign_correspondent: new FormControl(null),
|
||||||
assign_storage_path: new FormControl(null),
|
assign_storage_path: new FormControl(null),
|
||||||
assign_view_users: new FormControl(null),
|
assign_view_users: new FormControl([]),
|
||||||
assign_view_groups: new FormControl(null),
|
assign_view_groups: new FormControl([]),
|
||||||
assign_change_users: new FormControl(null),
|
assign_change_users: new FormControl([]),
|
||||||
assign_change_groups: new FormControl(null),
|
assign_change_groups: new FormControl([]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ export interface PaperlessConsumptionTemplate extends ObjectWithPermissions {
|
|||||||
|
|
||||||
filter_path: string
|
filter_path: string
|
||||||
|
|
||||||
|
assign_title?: string
|
||||||
|
|
||||||
assign_tags?: number[] // PaperlessTag.id
|
assign_tags?: number[] // PaperlessTag.id
|
||||||
|
|
||||||
assign_document_type?: number // PaperlessDocumentType.id
|
assign_document_type?: number // PaperlessDocumentType.id
|
||||||
|
@ -602,7 +602,7 @@ class Consumer(LoggingMixin):
|
|||||||
for template in ConsumptionTemplate.objects.all().order_by("order"):
|
for template in ConsumptionTemplate.objects.all().order_by("order"):
|
||||||
template_overrides = DocumentMetadataOverrides()
|
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
|
template.filter_filename is not None
|
||||||
and fnmatch(
|
and fnmatch(
|
||||||
@ -616,6 +616,8 @@ class Consumer(LoggingMixin):
|
|||||||
)
|
)
|
||||||
):
|
):
|
||||||
self.log.info(f"Document matched consumption template {template.name}")
|
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:
|
if template.assign_tags is not None:
|
||||||
template_overrides.tag_ids = [
|
template_overrides.tag_ids = [
|
||||||
tag.pk for tag in template.assign_tags.all()
|
tag.pk for tag in template.assign_tags.all()
|
||||||
@ -654,6 +656,38 @@ class Consumer(LoggingMixin):
|
|||||||
)
|
)
|
||||||
return overrides
|
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(
|
def _store(
|
||||||
self,
|
self,
|
||||||
text: str,
|
text: str,
|
||||||
@ -686,9 +720,15 @@ class Consumer(LoggingMixin):
|
|||||||
|
|
||||||
storage_type = Document.STORAGE_TYPE_UNENCRYPTED
|
storage_type = Document.STORAGE_TYPE_UNENCRYPTED
|
||||||
|
|
||||||
|
print("override_title", self.override_title)
|
||||||
|
|
||||||
with open(self.path, "rb") as f:
|
with open(self.path, "rb") as f:
|
||||||
document = Document.objects.create(
|
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,
|
content=text,
|
||||||
mime_type=mime_type,
|
mime_type=mime_type,
|
||||||
checksum=hashlib.md5(f.read()).hexdigest(),
|
checksum=hashlib.md5(f.read()).hexdigest(),
|
||||||
@ -800,6 +840,8 @@ def merge_overrides(
|
|||||||
overridesA: DocumentMetadataOverrides,
|
overridesA: DocumentMetadataOverrides,
|
||||||
overridesB: DocumentMetadataOverrides,
|
overridesB: DocumentMetadataOverrides,
|
||||||
) -> DocumentMetadataOverrides:
|
) -> DocumentMetadataOverrides:
|
||||||
|
if overridesA.title is None:
|
||||||
|
overridesA.title = overridesB.title
|
||||||
if overridesA.tag_ids is None:
|
if overridesA.tag_ids is None:
|
||||||
overridesA.tag_ids = overridesB.tag_ids
|
overridesA.tag_ids = overridesB.tag_ids
|
||||||
if overridesA.correspondent_id is None:
|
if overridesA.correspondent_id is None:
|
||||||
|
@ -167,6 +167,16 @@ class Migration(migrations.Migration):
|
|||||||
verbose_name="assign this tag",
|
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",
|
"assign_view_groups",
|
||||||
models.ManyToManyField(
|
models.ManyToManyField(
|
||||||
|
@ -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(
|
assign_tags = models.ManyToManyField(
|
||||||
Tag,
|
Tag,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -1066,6 +1066,7 @@ class ConsumptionTemplateSerializer(OwnedObjectSerializer):
|
|||||||
"sources",
|
"sources",
|
||||||
"filter_path",
|
"filter_path",
|
||||||
"filter_filename",
|
"filter_filename",
|
||||||
|
"assign_title",
|
||||||
"assign_tags",
|
"assign_tags",
|
||||||
"assign_correspondent",
|
"assign_correspondent",
|
||||||
"assign_document_type",
|
"assign_document_type",
|
||||||
@ -1085,20 +1086,8 @@ class ConsumptionTemplateSerializer(OwnedObjectSerializer):
|
|||||||
super().update(instance, validated_data)
|
super().update(instance, validated_data)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
# def create(self, validated_data):
|
def validate(self, attrs):
|
||||||
# if "assign_tags" in validated_data:
|
if len(attrs["filter_filename"]) == 0 and len(attrs["filter_path"]) == 0:
|
||||||
# assign_tags = validated_data.pop("assign_tags")
|
raise serializers.ValidationError("File name or path filter are required")
|
||||||
# mail_rule = super().create(validated_data)
|
|
||||||
# if assign_tags:
|
|
||||||
# mail_rule.assign_tags.set(assign_tags)
|
|
||||||
# return mail_rule
|
|
||||||
|
|
||||||
# def validate(self, attrs):
|
return 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
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user