mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Allows filtering email by the TO value(s) as well
This commit is contained in:
parent
70ac696f17
commit
3e467c517d
@ -9,6 +9,7 @@
|
||||
"account": 2,
|
||||
"folder": "INBOX",
|
||||
"filter_from": null,
|
||||
"filter_to": null,
|
||||
"filter_subject": "[paperless]",
|
||||
"filter_body": null,
|
||||
"filter_attachment_filename": null,
|
||||
|
@ -18,6 +18,7 @@
|
||||
<div class="col">
|
||||
<p class="small" i18n>Paperless will only process mails that match <em>all</em> of the filters specified below.</p>
|
||||
<app-input-text i18n-title title="Filter from" formControlName="filter_from" [error]="error?.filter_from"></app-input-text>
|
||||
<app-input-text i18n-title title="Filter to" formControlName="filter_to" [error]="error?.filter_to"></app-input-text>
|
||||
<app-input-text i18n-title title="Filter subject" formControlName="filter_subject" [error]="error?.filter_subject"></app-input-text>
|
||||
<app-input-text i18n-title title="Filter body" formControlName="filter_body" [error]="error?.filter_body"></app-input-text>
|
||||
<app-input-text i18n-title title="Filter attachment filename" formControlName="filter_attachment_filename" i18n-hint hint="Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." [error]="error?.filter_attachment_filename"></app-input-text>
|
||||
|
@ -149,6 +149,7 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<PaperlessMa
|
||||
account: new FormControl(null),
|
||||
folder: new FormControl('INBOX'),
|
||||
filter_from: new FormControl(null),
|
||||
filter_to: new FormControl(null),
|
||||
filter_subject: new FormControl(null),
|
||||
filter_body: new FormControl(null),
|
||||
filter_attachment_filename: new FormControl(null),
|
||||
|
@ -386,6 +386,7 @@ export class SettingsComponent
|
||||
account: rule.account,
|
||||
folder: rule.folder,
|
||||
filter_from: rule.filter_from,
|
||||
filter_to: rule.filter_to,
|
||||
filter_subject: rule.filter_subject,
|
||||
filter_body: rule.filter_body,
|
||||
filter_attachment_filename: rule.filter_attachment_filename,
|
||||
@ -406,6 +407,7 @@ export class SettingsComponent
|
||||
account: new FormControl(null),
|
||||
folder: new FormControl(null),
|
||||
filter_from: new FormControl(null),
|
||||
filter_to: new FormControl(null),
|
||||
filter_subject: new FormControl(null),
|
||||
filter_body: new FormControl(null),
|
||||
filter_attachment_filename: new FormControl(null),
|
||||
|
@ -42,6 +42,8 @@ export interface PaperlessMailRule extends ObjectWithId {
|
||||
|
||||
filter_from: string
|
||||
|
||||
filter_to: string
|
||||
|
||||
filter_subject: string
|
||||
|
||||
filter_body: string
|
||||
|
@ -53,6 +53,7 @@ class MailRuleAdmin(admin.ModelAdmin):
|
||||
),
|
||||
"fields": (
|
||||
"filter_from",
|
||||
"filter_to",
|
||||
"filter_subject",
|
||||
"filter_body",
|
||||
"filter_attachment_filename",
|
||||
|
@ -82,7 +82,12 @@ class BaseMailAction:
|
||||
"""
|
||||
return {}
|
||||
|
||||
def post_consume(self, M: MailBox, message_uid: str, parameter: str):
|
||||
def post_consume(
|
||||
self,
|
||||
M: MailBox,
|
||||
message_uid: str,
|
||||
parameter: str,
|
||||
): # pragma: nocover
|
||||
"""
|
||||
Perform mail action on the given mail uid in the mailbox.
|
||||
"""
|
||||
@ -160,7 +165,7 @@ class TagMailAction(BaseMailAction):
|
||||
return {"flagged": False}
|
||||
elif self.keyword:
|
||||
return AND(NOT(gmail_label=self.keyword), no_keyword=self.keyword)
|
||||
else:
|
||||
else: # pragma: nocover
|
||||
raise ValueError("This should never happen.")
|
||||
|
||||
def post_consume(self, M: MailBox, message_uid: str, parameter: str):
|
||||
@ -363,6 +368,8 @@ def make_criterias(rule):
|
||||
criterias["date_gte"] = maximum_age
|
||||
if rule.filter_from:
|
||||
criterias["from_"] = rule.filter_from
|
||||
if rule.filter_to:
|
||||
criterias["to"] = rule.filter_to
|
||||
if rule.filter_subject:
|
||||
criterias["subject"] = rule.filter_subject
|
||||
if rule.filter_body:
|
||||
|
19
src/paperless_mail/migrations/0019_mailrule_filter_to.py
Normal file
19
src/paperless_mail/migrations/0019_mailrule_filter_to.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-11 21:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("paperless_mail", "0018_processedmail"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="mailrule",
|
||||
name="filter_to",
|
||||
field=models.CharField(
|
||||
blank=True, max_length=256, null=True, verbose_name="filter to"
|
||||
),
|
||||
),
|
||||
]
|
@ -113,12 +113,21 @@ class MailRule(document_models.ModelWithOwner):
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
filter_to = models.CharField(
|
||||
_("filter to"),
|
||||
max_length=256,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
filter_subject = models.CharField(
|
||||
_("filter subject"),
|
||||
max_length=256,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
filter_body = models.CharField(
|
||||
_("filter body"),
|
||||
max_length=256,
|
||||
|
@ -70,6 +70,7 @@ class MailRuleSerializer(OwnedObjectSerializer):
|
||||
"account",
|
||||
"folder",
|
||||
"filter_from",
|
||||
"filter_to",
|
||||
"filter_subject",
|
||||
"filter_body",
|
||||
"filter_attachment_filename",
|
||||
|
@ -201,6 +201,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
|
||||
account=account1,
|
||||
folder="INBOX",
|
||||
filter_from="from@example.com",
|
||||
filter_to="someone@somewhere.com",
|
||||
filter_subject="subject",
|
||||
filter_body="body",
|
||||
filter_attachment_filename="file.pdf",
|
||||
@ -222,6 +223,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(returned_rule1["account"], account1.pk)
|
||||
self.assertEqual(returned_rule1["folder"], rule1.folder)
|
||||
self.assertEqual(returned_rule1["filter_from"], rule1.filter_from)
|
||||
self.assertEqual(returned_rule1["filter_to"], rule1.filter_to)
|
||||
self.assertEqual(returned_rule1["filter_subject"], rule1.filter_subject)
|
||||
self.assertEqual(returned_rule1["filter_body"], rule1.filter_body)
|
||||
self.assertEqual(
|
||||
@ -275,6 +277,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
|
||||
"account": account1.pk,
|
||||
"folder": "INBOX",
|
||||
"filter_from": "from@example.com",
|
||||
"filter_to": "aperson@aplace.com",
|
||||
"filter_subject": "subject",
|
||||
"filter_body": "body",
|
||||
"filter_attachment_filename": "file.pdf",
|
||||
@ -307,6 +310,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(returned_rule1["account"], account1.pk)
|
||||
self.assertEqual(returned_rule1["folder"], rule1["folder"])
|
||||
self.assertEqual(returned_rule1["filter_from"], rule1["filter_from"])
|
||||
self.assertEqual(returned_rule1["filter_to"], rule1["filter_to"])
|
||||
self.assertEqual(returned_rule1["filter_subject"], rule1["filter_subject"])
|
||||
self.assertEqual(returned_rule1["filter_body"], rule1["filter_body"])
|
||||
self.assertEqual(
|
||||
|
@ -5,6 +5,7 @@ import uuid
|
||||
from collections import namedtuple
|
||||
from typing import ContextManager
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
from unittest import mock
|
||||
|
||||
@ -131,12 +132,20 @@ class BogusMailBox(ContextManager):
|
||||
from_ = criteria[criteria.index("FROM") + 1].strip('"')
|
||||
msg = filter(lambda m: from_ in m.from_, msg)
|
||||
|
||||
if "TO" in criteria:
|
||||
to_ = criteria[criteria.index("TO") + 1].strip('"')
|
||||
msg = []
|
||||
for m in self.messages:
|
||||
for to_addrs in m.to:
|
||||
if to_ in to_addrs:
|
||||
msg.append(m)
|
||||
|
||||
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)
|
||||
msg = filter(lambda m: tag not in m.flags, msg)
|
||||
|
||||
if "(X-GM-LABELS" in criteria: # ['NOT', '(X-GM-LABELS', '"processed"']
|
||||
msg = filter(lambda m: "processed" not in m.flags, msg)
|
||||
@ -205,15 +214,21 @@ class TestMail(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
||||
body: str = "",
|
||||
subject: str = "the suject",
|
||||
from_: str = "noone@mail.com",
|
||||
to: Optional[List[str]] = None,
|
||||
seen: bool = False,
|
||||
flagged: bool = False,
|
||||
processed: bool = False,
|
||||
) -> MailMessage:
|
||||
|
||||
if to is None:
|
||||
to = ["tosomeone@somewhere.com"]
|
||||
|
||||
email_msg = email.message.EmailMessage()
|
||||
# TODO: This does NOT set the UID
|
||||
email_msg["Message-ID"] = str(uuid.uuid4())
|
||||
email_msg["Subject"] = subject
|
||||
email_msg["From"] = from_
|
||||
email_msg["To"] = str(" ,".join(to))
|
||||
email_msg.set_content(body)
|
||||
|
||||
# Either add some default number of attachments
|
||||
@ -266,6 +281,7 @@ class TestMail(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
||||
self.create_message(
|
||||
subject="Invoice 1",
|
||||
from_="amazon@amazon.de",
|
||||
to=["me@myselfandi.com", "helpdesk@mydomain.com"],
|
||||
body="cables",
|
||||
seen=True,
|
||||
flagged=False,
|
||||
@ -276,6 +292,7 @@ class TestMail(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
||||
self.create_message(
|
||||
subject="Invoice 2",
|
||||
body="from my favorite electronic store",
|
||||
to=["invoices@mycompany.com"],
|
||||
seen=False,
|
||||
flagged=True,
|
||||
processed=True,
|
||||
@ -285,6 +302,7 @@ class TestMail(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
||||
self.create_message(
|
||||
subject="Claim your $10M price now!",
|
||||
from_="amazon@amazon-some-indian-site.org",
|
||||
to="special@me.me",
|
||||
seen=False,
|
||||
),
|
||||
)
|
||||
@ -946,21 +964,26 @@ class TestMail(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
||||
password="secret",
|
||||
)
|
||||
|
||||
for (f_body, f_from, f_subject, expected_mail_count) in [
|
||||
(None, None, "Claim", 1),
|
||||
("electronic", None, None, 1),
|
||||
(None, "amazon", None, 2),
|
||||
("cables", "amazon", "Invoice", 1),
|
||||
for (f_body, f_from, f_to, f_subject, expected_mail_count) in [
|
||||
(None, None, None, "Claim", 1),
|
||||
("electronic", None, None, None, 1),
|
||||
(None, "amazon", None, None, 2),
|
||||
("cables", "amazon", None, "Invoice", 1),
|
||||
(None, None, "test@email.com", None, 0),
|
||||
(None, None, "invoices@mycompany.com", None, 1),
|
||||
("electronic", None, "invoices@mycompany.com", None, 1),
|
||||
(None, "amazon", "me@myselfandi.com", None, 1),
|
||||
]:
|
||||
with self.subTest(f_body=f_body, f_from=f_from, f_subject=f_subject):
|
||||
MailRule.objects.all().delete()
|
||||
rule = MailRule.objects.create(
|
||||
_ = MailRule.objects.create(
|
||||
name="testrule3",
|
||||
account=account,
|
||||
action=MailRule.MailAction.DELETE,
|
||||
filter_subject=f_subject,
|
||||
filter_body=f_body,
|
||||
filter_from=f_from,
|
||||
filter_to=f_to,
|
||||
)
|
||||
self.reset_bogus_mailbox()
|
||||
self._queue_consumption_tasks_mock.reset_mock()
|
||||
|
Loading…
x
Reference in New Issue
Block a user