mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Fixes handling of gmail label extension to IMAP
This commit is contained in:
		| @@ -4,6 +4,7 @@ import tempfile | |||||||
| from datetime import date | from datetime import date | ||||||
| from datetime import timedelta | from datetime import timedelta | ||||||
| from fnmatch import fnmatch | from fnmatch import fnmatch | ||||||
|  | from typing import Dict | ||||||
|  |  | ||||||
| import magic | import magic | ||||||
| import pathvalidate | import pathvalidate | ||||||
| @@ -30,7 +31,7 @@ class MailError(Exception): | |||||||
|  |  | ||||||
|  |  | ||||||
| class BaseMailAction: | class BaseMailAction: | ||||||
|     def get_criteria(self): |     def get_criteria(self) -> Dict: | ||||||
|         return {} |         return {} | ||||||
|  |  | ||||||
|     def post_consume(self, M, message_uids, parameter): |     def post_consume(self, M, message_uids, parameter): | ||||||
| @@ -78,7 +79,7 @@ class TagMailAction(BaseMailAction): | |||||||
|             M.flag(message_uids, [self.keyword], True) |             M.flag(message_uids, [self.keyword], True) | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_rule_action(rule): | def get_rule_action(rule) -> BaseMailAction: | ||||||
|     if rule.action == MailRule.MailAction.FLAG: |     if rule.action == MailRule.MailAction.FLAG: | ||||||
|         return FlagMailAction() |         return FlagMailAction() | ||||||
|     elif rule.action == MailRule.MailAction.DELETE: |     elif rule.action == MailRule.MailAction.DELETE: | ||||||
| @@ -108,7 +109,7 @@ def make_criterias(rule): | |||||||
|     return {**criterias, **get_rule_action(rule).get_criteria()} |     return {**criterias, **get_rule_action(rule).get_criteria()} | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_mailbox(server, port, security): | def get_mailbox(server, port, security) -> MailBox: | ||||||
|     if security == MailAccount.ImapSecurity.NONE: |     if security == MailAccount.ImapSecurity.NONE: | ||||||
|         mailbox = MailBoxUnencrypted(server, port) |         mailbox = MailBoxUnencrypted(server, port) | ||||||
|     elif security == MailAccount.ImapSecurity.STARTTLS: |     elif security == MailAccount.ImapSecurity.STARTTLS: | ||||||
| @@ -167,7 +168,7 @@ class MailAccountHandler(LoggingMixin): | |||||||
|                 "Unknown correspondent selector", |                 "Unknown correspondent selector", | ||||||
|             )  # pragma: nocover |             )  # pragma: nocover | ||||||
|  |  | ||||||
|     def handle_mail_account(self, account): |     def handle_mail_account(self, account: MailAccount): | ||||||
|  |  | ||||||
|         self.renew_logging_group() |         self.renew_logging_group() | ||||||
|  |  | ||||||
| @@ -181,7 +182,14 @@ class MailAccountHandler(LoggingMixin): | |||||||
|                 account.imap_security, |                 account.imap_security, | ||||||
|             ) as M: |             ) as M: | ||||||
|  |  | ||||||
|  |                 supports_gmail_labels = "X-GM-EXT-1" in M.client.capabilities | ||||||
|  |                 supports_auth_plain = "AUTH=PLAIN" in M.client.capabilities | ||||||
|  |  | ||||||
|  |                 self.log("debug", f"GMAIL Label Support: {supports_gmail_labels}") | ||||||
|  |                 self.log("debug", f"AUTH=PLAIN Support: {supports_auth_plain}") | ||||||
|  |  | ||||||
|                 try: |                 try: | ||||||
|  |  | ||||||
|                     M.login(account.username, account.password) |                     M.login(account.username, account.password) | ||||||
|  |  | ||||||
|                 except UnicodeEncodeError: |                 except UnicodeEncodeError: | ||||||
| @@ -215,7 +223,11 @@ class MailAccountHandler(LoggingMixin): | |||||||
|  |  | ||||||
|                 for rule in account.rules.order_by("order"): |                 for rule in account.rules.order_by("order"): | ||||||
|                     try: |                     try: | ||||||
|                         total_processed_files += self.handle_mail_rule(M, rule) |                         total_processed_files += self.handle_mail_rule( | ||||||
|  |                             M, | ||||||
|  |                             rule, | ||||||
|  |                             supports_gmail_labels, | ||||||
|  |                         ) | ||||||
|                     except Exception as e: |                     except Exception as e: | ||||||
|                         self.log( |                         self.log( | ||||||
|                             "error", |                             "error", | ||||||
| @@ -233,7 +245,12 @@ class MailAccountHandler(LoggingMixin): | |||||||
|  |  | ||||||
|         return total_processed_files |         return total_processed_files | ||||||
|  |  | ||||||
|     def handle_mail_rule(self, M: MailBox, rule): |     def handle_mail_rule( | ||||||
|  |         self, | ||||||
|  |         M: MailBox, | ||||||
|  |         rule: MailRule, | ||||||
|  |         supports_gmail_labels: bool = False, | ||||||
|  |     ): | ||||||
|  |  | ||||||
|         self.log("debug", f"Rule {rule}: Selecting folder {rule.folder}") |         self.log("debug", f"Rule {rule}: Selecting folder {rule.folder}") | ||||||
|  |  | ||||||
| @@ -261,11 +278,19 @@ class MailAccountHandler(LoggingMixin): | |||||||
|             ) from err |             ) from err | ||||||
|  |  | ||||||
|         criterias = make_criterias(rule) |         criterias = make_criterias(rule) | ||||||
|         criterias_imap = AND(**criterias) |  | ||||||
|  |         # Deal with the Gmail label extension | ||||||
|         if "gmail_label" in criterias: |         if "gmail_label" in criterias: | ||||||
|  |  | ||||||
|             gmail_label = criterias["gmail_label"] |             gmail_label = criterias["gmail_label"] | ||||||
|             del criterias["gmail_label"] |             del criterias["gmail_label"] | ||||||
|             criterias_imap = AND(NOT(gmail_label=gmail_label), **criterias) |  | ||||||
|  |             if not supports_gmail_labels: | ||||||
|  |                 criterias_imap = AND(**criterias) | ||||||
|  |             else: | ||||||
|  |                 criterias_imap = AND(NOT(gmail_label=gmail_label), **criterias) | ||||||
|  |         else: | ||||||
|  |             criterias_imap = AND(**criterias) | ||||||
|  |  | ||||||
|         self.log( |         self.log( | ||||||
|             "debug", |             "debug", | ||||||
|   | |||||||
| @@ -47,15 +47,16 @@ class BogusFolderManager: | |||||||
|  |  | ||||||
|  |  | ||||||
| class BogusClient: | class BogusClient: | ||||||
|  |     def __init__(self, messages): | ||||||
|  |         self.messages: List[MailMessage] = messages | ||||||
|  |         self.capabilities: List[str] = [] | ||||||
|  |  | ||||||
|     def __enter__(self): |     def __enter__(self): | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     def __exit__(self, exc_type, exc_val, exc_tb): |     def __exit__(self, exc_type, exc_val, exc_tb): | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|     def __init__(self, messages): |  | ||||||
|         self.messages: List[MailMessage] = messages |  | ||||||
|  |  | ||||||
|     def authenticate(self, mechanism, authobject): |     def authenticate(self, mechanism, authobject): | ||||||
|         # authobject must be a callable object |         # authobject must be a callable object | ||||||
|         auth_bytes = authobject(None) |         auth_bytes = authobject(None) | ||||||
| @@ -80,12 +81,6 @@ class BogusMailBox(ContextManager): | |||||||
|     # Note the non-ascii characters here |     # Note the non-ascii characters here | ||||||
|     UTF_PASSWORD: str = "w57äöüw4b6huwb6nhu" |     UTF_PASSWORD: str = "w57äöüw4b6huwb6nhu" | ||||||
|  |  | ||||||
|     def __enter__(self): |  | ||||||
|         return self |  | ||||||
|  |  | ||||||
|     def __exit__(self, exc_type, exc_val, exc_tb): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.messages: List[MailMessage] = [] |         self.messages: List[MailMessage] = [] | ||||||
|         self.messages_spam: List[MailMessage] = [] |         self.messages_spam: List[MailMessage] = [] | ||||||
| @@ -93,6 +88,12 @@ class BogusMailBox(ContextManager): | |||||||
|         self.client = BogusClient(self.messages) |         self.client = BogusClient(self.messages) | ||||||
|         self._host = "" |         self._host = "" | ||||||
|  |  | ||||||
|  |     def __enter__(self): | ||||||
|  |         return self | ||||||
|  |  | ||||||
|  |     def __exit__(self, exc_type, exc_val, exc_tb): | ||||||
|  |         pass | ||||||
|  |  | ||||||
|     def updateClient(self): |     def updateClient(self): | ||||||
|         self.client = BogusClient(self.messages) |         self.client = BogusClient(self.messages) | ||||||
|  |  | ||||||
| @@ -648,6 +649,7 @@ class TestMail(DirectoriesMixin, TestCase): | |||||||
|  |  | ||||||
|     def test_handle_mail_account_tag_gmail(self): |     def test_handle_mail_account_tag_gmail(self): | ||||||
|         self.bogus_mailbox._host = "imap.gmail.com" |         self.bogus_mailbox._host = "imap.gmail.com" | ||||||
|  |         self.bogus_mailbox.client.capabilities = ["X-GM-EXT-1"] | ||||||
|  |  | ||||||
|         account = MailAccount.objects.create( |         account = MailAccount.objects.create( | ||||||
|             name="test", |             name="test", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Trenton H
					Trenton H