-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
320 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
from datetime import datetime | ||
from typing import TYPE_CHECKING | ||
|
||
import frappe | ||
import pytz | ||
from frappe import _ | ||
from frappe.utils import convert_utc_to_system_timezone, now | ||
|
||
from mail_server.mail_server.doctype.mail_server_sync_history.mail_server_sync_history import ( | ||
get_mail_server_sync_history, | ||
) | ||
from mail_server.utils.validation import ( | ||
is_domain_registry_exists, | ||
validate_user_has_domain_owner_role, | ||
validate_user_is_domain_owner, | ||
) | ||
|
||
if TYPE_CHECKING: | ||
from mail_server.mail_server.doctype.mail_server_sync_history.mail_server_sync_history import ( | ||
MailServerSyncHistory, | ||
) | ||
|
||
|
||
from email.utils import formataddr | ||
|
||
from mail_server.utils import convert_to_utc | ||
|
||
|
||
@frappe.whitelist(methods=["GET"]) | ||
def fetch( | ||
domain_name: str, limit: int = 100, last_synced_at: str | None = None | ||
) -> dict[str, list[dict] | str]: | ||
"""Returns the incoming mails for the given domain.""" | ||
|
||
user = frappe.session.user | ||
validate_user_has_domain_owner_role(user) | ||
is_domain_registry_exists(domain_name, raise_exception=True) | ||
validate_user_is_domain_owner(user, domain_name) | ||
|
||
source = get_source() | ||
last_synced_at = convert_to_system_timezone(last_synced_at) | ||
sync_history = get_mail_server_sync_history(source, frappe.session.user, domain_name) | ||
result = get_incoming_mails(domain_name, limit, last_synced_at or sync_history.last_synced_at) | ||
update_mail_server_sync_history(sync_history, result["last_synced_at"], result["last_synced_mail"]) | ||
result["last_synced_at"] = convert_to_utc(result["last_synced_at"]) | ||
|
||
return result | ||
|
||
|
||
def get_source() -> str: | ||
"""Returns the source of the request.""" | ||
|
||
return frappe.request.headers.get("X-Frappe-Mail-Site") or frappe.local.request_ip | ||
|
||
|
||
def convert_to_system_timezone(last_synced_at: str) -> datetime | None: | ||
"""Converts the last_synced_at to system timezone.""" | ||
|
||
if last_synced_at: | ||
dt = datetime.fromisoformat(last_synced_at) | ||
dt_utc = dt.astimezone(pytz.utc) | ||
return convert_utc_to_system_timezone(dt_utc) | ||
|
||
|
||
def get_incoming_mails( | ||
domain_name: str, | ||
limit: int, | ||
last_synced_at: str | None = None, | ||
) -> dict[str, list[dict] | str]: | ||
"""Returns the incoming mails for the given domain.""" | ||
|
||
IML = frappe.qb.DocType("Incoming Mail Log") | ||
query = ( | ||
frappe.qb.from_(IML) | ||
.select( | ||
IML.name.as_("id"), | ||
IML.processed_at, | ||
IML.is_spam, | ||
IML.message, | ||
) | ||
.where((IML.is_rejected == 0) & (IML.status == "Accepted") & (IML.domain_name == domain_name)) | ||
.orderby(IML.processed_at) | ||
.limit(limit) | ||
) | ||
|
||
if last_synced_at: | ||
query = query.where(IML.processed_at > last_synced_at) | ||
|
||
mails = query.run(as_dict=True) | ||
last_synced_at = mails[-1].processed_at if mails else now() | ||
last_synced_mail = mails[-1].id if mails else None | ||
|
||
return { | ||
"mails": mails, | ||
"last_synced_at": last_synced_at, | ||
"last_synced_mail": last_synced_mail, | ||
} | ||
|
||
|
||
def update_mail_server_sync_history( | ||
sync_history: "MailServerSyncHistory", | ||
last_synced_at: str, | ||
last_synced_mail: str | None = None, | ||
) -> None: | ||
"""Update the last_synced_at in the Mail Server Sync History.""" | ||
|
||
kwargs = { | ||
"last_synced_at": last_synced_at or now(), | ||
} | ||
|
||
if last_synced_mail: | ||
kwargs["last_synced_mail"] = last_synced_mail | ||
|
||
sync_history._db_set(**kwargs, commit=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
8 changes: 8 additions & 0 deletions
8
mail_server/mail_server/doctype/mail_server_sync_history/mail_server_sync_history.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors | ||
// For license information, please see license.txt | ||
|
||
// frappe.ui.form.on("Mail Server Sync History", { | ||
// refresh(frm) { | ||
|
||
// }, | ||
// }); |
90 changes: 90 additions & 0 deletions
90
mail_server/mail_server/doctype/mail_server_sync_history/mail_server_sync_history.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
{ | ||
"actions": [], | ||
"autoname": "hash", | ||
"creation": "2024-10-28 12:25:01.227429", | ||
"doctype": "DocType", | ||
"engine": "InnoDB", | ||
"field_order": [ | ||
"section_break_gdn1", | ||
"user", | ||
"source", | ||
"column_break_xk0e", | ||
"domain_name", | ||
"last_synced_at", | ||
"last_synced_mail" | ||
], | ||
"fields": [ | ||
{ | ||
"fieldname": "section_break_gdn1", | ||
"fieldtype": "Section Break" | ||
}, | ||
{ | ||
"fieldname": "user", | ||
"fieldtype": "Link", | ||
"in_list_view": 1, | ||
"label": "User", | ||
"options": "User", | ||
"reqd": 1, | ||
"search_index": 1 | ||
}, | ||
{ | ||
"fieldname": "source", | ||
"fieldtype": "Data", | ||
"in_list_view": 1, | ||
"label": "Source", | ||
"reqd": 1, | ||
"search_index": 1 | ||
}, | ||
{ | ||
"fieldname": "column_break_xk0e", | ||
"fieldtype": "Column Break" | ||
}, | ||
{ | ||
"fieldname": "domain_name", | ||
"fieldtype": "Link", | ||
"in_list_view": 1, | ||
"label": "Domain Name", | ||
"options": "Mail Domain Registry", | ||
"reqd": 1, | ||
"search_index": 1 | ||
}, | ||
{ | ||
"fieldname": "last_synced_at", | ||
"fieldtype": "Datetime", | ||
"label": "Last Synced At", | ||
"search_index": 1 | ||
}, | ||
{ | ||
"fieldname": "last_synced_mail", | ||
"fieldtype": "Data", | ||
"label": "Last Synced Mail" | ||
} | ||
], | ||
"in_create": 1, | ||
"index_web_pages_for_search": 1, | ||
"links": [], | ||
"modified": "2024-10-28 12:28:26.008255", | ||
"modified_by": "Administrator", | ||
"module": "Mail Server", | ||
"name": "Mail Server Sync History", | ||
"naming_rule": "Random", | ||
"owner": "Administrator", | ||
"permissions": [ | ||
{ | ||
"create": 1, | ||
"delete": 1, | ||
"email": 1, | ||
"export": 1, | ||
"print": 1, | ||
"read": 1, | ||
"report": 1, | ||
"role": "System Manager", | ||
"share": 1, | ||
"write": 1 | ||
} | ||
], | ||
"sort_field": "creation", | ||
"sort_order": "DESC", | ||
"states": [], | ||
"track_changes": 1 | ||
} |
75 changes: 75 additions & 0 deletions
75
mail_server/mail_server/doctype/mail_server_sync_history/mail_server_sync_history.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors | ||
# For license information, please see license.txt | ||
|
||
import frappe | ||
from frappe import _ | ||
from frappe.model.document import Document | ||
|
||
|
||
class MailServerSyncHistory(Document): | ||
def before_insert(self) -> None: | ||
self.validate_duplicate() | ||
|
||
def validate_duplicate(self) -> None: | ||
"""Validate if the Mail Server Sync History already exists.""" | ||
|
||
if frappe.db.exists( | ||
"Mail Server Sync History", | ||
{"source": self.source, "user": self.user, "domain_name": self.domain_name}, | ||
): | ||
frappe.throw(_("Mail Server Sync History already exists for this source, user and domain.")) | ||
|
||
def _db_set( | ||
self, | ||
update_modified: bool = True, | ||
commit: bool = False, | ||
notify_update: bool = False, | ||
**kwargs, | ||
) -> None: | ||
"""Updates the document with the given key-value pairs.""" | ||
|
||
self.db_set(kwargs, update_modified=update_modified, commit=commit) | ||
|
||
if notify_update: | ||
self.notify_update() | ||
|
||
|
||
def create_mail_server_sync_history( | ||
source: str, | ||
user: str, | ||
domain_name: str, | ||
last_synced_at: str | None = None, | ||
commit: bool = False, | ||
) -> "MailServerSyncHistory": | ||
"""Create a Mail Server Sync History.""" | ||
|
||
doc = frappe.new_doc("Mail Server Sync History") | ||
doc.source = source | ||
doc.user = user | ||
doc.domain_name = domain_name | ||
doc.last_synced_at = last_synced_at | ||
doc.insert(ignore_permissions=True) | ||
|
||
if commit: | ||
frappe.db.commit() | ||
|
||
return doc | ||
|
||
|
||
def get_mail_server_sync_history(source: str, user: str, domain_name: str) -> "MailServerSyncHistory": | ||
"""Returns the Mail Server Sync History for the given source, user and domain.""" | ||
|
||
if name := frappe.db.exists( | ||
"Mail Server Sync History", {"source": source, "user": user, "domain_name": domain_name} | ||
): | ||
return frappe.get_doc("Mail Server Sync History", name) | ||
|
||
return create_mail_server_sync_history(source, user, domain_name, commit=True) | ||
|
||
|
||
def on_doctype_update(): | ||
frappe.db.add_unique( | ||
"Mail Server Sync History", | ||
["source", "user", "domain_name"], | ||
constraint_name="unique_source_user_domain", | ||
) |
9 changes: 9 additions & 0 deletions
9
mail_server/mail_server/doctype/mail_server_sync_history/test_mail_server_sync_history.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors | ||
# See license.txt | ||
|
||
# import frappe | ||
from frappe.tests.utils import FrappeTestCase | ||
|
||
|
||
class TestMailServerSyncHistory(FrappeTestCase): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters