From 1f8e13e1d5a4d46ec9010ca985c57e278848be39 Mon Sep 17 00:00:00 2001 From: khushal Date: Mon, 20 Jan 2025 14:13:36 +0530 Subject: [PATCH] (20250120) Safety Push. --- utils_v2/api/async_quart.py | 16 ++++---- .../goog/controllers/gmail/gmail_client.py | 7 ++-- .../goog/controllers/gmail/gmail_message.py | 37 +++++++++++++------ 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/utils_v2/api/async_quart.py b/utils_v2/api/async_quart.py index 2bcabe3..5ee2872 100644 --- a/utils_v2/api/async_quart.py +++ b/utils_v2/api/async_quart.py @@ -545,7 +545,7 @@ def read_input( def get_session_info( key: str, - model: str = None, + controller: str = None, session_func: str = None, session_coro: str = None, get: str = None, @@ -560,12 +560,12 @@ def get_session_info( PLEASE USE "ResponseModel" AS THE RETURNED VALUE OF THE API ENDPOINT IF YOU ARE USING THIS DECORATOR. :param key: The key in either the 'inbound_data' or the 'inbound_headers' from which the session info will be available. Examples: 'sessionToken' or 'X-Session-Token'. - :param model: The object from which the func/coro should be called. This could be the name of the variable holding - an instance of a class. Should be available in the scope of 'current_app'. - :param session_func: The synchronous func of the model to call. This can either be an independent function or a + :param controller: The object from which the func/coro should be called. This could be the name of the variable + holding an instance of a class. Should be available in the scope of 'current_app'. + :param session_func: The synchronous func of the controller to call. This can either be an independent function or a class's method. Should be available in the scope of 'current_app'. - :param session_coro: The asynchronous func of the model to call. This can either be an independent function or a - class's method. Ignored if 'func' was provided. Should be available in the scope of 'current_app'. + :param session_coro: The asynchronous func of the controller to call. This can either be an independent function or + a class's method. Ignored if 'func' was provided. Should be available in the scope of 'current_app'. :param get: The field inside the dict to get. Specify this in dot notation. The whole response will be returned as is if this is null. :param mandatory: If set to True, the API call will enforce session checking; and if a session is not found, the @@ -593,12 +593,12 @@ def get_session_info( # For synchronous functions: if session_func: - if model: session_info = getattr(getattr(current_app, model), session_func)(session_id) + if controller: session_info = getattr(getattr(current_app, controller), session_func)(session_id) else: session_info = getattr(current_app, session_func)(session_id) # For asynchronous coroutines: elif session_coro: - if model: session_info = await getattr(getattr(current_app, model), session_coro)(session_id) + if controller: session_info = await getattr(getattr(current_app, controller), session_coro)(session_id) else: session_info = await getattr(current_app, session_coro)(session_id) # If something goes wrong: diff --git a/utils_v2/goog/controllers/gmail/gmail_client.py b/utils_v2/goog/controllers/gmail/gmail_client.py index 441b768..f1e3bde 100644 --- a/utils_v2/goog/controllers/gmail/gmail_client.py +++ b/utils_v2/goog/controllers/gmail/gmail_client.py @@ -51,7 +51,7 @@ from utils_v2.mail import mail_parser from utils_v2.goog.controllers.base import AsyncGoogleBase from utils_v2.goog.models.auth_tokens import GoogleAuthTokens from utils_v2.goog.models.api_call import GoogleApiResponse -from utils_v2.goog.controllers.gmail.gmail_message import GMailMessage +from utils_v2.goog.controllers.gmail.gmail_message import GmailMessage # Related to Google: from google.auth.transport.requests import Request @@ -857,7 +857,7 @@ class AsyncGmailClient(AsyncGoogleBase): async def send_message( self, tokens: GoogleAuthTokens, - message: GMailMessage, + message: GmailMessage, thread_id: str = None, user_id: str = "me" ) -> GoogleApiResponse: @@ -940,7 +940,7 @@ if __name__ == "__main__": async def main(): # Create an instance of the client: - my_gmail = AsyncGMailClient( + my_gmail = AsyncGmailClient( service_name = "gmail", oauth_json = secrets_dict, http_client = test_client, @@ -972,7 +972,6 @@ if __name__ == "__main__": print("DATA:", json.to_string(response.data, default = str)) if not response.success: print("\n\n---\n\n") - print("FULL RESPONSE JSON:", json.to_string(await response.get_json())) asyncio.run(main()) diff --git a/utils_v2/goog/controllers/gmail/gmail_message.py b/utils_v2/goog/controllers/gmail/gmail_message.py index d6ea111..7fbfec0 100644 --- a/utils_v2/goog/controllers/gmail/gmail_message.py +++ b/utils_v2/goog/controllers/gmail/gmail_message.py @@ -96,7 +96,7 @@ from typing import List # ***************************************************************************************************************** -class GMailMessage: +class GmailMessage: def __init__( self, @@ -160,7 +160,7 @@ class GMailMessage: # ┣┫┏┫┏┫ ┃ ┏┓┏┓╋┏┓┏┓╋ # ┛┗┗┻┗┻ ┗┛┗┛┛┗┗┗ ┛┗┗ - def add_text(self, text): + def add_text(self, text) -> None: """ Add plain-text to the mail body. @@ -170,7 +170,7 @@ class GMailMessage: self.message.attach(MIMEText(text, "plain")) - def add_html(self, html_text): + def add_html(self, html_text) -> None: """ Add HTML text to the mail body. @@ -185,7 +185,7 @@ class GMailMessage: image_file: str | io.BytesIO, file_name: str = None, content_id: str = None - ): + ) -> None: """ Add an inline image to the body of the mail. @@ -238,7 +238,7 @@ class GMailMessage: self, attachment_file: str | io.BytesIO, file_name: str = None - ): + ) -> None: """ Add a file as an attachment to the mail. This file, even if possible, will not be rendered on the screen in-line @@ -246,7 +246,7 @@ class GMailMessage: :param attachment_file: The file that you would like to attach. :param file_name: The name of the file. This is the same name by which it will be downloaded. You need not specify this if the input file is specified as a path. Needed when you give the input file as a buffer. - :return: + :return: None. """ # Declare the part to be attached to the multipart message: @@ -277,18 +277,19 @@ class GMailMessage: def get_raw_message( self, - as_base64: bool = True - ): + as_base64: bool = False + ) -> str: """ Get the raw string dump from the current contents of the message. This text will be compliant with RFC 5322 and RFC 2045 (among others). + :param :param as_base64: If set to True, the response will be a URL-safe B64 output, else it'll be a raw string. :return: The standardized raw text dump. either as a raw string or as a Base64 (url-safe) string. """ - if not as_base64: return self.message - else: return base64.urlsafe_b64encode(self.message.as_bytes()).decode() + if as_base64: return base64.urlsafe_b64encode(self.message.as_bytes()).decode() + else: return self.message.as_string() # ***************************************************************************************************************** @@ -300,13 +301,16 @@ class GMailMessage: if __name__ == "__main__": - my_mail = GMailMessage( + # Create an instance of a mail message: + my_mail = GmailMessage( from_email = "sender@gmail.com", to_email = "recipient@gmail.com", subject = "Bhopli is the best!", cc_emails = None, bcc_emails = None ) + + # Add content to it: my_mail.add_html( """ @@ -333,4 +337,13 @@ if __name__ == "__main__": my_mail.add_text("This is how you should pet her 👇") my_mail.add_inline_image(r"../../../../data/images/cat_petting.png") my_mail.add_attachment(r"../../../../data/pdf/sample_label.pdf") - print(my_mail.get_raw_message(as_base64 = False)) + + # Get the raw contents of the message: + mail_raw = my_mail.get_raw_message(as_base64 = False) + print("RAW TYPE:", type(mail_raw)) + + # Try parsing it: + from utils_v2.string import json + from utils_v2.mail import mail_parser + mail_json = mail_parser.parse(mail_raw) + print("PARSED MAIL (JSON):", json.to_string(mail_json, default = str))