Feature: consumption templates (#4196)

* Initial implementation of consumption templates

* Frontend implementation of consumption templates

Testing

* Support consumption template source

* order templates, automatically add permissions

* Support title assignment in consumption templates

* Refactoring, filters to and, show sources on list

Show sources on template list, update some translation strings

Make filters and

minor testing

* Update strings

* Only update django-multiselectfield

* Basic docs, document some methods

* Improve testing coverage, template multi-assignment merges
This commit is contained in:
shamoon
2023-09-22 16:53:13 -07:00
committed by GitHub
parent 86d223fd93
commit 9712ac109d
51 changed files with 3250 additions and 444 deletions

View File

@@ -436,6 +436,9 @@ class MailAccountHandler(LoggingMixin):
elif rule.assign_title_from == MailRule.TitleSource.FROM_FILENAME:
return os.path.splitext(os.path.basename(att.filename))[0]
elif rule.assign_title_from == MailRule.TitleSource.NONE:
return None
else:
raise NotImplementedError(
"Unknown title selector.",
@@ -690,6 +693,7 @@ class MailAccountHandler(LoggingMixin):
input_doc = ConsumableDocument(
source=DocumentSource.MailFetch,
original_file=temp_filename,
mailrule_id=rule.pk,
)
doc_overrides = DocumentMetadataOverrides(
title=title,
@@ -697,7 +701,9 @@ class MailAccountHandler(LoggingMixin):
correspondent_id=correspondent.id if correspondent else None,
document_type_id=doc_type.id if doc_type else None,
tag_ids=tag_ids,
owner_id=rule.owner.id if rule.owner else None,
owner_id=rule.owner.id
if (rule.assign_owner_from_rule and rule.owner)
else None,
)
consume_task = consume_file.s(

View File

@@ -0,0 +1,34 @@
# Generated by Django 4.1.11 on 2023-09-18 18:50
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("paperless_mail", "0021_alter_mailaccount_password"),
]
operations = [
migrations.AddField(
model_name="mailrule",
name="assign_owner_from_rule",
field=models.BooleanField(
default=True,
verbose_name="Assign the rule owner to documents",
),
),
migrations.AlterField(
model_name="mailrule",
name="assign_title_from",
field=models.PositiveIntegerField(
choices=[
(1, "Use subject as title"),
(2, "Use attachment filename as title"),
(3, "Do not assign title from rule"),
],
default=1,
verbose_name="assign title from",
),
),
]

View File

@@ -82,6 +82,7 @@ class MailRule(document_models.ModelWithOwner):
class TitleSource(models.IntegerChoices):
FROM_SUBJECT = 1, _("Use subject as title")
FROM_FILENAME = 2, _("Use attachment filename as title")
NONE = 3, _("Do not assign title from rule")
class CorrespondentSource(models.IntegerChoices):
FROM_NOTHING = 1, _("Do not assign a correspondent")
@@ -225,6 +226,11 @@ class MailRule(document_models.ModelWithOwner):
verbose_name=_("assign this correspondent"),
)
assign_owner_from_rule = models.BooleanField(
_("Assign the rule owner to documents"),
default=True,
)
def __str__(self):
return f"{self.account.name}.{self.name}"

View File

@@ -88,6 +88,7 @@ class MailRuleSerializer(OwnedObjectSerializer):
"assign_correspondent_from",
"assign_correspondent",
"assign_document_type",
"assign_owner_from_rule",
"order",
"attachment_type",
"consumption_scope",

View File

@@ -464,6 +464,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
"assign_tags": [tag.pk],
"assign_correspondent": correspondent.pk,
"assign_document_type": document_type.pk,
"assign_owner_from_rule": True,
}
response = self.client.post(
@@ -512,6 +513,10 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
rule1["assign_document_type"],
)
self.assertEqual(returned_rule1["assign_tags"], rule1["assign_tags"])
self.assertEqual(
returned_rule1["assign_owner_from_rule"],
rule1["assign_owner_from_rule"],
)
def test_delete_mail_rule(self):
"""

View File

@@ -392,6 +392,11 @@ class TestMail(
assign_title_from=MailRule.TitleSource.FROM_SUBJECT,
)
self.assertEqual(handler._get_title(message, att, rule), "the message title")
rule = MailRule(
name="b",
assign_title_from=MailRule.TitleSource.NONE,
)
self.assertEqual(handler._get_title(message, att, rule), None)
def test_handle_message(self):
message = self.create_message(