""" AUTHOR: Khushal P Soonderji DATE: Thursday, 5th Dec., 2024 OBJECTIVE: To work with auth details of SMS clients like Nimbus SMS (India) and Savvy Bulk SMS (Kenya). REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys sys.path.append(".") sys.path.append("..") # My async utils: from utils_v2.string import json from utils_v2.date_time import date_time from utils_v2.database.async_mysql_v2 import AsyncMySQL from utils_v2.database.async_mongo_v2 import AsyncMongo # Base model: from models.behaviour.base import BaseModel # To work with MongoDB: from bson import ObjectId # To work with datatypes: from typing import Literal # To make deep-copies: import copy # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** CLASSES *** # ***** **** # ***************************************************************************************************************** class SMSAuthModel(BaseModel): AUTH_COLLECTION = "_authTokens" async def set( self, db_conn: AsyncMySQL, mongo_conn: AsyncMongo, user_info: dict, client_user_id: dict, auth: dict, token: dict, service_client: Literal["nimbusSmsIndia", "savvyBulkSmsKenya"], auth_type: Literal["auth"], sync_freq: Literal[60, 300, 900] = 300, session_token: str = None ) -> ObjectId | None: """ To store auth/tokens for a particular service to the database. :param db_conn: The database connection (MariaDB) to use to perform the action. :param mongo_conn: The database connection (MongoDB) to use to perform the action. :param user_info: The dictionary that has the user's session information. :param client_user_id: The way the third-party client recognizes your user. :param auth: The authentication details of the account. :param token: The token granted by the third-party service. :param service_client: The name of the company or brand that is providing this service that is being integrated. :param auth_type: To identify the type of authentication being done here. This could indicate simple password authentication, more advance OAuth2.0 authentication, etc. :param sync_freq: The time interval in which mails need to be sync'd. Specify this in seconds. :param session_token: The session token of the user who requested this service. :return: An ObjectId to later store the granted tokens. """ # Note down the timestamp at which this event occurred: request_ts = date_time.get_current_utc_date_time(as_string = False) # Get the identifier from the database: mongo_json = await mongo_conn.find_one_and_update( collection = self.AUTH_COLLECTION, filter = mongo_conn.dict_to_dot_notation({ "serviceType": "email", "user": { "entityId": user_info["entityId"], "billingAccountId": user_info["billingAccountId"] }, "clientUserId": client_user_id }), update = { "$set": { "lastRequestTs": request_ts, "status": "active", "syncFreq": max(sync_freq, 60) }, "$setOnInsert": { "version": "1.0.0", "serviceType": "sms", "client": service_client, "authType": auth_type, "user": user_info, "clientUserId": client_user_id, "auth": auth, "token": token, "firstRefreshTs": None, "lastRefreshTs": None, "firstRequestTs": request_ts } }, projection = { "_id": True }, upsert = True, return_updated = True ) # Tell MariaDB that an authorization request was initiated: db_json = {} if mongo_json is not None: db_json = await self.call_procedure( db_conn = db_conn, proc_name = "entity_integration_save", proc_args = ( user_info["entityId"], # ........................................... 'p_entity_id' service_client, # .................................................. 'p_provider' "Active", # ........................................................ 'p_current_status' "Auth Details Accepted", # ......................................... 'p_last_action' None, # ............................................................ 'p_display_name' None, # ............................................................ 'p_display_picture' str(mongo_json["_id"]), # .......................................... 'p_token_id' json.to_string(python_data = client_user_id, no_space = True), # ... 'p_notes' user_info["userId"] # .............................................. 'p_created_by' ), session_token = session_token ) # Done here: return mongo_json["_id"] if mongo_json and db_json.get("status") == 1 else None async def get( self, mongo_conn: AsyncMongo, token_id: ObjectId | str = None, **kwargs ) -> dict | None: """ To retrieve stored auth/tokens from the database. :param mongo_conn: The database connection (MongoDB) to use to perform the action. :param token_id: The identifier granted providing auth details for the first time in 'set_token'. :param kwargs: Any set of key-value pairs to build custom search criteria. This could be things like the user info, the client, the type of authentication used, or even the kind of service. :return: The retrieved record that has the token, and information about the service and client if found, else None when there is no matching record. """ # Build the filter: filter_json = {k: v for k, v in kwargs.items()} if token_id: filter_json["_id"] = ObjectId(token_id) # If there is no search criteria, we exit with failure: if not filter_json: return None # If there is some filtering possible, # we fetch and return the token: return await mongo_conn.find_one( collection = self.AUTH_COLLECTION, filter = filter_json, projection = { "_id": True, "serviceType": True, "authType": True, "client": True, "clientUserId": True, "token": True } ) # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass