(20250117) Major revamping in the mail module. Everything revamped. Sending is a pending task.

This commit is contained in:
2025-01-17 15:36:59 +05:30
parent 32c243f3d3
commit be9bdf797a
12 changed files with 675 additions and 65 deletions
+136 -7
View File
@@ -66,12 +66,12 @@ from typing import List, Any
# To make HTTP requests:
import httpx
# To work with MongoDB:
from bson.objectid import ObjectId
# To parse the HTML content in the mail:
from bs4 import BeautifulSoup
# To work with MongoDB:
from bson import ObjectId
# To work with date and time:
import datetime
@@ -264,6 +264,33 @@ class MailController(CoreMessageController, ABC):
# Done here:
return text_parts
def drop_attachments(
self,
payload: dict
) -> dict:
"""
At the time of creating the system, we don't have a mechanism to save, organize and serve files in a
satisfactory way. This is a simple way to ignore all attachments till then by dropping them entirely.
:param payload: The mail's full payload.
:return: The same payload, but with all attachment data wiped clean.
"""
# If the part is some sort of file:
if payload["contentMainType"] not in ["multipart", "text"]:
payload["payload"] = None
payload["payloadId"] = None
payload["payloadUrl"] = None
# If the payload is of multipart type,
# we use recursion to look inside it:
elif payload["contentMainType"] == "multipart":
for part in payload["payload"]:
self.drop_attachments(part)
# Done here:
return payload
# ┏┓┏┓ ┓ ┏┓ ┏┓
# ┃┃┣┫┓┏╋┣┓┏┛ ┃┫
# ┗┛┛┗┗┻┗┛┗┗━•┗┛
@@ -317,6 +344,34 @@ class MailController(CoreMessageController, ABC):
pass
@abstractmethod
async def refresh_authorization(
self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo,
mail_client: AsyncGMailClient,
http_client: httpx.AsyncClient,
auth_token: CoreAuthTokenModel,
force_refresh: bool = False,
session_token: str = None
) -> CoreAuthTokenModel:
"""
To refresh the third-party client's access/authorization token(s) before use.
:param sql_conn: The database connection to use when storing the refreshed tokens.
:param mongo_data_conn: The database connection to use when storing the refreshed tokens.
:param mail_client: The connection of the third-party mail client.
:param http_client: The HTTP client to use to make the token refresh request.
:param auth_token: The auth-token model of the existing integration. This may get updated if a refresh is needed
(or forced).
:param force_refresh: Whether, or not, you would like to force a refresh even if the token hasn't expired yet.
:param session_token: The session token of the user. This will be null if this method is invoked by a cron
script in the background. Needed only to identify the user in case of a failure to send a timely alert.
:return: The same auth-token model instance, but maybe with updated tokens.
"""
pass
# ┳┳┓ •┓ ┏┓ • •
# ┃┃┃┏┓┓┃ ┗┓┓┏┏┳┓┏┳┓┏┓┏┓┓┓┏┓╋┓┏┓┏┓
# ┛ ┗┗┻┗┗ ┗┛┗┻┛┗┗┛┗┗┗┻┛ ┗┗┗┻┗┗┗┛┛┗
@@ -372,7 +427,7 @@ class MailController(CoreMessageController, ABC):
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo,
mail_client: AsyncGMailClient,
token_key: ObjectId | str,
auth_token: CoreAuthTokenModel,
user_info: CoreUserInfoModel | None,
llm: CoreLLMController = None,
force_sync: bool = False,
@@ -387,7 +442,7 @@ class MailController(CoreMessageController, ABC):
:param sql_conn: The database connection to use to perform this task.
:param mongo_data_conn: The database connection to use to perform this task.
:param mail_client: The instance of the third-party mail client that will be used to get the URL.
:param token_key: The key by which the auth-tokens to this account are identified.
:param auth_token: The credentials to the account with the third-party client.
:param user_info: The information about your user who is trying to use this system. Needed to note LLM token
usage in the process of mail summarization.
:param llm: The instance of the LLm that can be used to summarize the contents of the mail.
@@ -410,7 +465,58 @@ class MailController(CoreMessageController, ABC):
# Use these to show your users their mails once the mails are on your server. This would include activities like
# listing mails, showing full mails, showing mail trails, etc.
pass
async def list_mails(
self,
mongo_data_conn: AsyncMongo,
token_ids: List[ObjectId | str],
limit: int = 100,
skip: int = 0,
additional_filter: dict = None
) -> List[CoreMessageModel] | None:
"""
To list mails (just previews, not full payloads).
:param mongo_data_conn: The database connection to use to fetch the data.
:param token_ids: The ids by which the mails will be identified. These are the auth-token ids of the accounts to
which the mails belong.
:param limit: The max. no. of mails to fetch. Good for pagination.
:param skip: The no. of initial mails to skip before picking mails to show. Good for pagination.
:param additional_filter: Any additional constraints.
:return: A list of message models that describe the contents of the mails.
"""
# Regardless of what additional filter is provided from outside,
# we add a mail-selecting filter here:
if additional_filter is None: additional_filter = {}
additional_filter["serviceType"] = "email"
# Simply call the core model:
return await self.get_message_previews(
mongo_data_conn = mongo_data_conn,
token_ids = token_ids,
limit = limit,
skip = skip,
additional_filter = additional_filter
)
async def get_one_mail(
self,
mongo_data_conn: AsyncMongo,
message_id: ObjectId | str
) -> CoreMessageModel | None:
"""
To get one full mail (the full payload, not just the preview).
:param mongo_data_conn: The database connection to use to fetch the data.
:param message_id: The ObjectId of the document that holds the mail.
:return: The message model containing the full payload of the mail.
"""
# Simply call the core model:
return await self.get_message(
mongo_data_conn = mongo_data_conn,
message_id = message_id
)
# ┳┳┓ •┓ ┏┓ ┓•
# ┃┃┃┏┓┓┃ ┗┓┏┓┏┓┏┫┓┏┓┏┓
@@ -427,7 +533,30 @@ class MailController(CoreMessageController, ABC):
# We cannot modify the mails themselves, but we can set/unset tags on them for internal referencing and filtering.
# This will help the users organize their inboxes well.
pass
async def update_mail_tags(
self,
mongo_data_conn: AsyncMongo,
message_id: ObjectId | str,
unset_tags: List[str] = None,
set_tags: List[str] = None
) -> bool:
"""
To set and unset tags on a mail.
:param mongo_data_conn: The database connection to use to perform this action.
:param message_id: The ObjectId of the document in MongoDb that holds the message.
:param unset_tags: The list of tags to unset (done before setting new tags).
:param set_tags: The list of tags to set (done after unsetting old tags).
:return: True if successful, else False.
"""
# Simply call the core model:
return await self.update_message_tags(
mongo_data_conn = mongo_data_conn,
message_id = message_id,
unset_tags = unset_tags,
set_tags = set_tags
)
# *****************************************************************************************************************