diff --git a/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.html index e75ca1a5b..3981bc8be 100644 --- a/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.html @@ -15,6 +15,7 @@
+ diff --git a/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.ts index 2f79b9fbc..e6df00b23 100644 --- a/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component.ts @@ -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([]), }) } diff --git a/src-ui/src/app/data/paperless-consumption-template.ts b/src-ui/src/app/data/paperless-consumption-template.ts index f424e23f2..bc7eab734 100644 --- a/src-ui/src/app/data/paperless-consumption-template.ts +++ b/src-ui/src/app/data/paperless-consumption-template.ts @@ -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 diff --git a/src/documents/consumer.py b/src/documents/consumer.py index 63251e0f9..cd505f4c2 100644 --- a/src/documents/consumer.py +++ b/src/documents/consumer.py @@ -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: diff --git a/src/documents/migrations/1039_consumptiontemplate.py b/src/documents/migrations/1039_consumptiontemplate.py index fb27239f0..5ca928159 100644 --- a/src/documents/migrations/1039_consumptiontemplate.py +++ b/src/documents/migrations/1039_consumptiontemplate.py @@ -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( diff --git a/src/documents/models.py b/src/documents/models.py index 231e5dba2..84bb7d9d1 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -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, diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index aacd978ae..7c861c2c1 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -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