mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 10:12:35 -04:00 
			
		
		
		
	Merge pull request #1032 from pheerai/feature-mailActionCustomTag
Feature mail action custom tag
This commit is contained in:
		
						commit
						4db3f366ef
					
				| @ -161,6 +161,9 @@ These are as follows: | |||||||
|     will not consume flagged mails. |     will not consume flagged mails. | ||||||
| *   **Move to folder:** Moves consumed mails out of the way so that paperless wont | *   **Move to folder:** Moves consumed mails out of the way so that paperless wont | ||||||
|     consume them again. |     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:: | .. caution:: | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -62,6 +62,17 @@ class FlagMailAction(BaseMailAction): | |||||||
|         M.flag(message_uids, [MailMessageFlags.FLAGGED], True) |         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): | def get_rule_action(rule): | ||||||
|     if rule.action == MailRule.MailAction.FLAG: |     if rule.action == MailRule.MailAction.FLAG: | ||||||
|         return FlagMailAction() |         return FlagMailAction() | ||||||
| @ -71,6 +82,8 @@ def get_rule_action(rule): | |||||||
|         return MoveMailAction() |         return MoveMailAction() | ||||||
|     elif rule.action == MailRule.MailAction.MARK_READ: |     elif rule.action == MailRule.MailAction.MARK_READ: | ||||||
|         return MarkReadMailAction() |         return MarkReadMailAction() | ||||||
|  |     elif rule.action == MailRule.MailAction.TAG: | ||||||
|  |         return TagMailAction(rule.action_parameter) | ||||||
|     else: |     else: | ||||||
|         raise NotImplementedError("Unknown action.")  # pragma: nocover |         raise NotImplementedError("Unknown action.")  # pragma: nocover | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								src/paperless_mail/migrations/0015_alter_mailrule_action.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/paperless_mail/migrations/0015_alter_mailrule_action.py
									
									
									
									
									
										Normal 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", | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @ -65,6 +65,7 @@ class MailRule(models.Model): | |||||||
|         MOVE = 2, _("Move to specified folder") |         MOVE = 2, _("Move to specified folder") | ||||||
|         MARK_READ = 3, _("Mark as read, don't process read mails") |         MARK_READ = 3, _("Mark as read, don't process read mails") | ||||||
|         FLAG = 4, _("Flag the mail, don't process flagged 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): |     class TitleSource(models.IntegerChoices): | ||||||
|         FROM_SUBJECT = 1, _("Use subject as title") |         FROM_SUBJECT = 1, _("Use subject as title") | ||||||
|  | |||||||
| @ -96,6 +96,10 @@ class BogusMailBox(ContextManager): | |||||||
|         if "UNFLAGGED" in criteria: |         if "UNFLAGGED" in criteria: | ||||||
|             msg = filter(lambda m: not m.flagged, msg) |             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) |         return list(msg) | ||||||
| 
 | 
 | ||||||
|     def delete(self, uid_list): |     def delete(self, uid_list): | ||||||
| @ -109,6 +113,9 @@ class BogusMailBox(ContextManager): | |||||||
|                         message.flagged = value |                         message.flagged = value | ||||||
|                     if flag == MailMessageFlags.SEEN: |                     if flag == MailMessageFlags.SEEN: | ||||||
|                         message.seen = value |                         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): |     def move(self, uid_list, folder): | ||||||
|         if folder == "spam": |         if folder == "spam": | ||||||
| @ -130,6 +137,7 @@ def create_message( | |||||||
|     from_: str = "noone@mail.com", |     from_: str = "noone@mail.com", | ||||||
|     seen: bool = False, |     seen: bool = False, | ||||||
|     flagged: bool = False, |     flagged: bool = False, | ||||||
|  |     processed: bool = False, | ||||||
| ) -> MailMessage: | ) -> MailMessage: | ||||||
|     email_msg = email.message.EmailMessage() |     email_msg = email.message.EmailMessage() | ||||||
|     # TODO: This does NOT set the UID |     # TODO: This does NOT set the UID | ||||||
| @ -175,6 +183,9 @@ def create_message( | |||||||
| 
 | 
 | ||||||
|     imap_msg.seen = seen |     imap_msg.seen = seen | ||||||
|     imap_msg.flagged = flagged |     imap_msg.flagged = flagged | ||||||
|  |     if processed: | ||||||
|  |         imap_msg._raw_flag_data.append(f"+FLAGS (processed)".encode()) | ||||||
|  |         MailMessage.flags.fget.cache_clear() | ||||||
| 
 | 
 | ||||||
|     return imap_msg |     return imap_msg | ||||||
| 
 | 
 | ||||||
| @ -217,6 +228,7 @@ class TestMail(DirectoriesMixin, TestCase): | |||||||
|                 body="cables", |                 body="cables", | ||||||
|                 seen=True, |                 seen=True, | ||||||
|                 flagged=False, |                 flagged=False, | ||||||
|  |                 processed=False, | ||||||
|             ), |             ), | ||||||
|         ) |         ) | ||||||
|         self.bogus_mailbox.messages.append( |         self.bogus_mailbox.messages.append( | ||||||
| @ -225,6 +237,7 @@ class TestMail(DirectoriesMixin, TestCase): | |||||||
|                 body="from my favorite electronic store", |                 body="from my favorite electronic store", | ||||||
|                 seen=False, |                 seen=False, | ||||||
|                 flagged=True, |                 flagged=True, | ||||||
|  |                 processed=True, | ||||||
|             ), |             ), | ||||||
|         ) |         ) | ||||||
|         self.bogus_mailbox.messages.append( |         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), 2) | ||||||
|         self.assertEqual(len(self.bogus_mailbox.messages_spam), 1) |         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): |     def test_error_login(self): | ||||||
|         account = MailAccount.objects.create( |         account = MailAccount.objects.create( | ||||||
|             name="test", |             name="test", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user