Merge pull request #1032 from pheerai/feature-mailActionCustomTag

Feature mail action custom tag
This commit is contained in:
Trenton Holmes 2022-06-02 09:46:34 -07:00 committed by GitHub
commit 4db3f366ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 0 deletions

View File

@ -161,6 +161,9 @@ These are as follows:
will not consume flagged mails.
* **Move to folder:** Moves consumed mails out of the way so that paperless wont
consume them again.
* **Add custom Tag:** Adds a custom tag to mails with consumed documents (the IMAP
standard calls these "keywords"). Paperless will not consume mails already tagged.
Not all mail servers support this feature!
.. caution::

View File

@ -62,6 +62,17 @@ class FlagMailAction(BaseMailAction):
M.flag(message_uids, [MailMessageFlags.FLAGGED], True)
class TagMailAction(BaseMailAction):
def __init__(self, parameter):
self.keyword = parameter
def get_criteria(self):
return {"no_keyword": self.keyword}
def post_consume(self, M: MailBox, message_uids, parameter):
M.flag(message_uids, [self.keyword], True)
def get_rule_action(rule):
if rule.action == MailRule.MailAction.FLAG:
return FlagMailAction()
@ -71,6 +82,8 @@ def get_rule_action(rule):
return MoveMailAction()
elif rule.action == MailRule.MailAction.MARK_READ:
return MarkReadMailAction()
elif rule.action == MailRule.MailAction.TAG:
return TagMailAction(rule.action_parameter)
else:
raise NotImplementedError("Unknown action.") # pragma: nocover

View File

@ -0,0 +1,28 @@
# Generated by Django 4.0.4 on 2022-05-29 13:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("paperless_mail", "0014_alter_mailrule_action"),
]
operations = [
migrations.AlterField(
model_name="mailrule",
name="action",
field=models.PositiveIntegerField(
choices=[
(1, "Delete"),
(2, "Move to specified folder"),
(3, "Mark as read, don't process read mails"),
(4, "Flag the mail, don't process flagged mails"),
(5, "Tag the mail with specified tag, don't process tagged mails"),
],
default=3,
verbose_name="action",
),
),
]

View File

@ -65,6 +65,7 @@ class MailRule(models.Model):
MOVE = 2, _("Move to specified folder")
MARK_READ = 3, _("Mark as read, don't process read mails")
FLAG = 4, _("Flag the mail, don't process flagged mails")
TAG = 5, _("Tag the mail with specified tag, don't process tagged mails")
class TitleSource(models.IntegerChoices):
FROM_SUBJECT = 1, _("Use subject as title")

View File

@ -96,6 +96,10 @@ class BogusMailBox(ContextManager):
if "UNFLAGGED" in criteria:
msg = filter(lambda m: not m.flagged, msg)
if "UNKEYWORD" in criteria:
tag = criteria[criteria.index("UNKEYWORD") + 1].strip("'")
msg = filter(lambda m: "processed" not in m.flags, msg)
return list(msg)
def delete(self, uid_list):
@ -109,6 +113,9 @@ class BogusMailBox(ContextManager):
message.flagged = value
if flag == MailMessageFlags.SEEN:
message.seen = value
if flag == "processed":
message._raw_flag_data.append(f"+FLAGS (processed)".encode())
MailMessage.flags.fget.cache_clear()
def move(self, uid_list, folder):
if folder == "spam":
@ -130,6 +137,7 @@ def create_message(
from_: str = "noone@mail.com",
seen: bool = False,
flagged: bool = False,
processed: bool = False,
) -> MailMessage:
email_msg = email.message.EmailMessage()
# TODO: This does NOT set the UID
@ -175,6 +183,9 @@ def create_message(
imap_msg.seen = seen
imap_msg.flagged = flagged
if processed:
imap_msg._raw_flag_data.append(f"+FLAGS (processed)".encode())
MailMessage.flags.fget.cache_clear()
return imap_msg
@ -217,6 +228,7 @@ class TestMail(DirectoriesMixin, TestCase):
body="cables",
seen=True,
flagged=False,
processed=False,
),
)
self.bogus_mailbox.messages.append(
@ -225,6 +237,7 @@ class TestMail(DirectoriesMixin, TestCase):
body="from my favorite electronic store",
seen=False,
flagged=True,
processed=True,
),
)
self.bogus_mailbox.messages.append(
@ -571,6 +584,29 @@ class TestMail(DirectoriesMixin, TestCase):
self.assertEqual(len(self.bogus_mailbox.messages), 2)
self.assertEqual(len(self.bogus_mailbox.messages_spam), 1)
def test_handle_mail_account_tag(self):
account = MailAccount.objects.create(
name="test",
imap_server="",
username="admin",
password="secret",
)
_ = MailRule.objects.create(
name="testrule",
account=account,
action=MailRule.MailAction.TAG,
action_parameter="processed",
)
self.assertEqual(len(self.bogus_mailbox.messages), 3)
self.assertEqual(self.async_task.call_count, 0)
self.assertEqual(len(self.bogus_mailbox.fetch("UNKEYWORD processed", False)), 2)
self.mail_account_handler.handle_mail_account(account)
self.assertEqual(self.async_task.call_count, 2)
self.assertEqual(len(self.bogus_mailbox.fetch("UNKEYWORD processed", False)), 0)
self.assertEqual(len(self.bogus_mailbox.messages), 3)
def test_error_login(self):
account = MailAccount.objects.create(
name="test",