(20241212) Reorganizing code to perform core actions in one place.

This commit is contained in:
2024-12-12 18:34:51 +05:30
parent 70c817b3b8
commit fb95e0b38c
50 changed files with 1259 additions and 3166 deletions
+3 -2
View File
@@ -63,8 +63,9 @@ from utils_v2.api.async_quart import (
from shared import constants
# Data Models:
from models.data.api.ai.llm import LLMRequestHeaders, LLMInput
from models.data.core.user import CoreUserInfoModel
from models.api.ai.llm import LLMRequestHeaders
from models.core.ai.llm import LLMInput
from models.core.user import CoreUserInfoModel
# For asynchronous activities:
import asyncio
+6 -3
View File
@@ -63,6 +63,9 @@ from utils_v2.api.async_quart import (
# GMail-related utils:
from utils_v2.goog.gmail.gmail_client import SCOPES_GMAIL_MAIL_MANAGEMENT
# Data Models:
from models.core.auth_token import CoreAuthTokenModel
# Common:
from shared import constants
@@ -113,7 +116,7 @@ def init(blueprint_setup_state):
api_version = "1.0.0",
project = constants.PROJECT_NAME,
log_type = constants.MODULE_NAME,
operation = "gmailCllbk",
operation = "gmailClbk",
log_input = 2,
log_output = 1,
sensitive_keys = ["sessionToken", "X-Session-Token"]
@@ -156,7 +159,7 @@ async def handle_gmail_callback() -> render_template:
# Here's where we do the checking of the e-mails,
# if they don't match, we reject the authorization:
auth_token = await current_app.mail_oauth_model.get_token(
auth_token = await current_app.mail_controller.get_token(
mongo_conn = current_app.data_mongo,
token_id = g.inbound_data["state"]
)
@@ -211,7 +214,7 @@ async def handle_gmail_callback() -> render_template:
auth_token.clientUserId = google_tokens.client_user_id
auth_token.token = google_tokens.model_dump()
auth_token.status = "active"
tokens_saved = await current_app.mail_oauth_model.set_token(
tokens_saved = await current_app.mail_controller.set_token(
db_conn = current_app.sql_writer,
mongo_conn = current_app.data_mongo,
session_token = g.inbound_headers.get("X-Session-Token"),
+3 -3
View File
@@ -67,11 +67,11 @@ from utils_v2.goog.gmail.gmail_client import SCOPES_GMAIL_MAIL_MANAGEMENT
from shared import constants
# Data Models:
from models.data.api.mail.oauth import (
from models.api.mail.oauth import (
OAuthMailAuthorizationRequestHeaders,
OAuthMailAuthorizationRequestData
)
from models.data.core.auth_token import CoreAuthTokenModel
from models.core.auth_token import CoreAuthTokenModel
# For asynchronous activities:
import asyncio
@@ -175,7 +175,7 @@ async def request_oauth_authorization_url(
# ┗┛┗ ┛┗┗ ┛ ┗┻┗┗ ┻ ┗┛┛┗┗ ┛┗ ┻┗┻
# Make a user identifier from the session info:
token_id = await current_app.mail_oauth_model.get_token_id(
token_id = await current_app.mail_controller.get_token_id(
db_conn = current_app.sql_writer,
mongo_conn = current_app.data_mongo,
auth_token = CoreAuthTokenModel(
+256
View File
@@ -0,0 +1,256 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Monday, 2nd Dec., 2024
OBJECTIVE:
To receive requests for synchronising mails from various mail clients to the database. Sync'ing means we pull
the mail from the mail client (like GMail) and store it to our database. The mail is then ready for showing on
the UI at any time.
REFERENCES:
N/A
DOWNLOADS:
N/A
NOTES:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")
# For using Quart:
from quart import Blueprint, current_app, g, request
# My utils:
from utils_v2.string import json
from utils_v2.database.async_mongo_v2 import AsyncMongo
from utils_v2.api.codes import StatusCodes, HttpCodes
from utils_v2.api.response import ResponseModel
from utils_v2.api.async_quart import (
set_api_version,
read_input,
get_session_info,
log_request_to_mongo,
log_chain_to_mongo,
should_not_be_under_maintenance,
only_whitelisted_ips,
limit_rate,
validate_input,
handle_cancelled_request
)
# GMail-related utils:
from utils_v2.goog.gmail.gmail_client import SCOPES_GMAIL_MAIL_MANAGEMENT
from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens
# Common:
from shared import constants
# Data Models:
from models.core.user import CoreUserInfoModel
from models.api.mail.sync import MailSyncRequestHeaders, MailSyncRequestData
from models.api.mail.sync import MailSyncOneResult, MailSyncManyResults
# To work with datatypes:
from typing import Literal
# For asynchronous activities:
import asyncio
# To work with LLMs:
from langchain_openai import ChatOpenAI
# To work with date and time:
import datetime
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# Related to Quart:
mail_sync_bp = Blueprint("mail_sync", __name__)
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
@mail_sync_bp.record_once
def init(blueprint_setup_state):
# This gets called when the blueprint is registered.
# Consider this to be a one-time setup for the whole blueprint:
pass
# ---------------------------------------------------------------------------------------------------------------------
async def sync_mails(
user_info: CoreUserInfoModel,
inbound_headers: dict,
inbound_data: MailSyncRequestData
) -> MailSyncManyResults:
"""
A very simple function, but kept separate so that we get the option to switch between running it in the foreground
and running it in the background.
:param user_info: The information of the user as extracted from the session token.
:param inbound_headers: The headers that came in with the request.
:param inbound_data: The data that came in with the request.
:return: The results of the mail-sync'ing attempt.
"""
# Try to sync the mails:
return await current_app.mail_api_model.sync(
db_conn = current_app.sql_writer,
mongo_conn = current_app.data_mongo,
user_info = user_info,
token_id = inbound_data.tokenId,
llm = current_app.llm,
force_sync = inbound_data.forceSync,
start_date = inbound_data.startDate,
end_date = inbound_data.endDate,
max_count = inbound_data.maxCount,
session_token = inbound_headers["X-Session-Token"],
)
# ---------------------------------------------------------------------------------------------------------------------
@mail_sync_bp.route("/sync", methods = ["POST"])
@mail_sync_bp.route("/sync/<mode>", methods = ["POST"])
@set_api_version(api_version = "1.0.0")
@read_input(sanitize_headers = False, sanitize_data = False)
@get_session_info(key = "X-Session-Token", session_coro = "get_session")
@log_request_to_mongo(
attr_name = "logs_mongo",
project = constants.PROJECT_NAME,
log_type = constants.MODULE_NAME,
operation = "mailSyncApi",
log_input = True,
log_output = True,
sensitive_keys = ["sessionToken", "X-Session-Token"]
)
@log_chain_to_mongo(attr_name = "logs_mongo")
@should_not_be_under_maintenance(attr_name = "is_under_maintenance")
@validate_input(
header_validator = lambda x: MailSyncRequestHeaders(**x).model_dump(),
data_validator = lambda x: MailSyncRequestData(**x)
)
@handle_cancelled_request()
async def sync_mail(
mode: Literal["background", "bg"] = None,
inbound_headers: dict | MailSyncRequestHeaders = None,
inbound_data: dict | MailSyncRequestData = None,
inbound_files: dict = None,
**kwargs
):
"""
Use this when the user wants to pull old mails from some mail client (like GMail) and save it to the database for
ready access on the UI.
:param mode: Set it to one of the specified options to make the sync'ing process go to the background.
:param inbound_headers: auto-extracted by the decorators.
:param inbound_data: auto-extracted by the decorators.
:param inbound_files: auto-extracted by the decorators.
:param kwargs: Any number of extra inputs supplied by the decorators.
:return: A standard response structure.
"""
# If the session token is invalid/expired:
if kwargs.get("session_info") is None:
return ResponseModel(
status_code = StatusCodes.FAILED,
http_code = HttpCodes.UNAUTHORIZED
)
# Make the variables available in the scope of the current request:
g.inbound_headers = inbound_headers
g.inbound_data = inbound_data
# If we've been asked to sync the mails in the background:
if mode in ["background", "bg"]:
current_app.add_background_task(
sync_mails,
user_info = CoreUserInfoModel(**kwargs["session_info"]),
inbound_headers = inbound_headers,
inbound_data = inbound_data
)
return ResponseModel(
status_code = StatusCodes.OK,
http_code = HttpCodes.ACCEPTED,
message = "your mails are being sync'd in the background"
)
# Otherwise we process it right here:
sync_results = await sync_mails(
user_info = CoreUserInfoModel(**kwargs["session_info"]),
inbound_headers = inbound_headers,
inbound_data = inbound_data
)
# Response:
return ResponseModel(
status_code = StatusCodes.FAILED if sync_results.failureCount > 0 else StatusCodes.OK,
http_code = HttpCodes.INTERNAL_SERVER_ERROR if sync_results.failureCount > 0 else HttpCodes.SUCCESS,
message = sync_results.message,
data = {
"totalCount": sync_results.totalCount,
"successCount": sync_results.successCount,
"failureCount": sync_results.failureCount
}
)
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
pass
+1 -1
View File
@@ -63,7 +63,7 @@ from utils_v2.api.async_quart import (
)
# Data models:
from models.data.api.tech.alerts import (
from models.api.tech.alerts import (
ChatAlertRequestHeaders,
ChatAlertRequestData
)