From f47e81c411d10ff04e73db2f96cf3c78d48a8f97 Mon Sep 17 00:00:00 2001 From: khushal Date: Fri, 13 Dec 2024 19:43:56 +0530 Subject: [PATCH] (20241213) Small keyword bug fix. --- api/blueprints/finstitutions/__init__.py | 0 api/blueprints/finstitutions/auth.py | 225 ++++++++++++++++++ .../savvy_bulk_sms/async_savvy_bulk_sms.py | 2 +- 3 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 api/blueprints/finstitutions/__init__.py create mode 100644 api/blueprints/finstitutions/auth.py diff --git a/api/blueprints/finstitutions/__init__.py b/api/blueprints/finstitutions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/blueprints/finstitutions/auth.py b/api/blueprints/finstitutions/auth.py new file mode 100644 index 0000000..1517d20 --- /dev/null +++ b/api/blueprints/finstitutions/auth.py @@ -0,0 +1,225 @@ +""" + + AUTHOR: + + Khushal P Soonderji + + DATE: + + Friday, 13th Dec., 2024 + + OBJECTIVE: + + To receive auth details for various software. + + 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, request + +# My utils: +from utils_v2.string import json +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 +) + +# Common: +from shared import constants + +# To work with MongoDB: +from bson.objectid import ObjectId + +# Data Models: +from models.api.software.auth import SoftwareAuthRequestHeaders, SoftwareAuthRequestData +from models.core.auth_token import CoreAuthTokenModel + +# For asynchronous activities: +import asyncio + + +# ***************************************************************************************************************** +# ***** **** +# *** MACROS / ONE-TIME INIT *** +# ***** **** +# ***************************************************************************************************************** + + +# Related to Quart: +sw_auth_bp = Blueprint("sw_auth", __name__) + + +# ***************************************************************************************************************** +# ***** **** +# *** VARIABLES *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** FUNCTIONS *** +# ***** **** +# ***************************************************************************************************************** + + +@sw_auth_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 + + +# --------------------------------------------------------------------------------------------------------------------- + + +@sw_auth_bp.route("/auth", 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 = "smsAuthApi", + 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: SoftwareAuthRequestHeaders(**x).model_dump(), + data_validator = lambda x: SoftwareAuthRequestData(**x) +) +@handle_cancelled_request() +async def authorize_software_client( + inbound_headers: dict | SoftwareAuthRequestHeaders = None, + inbound_data: dict | SoftwareAuthRequestData = None, + inbound_files: dict = None, + **kwargs +): + + """ + God knows. Don't ask. + :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 + ) + + # Start by assuming failure: + success = False + + # ┏┳┓┓ ┏┓┏┓ ┏┓┏┏• ┏┓┳ + # ┃ ┣┓┏┓ ┃ ┣┫ ┃┃╋╋┓┏┏┓ ┣┫┃ + # ┻ ┛┗┗ ┗┛┛┗ ┗┛┛┛┗┗┗ ┛┗┻ + + if inbound_data.softwareClient == "theCaOfficeAi": + + auth_token = CoreAuthTokenModel( + serviceType = "software", + client = inbound_data.softwareClient, + authType = "auth", + auth = inbound_data.auth.model_dump(), + user = kwargs.get("session_info"), + clientUserId = {}, + status = "active", + syncFreq = 60 + ) + + token_id = await current_app.core_auth_token_controller.get_token_id( + db_conn = current_app.sql_writer, + mongo_conn = current_app.data_mongo, + auth_token = auth_token, + token_notes = {}, + session_token = inbound_headers["X-Session-Token"] + ) + + success = await current_app.core_auth_token_controller.set_token( + db_conn = current_app.sql_writer, + mongo_conn = current_app.data_mongo, + token_id = token_id, + auth_token = auth_token, + token_notes = {}, + session_token = inbound_headers["X-Session-Token"] + ) + + # ┳┓ + # ┣┫┏┓┏┏┓┏┓┏┓┏┏┓ + # ┛┗┗ ┛┣┛┗┛┛┗┛┗ + # ┛ + + # Done here: + return ResponseModel( + status_code = StatusCodes.OK if success else StatusCodes.FAILED, + http_code = HttpCodes.SUCCESS if success else HttpCodes.INTERNAL_SERVER_ERROR, + data = { + "client": inbound_data.softwareClient, + "authorized": success + } + ) + + +# ***************************************************************************************************************** +# ***** **** +# *** MAIN PROGRAM *** +# ***** **** +# ***************************************************************************************************************** + + +if __name__ == "__main__": + + pass diff --git a/utils_v2/sms/models/behaviour/savvy_bulk_sms/async_savvy_bulk_sms.py b/utils_v2/sms/models/behaviour/savvy_bulk_sms/async_savvy_bulk_sms.py index ef23a93..490b34a 100644 --- a/utils_v2/sms/models/behaviour/savvy_bulk_sms/async_savvy_bulk_sms.py +++ b/utils_v2/sms/models/behaviour/savvy_bulk_sms/async_savvy_bulk_sms.py @@ -142,7 +142,7 @@ class AsyncSavvyBulkSMS: self, recipient_number, message - ) -> dict | None: + ) -> SentSMSMessageModel: """ Send one SMS from Savvy Bulk SMS's API.