diff --git a/frappe_gmail_thread/__init__.py b/frappe_gmail_thread/__init__.py index 5becc17..5c4105c 100644 --- a/frappe_gmail_thread/__init__.py +++ b/frappe_gmail_thread/__init__.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "1.0.1" diff --git a/frappe_gmail_thread/api/activity.py b/frappe_gmail_thread/api/activity.py index 7d2a4bc..c282160 100644 --- a/frappe_gmail_thread/api/activity.py +++ b/frappe_gmail_thread/api/activity.py @@ -1,18 +1,59 @@ -import json - import frappe import frappe.utils +from frappe import _ def get_attachments_data(email): - attachments_data = json.loads(email.attachments_data) - # instead of using file_url from attachments_data, we have to use frappe.get_value to get the latest file_url + raw_attachments = getattr(email, "attachments_data", None) + if not raw_attachments: + return [] + + if isinstance(raw_attachments, str): + try: + attachments_data = frappe.parse_json(raw_attachments) + except (TypeError, ValueError, frappe.ValidationError): + frappe.log_error( + title=_("Invalid Gmail attachments_data JSON"), + message=frappe.get_traceback(), + ) + return [] + elif isinstance(raw_attachments, list): + attachments_data = raw_attachments + else: + return [] + + if not attachments_data or not isinstance(attachments_data, list): + return [] + + file_doc_names = { + a.get("file_doc_name") + for a in attachments_data + if isinstance(a, dict) and a.get("file_doc_name") + } + file_url_by_name: dict[str, str] = {} + if file_doc_names: + file_url_by_name = { + r["name"]: r["file_url"] + for r in frappe.db.get_all( + "File", + filters={"name": ("in", list(file_doc_names))}, + fields=["name", "file_url"], + ) + } + + valid: list[dict] = [] for attachment in attachments_data: + if not isinstance(attachment, dict): + continue file_doc_name = attachment.get("file_doc_name") if file_doc_name: - file_url = frappe.db.get_value("File", file_doc_name, "file_url") + file_url = file_url_by_name.get(file_doc_name) + if not file_url: + continue attachment["file_url"] = file_url - return attachments_data + if attachment.get("file_url"): + valid.append(attachment) + return valid @frappe.whitelist() diff --git a/frappe_gmail_thread/frappe_gmail_thread/doctype/gmail_account/gmail_account.py b/frappe_gmail_thread/frappe_gmail_thread/doctype/gmail_account/gmail_account.py index 85f43ba..d79059a 100644 --- a/frappe_gmail_thread/frappe_gmail_thread/doctype/gmail_account/gmail_account.py +++ b/frappe_gmail_thread/frappe_gmail_thread/doctype/gmail_account/gmail_account.py @@ -1,9 +1,6 @@ # Copyright (c) 2024, rtCamp and contributors # For license information, please see license.txt -# import frappe -import json - import frappe from frappe import _ from frappe.model.document import Document @@ -132,10 +129,15 @@ def before_save(self): @frappe.whitelist() # nosemgrep -def sync_labels_api(args): - args = json.loads(args) - doc = frappe.get_doc("Gmail Account", args.get("doc_name")) - if args.get("reset_historyid", False): +def sync_labels_api(args: str | dict | None = None, doc_name: str | None = None): + if args: + if isinstance(args, str): + args = frappe.parse_json(args) + doc_name = doc_name or args.get("doc_name") + if not args and not doc_name: + frappe.throw(_("doc_name is required")) + doc = frappe.get_doc("Gmail Account", doc_name) + if args and args.get("reset_historyid", False): doc.last_historyid = 0 doc.save() doc.reload() diff --git a/frappe_gmail_thread/utils/helpers.py b/frappe_gmail_thread/utils/helpers.py index e1a556d..701f8c0 100644 --- a/frappe_gmail_thread/utils/helpers.py +++ b/frappe_gmail_thread/utils/helpers.py @@ -10,9 +10,13 @@ class GmailInboundMail(Email): - def __init__(self, content): + def __init__(self, content, email_account=None): + # temp compatibility with frappe.email.receive.Email + self.email_account = email_account or frappe._dict() + if not hasattr(self.email_account, "attachment_limit"): + self.email_account.attachment_limit = None + super().__init__(content) - # remove quoted replies from email text content self.text_content = self.pop_down_quoted_replies(self.text_content, "text") self.html_content = self.pop_down_quoted_replies(self.html_content, "html") self.set_content_and_type() @@ -126,8 +130,7 @@ def create_new_email(email, gmail_account): email_content = base64.urlsafe_b64decode(email["raw"].encode("ASCII")).decode( "utf-8", errors="replace" ) - email_object = GmailInboundMail(content=email_content) - # check if email is sent or received + email_object = GmailInboundMail(content=email_content, email_account=gmail_account) is_sent = False # check if there is a user (not website user) with the same email as the sender in frappe, if yes, then it is a sent email is_sent = (