From 44ff7719f3d19b265b2239be8e6ff15aa7ba334b Mon Sep 17 00:00:00 2001 From: khushal Date: Thu, 23 Jan 2025 12:54:52 +0530 Subject: [PATCH] (20250123) Listing permitted from disabled accounts, new activity not allowed. --- api/blueprints/ai/llm/invoke.py | 5 +---- api/blueprints/common/disable.py | 5 +---- .../finstitutions/payments/list_v2.py | 4 +++- .../finstitutions/payments/request_v2.py | 9 +++------ .../finstitutions/trading/symbols/list.py | 9 +++------ api/blueprints/message/chat/list.py | 4 +++- api/blueprints/message/chat/send.py | 9 +++------ .../message/mail/retrieve/list_v2.py | 4 +++- api/blueprints/message/mail/send/send.py | 16 +++++----------- api/blueprints/message/mail/sync/sync_v3.py | 2 ++ api/blueprints/message/sms/list.py | 11 +++++------ api/blueprints/message/sms/send_v2.py | 9 +++------ controllers_v2/core/auth_token.py | 15 +++++++++++++-- shared/constants.py | 18 ++++++++++++++++++ 14 files changed, 66 insertions(+), 54 deletions(-) diff --git a/api/blueprints/ai/llm/invoke.py b/api/blueprints/ai/llm/invoke.py index 0218b5e..6b86a52 100644 --- a/api/blueprints/ai/llm/invoke.py +++ b/api/blueprints/ai/llm/invoke.py @@ -153,10 +153,7 @@ async def invoke_llm( # If the session token is invalid/expired: if kwargs.get("session_info") is None: - return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED - ) + return constants.API_RESPONSE_UNAUTHORIZED # ┳ ┓ # ┃┏┓┓┏┏┓┃┏┏┓ diff --git a/api/blueprints/common/disable.py b/api/blueprints/common/disable.py index 0b9f7c9..aba7796 100644 --- a/api/blueprints/common/disable.py +++ b/api/blueprints/common/disable.py @@ -158,10 +158,7 @@ async def disable_auth_token( # If the session token is invalid/expired: if kwargs.get("session_info") is None: - return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED - ) + return constants.API_RESPONSE_UNAUTHORIZED # Get the user's info: user_info = CoreUserInfoModel(**kwargs.get("session_info")) diff --git a/api/blueprints/finstitutions/payments/list_v2.py b/api/blueprints/finstitutions/payments/list_v2.py index ce635e2..3c2a4e6 100644 --- a/api/blueprints/finstitutions/payments/list_v2.py +++ b/api/blueprints/finstitutions/payments/list_v2.py @@ -169,8 +169,10 @@ async def payment_list( # Get the token ids from the token keys: auth_tokens = await current_app.payments_controller.get_tokens_from_keys( mongo_data_conn = current_app.data_mongo, - token_keys = inbound_data.tokenKeys + token_keys = inbound_data.tokenKeys, + must_be_active = False ) + if not auth_tokens: return constants.API_RESPONSE_NO_AUTH_TOKEN token_ids = [t.authTokenId for t in auth_tokens] # Build the additional filter: diff --git a/api/blueprints/finstitutions/payments/request_v2.py b/api/blueprints/finstitutions/payments/request_v2.py index 7693c02..c9981eb 100644 --- a/api/blueprints/finstitutions/payments/request_v2.py +++ b/api/blueprints/finstitutions/payments/request_v2.py @@ -164,13 +164,10 @@ async def request_payment( # Get the token from the token key: auth_token = await current_app.payments_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, - token_key = inbound_data.tokenKey - ) - if auth_token is None: return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = f"No such token key." + token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # Get the user's info: user_info = CoreUserInfoModel(**kwargs["session_info"]) diff --git a/api/blueprints/finstitutions/trading/symbols/list.py b/api/blueprints/finstitutions/trading/symbols/list.py index 5cf3565..2542b5a 100644 --- a/api/blueprints/finstitutions/trading/symbols/list.py +++ b/api/blueprints/finstitutions/trading/symbols/list.py @@ -167,13 +167,10 @@ async def request_oauth_authorization_url( # Get the auth-token: auth_token = await current_app.trading_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, - token_key = inbound_data.tokenKey - ) - if auth_token is None: return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = f"No such token key." + token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # Start by assuming failure: symbol_list = TradingSymbolListBrokerResponse() diff --git a/api/blueprints/message/chat/list.py b/api/blueprints/message/chat/list.py index 2ee5383..b943531 100644 --- a/api/blueprints/message/chat/list.py +++ b/api/blueprints/message/chat/list.py @@ -171,8 +171,10 @@ async def list_chat_messages( auth_tokens = await current_app.chat_controller.get_tokens_from_keys( mongo_data_conn = current_app.data_mongo, token_keys = inbound_data.tokenKeys, - limit = len(inbound_data.tokenKeys) + limit = len(inbound_data.tokenKeys), + must_be_active = False ) + if not auth_tokens: return constants.API_RESPONSE_NO_AUTH_TOKEN token_ids = [ObjectId(t.authTokenId) for t in auth_tokens] # Check if these tokens belong to the user claiming ownership: diff --git a/api/blueprints/message/chat/send.py b/api/blueprints/message/chat/send.py index 6040bd7..bf8443b 100644 --- a/api/blueprints/message/chat/send.py +++ b/api/blueprints/message/chat/send.py @@ -217,13 +217,10 @@ async def send_chat_messages_api( # Get the token from the token key: auth_token = await current_app.chat_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, - token_key = inbound_data.tokenKey - ) - if auth_token is None: return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = f"No such token key." + token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # ┏┓ ┓ ┓ ┳┳┓ # ┗┓┏┓┏┓┏┫ ╋┣┓┏┓ ┃┃┃┏┓┏┏┏┓┏┓┏┓ diff --git a/api/blueprints/message/mail/retrieve/list_v2.py b/api/blueprints/message/mail/retrieve/list_v2.py index 677bfc9..9237181 100644 --- a/api/blueprints/message/mail/retrieve/list_v2.py +++ b/api/blueprints/message/mail/retrieve/list_v2.py @@ -182,8 +182,10 @@ async def list_mails( # Get the token ids from the token keys: auth_tokens = await current_app.mail_controller.get_tokens_from_keys( mongo_data_conn = current_app.data_mongo, - token_keys = inbound_data.tokenKeys + token_keys = inbound_data.tokenKeys, + must_be_active = False ) + if not auth_tokens: return constants.API_RESPONSE_NO_AUTH_TOKEN token_ids = [t.authTokenId for t in auth_tokens] # Build the additional filter: diff --git a/api/blueprints/message/mail/send/send.py b/api/blueprints/message/mail/send/send.py index da5d587..f68b678 100644 --- a/api/blueprints/message/mail/send/send.py +++ b/api/blueprints/message/mail/send/send.py @@ -222,11 +222,7 @@ async def send_one_mail( if ( kwargs.get("session_info") is None and inbound_headers["Remote-IP"] not in current_app.whitelisted_ips - ): - return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED - ) + ): return constants.API_RESPONSE_UNAUTHORIZED # ┏┓ ┓ • ┏┓┓ ┓ # ┃┃┓┏┏┏┓┏┓┏┓┏┣┓┓┏┓ ┃ ┣┓┏┓┏┃┏ @@ -236,8 +232,10 @@ async def send_one_mail( # Get the token based on the key: auth_token = await current_app.mail_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, - token_key = inbound_data.tokenKey + token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # Get the user's info: if inbound_headers["Remote-IP"] not in current_app.whitelisted_ips: @@ -249,11 +247,7 @@ async def send_one_mail( mongo_data_conn = current_app.data_mongo, user_info = user_info, token_ids = [auth_token.authTokenId] - ): return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = "The account does not belong to this user." - ) + ): return constants.API_RESPONSE_UNAUTHORIZED # ┏┓ ┓ ┳┳┓ •┓ # ┗┓┏┓┏┓┏┫ ┃┃┃┏┓┓┃ diff --git a/api/blueprints/message/mail/sync/sync_v3.py b/api/blueprints/message/mail/sync/sync_v3.py index a401b89..b2c48df 100644 --- a/api/blueprints/message/mail/sync/sync_v3.py +++ b/api/blueprints/message/mail/sync/sync_v3.py @@ -154,7 +154,9 @@ async def sync_mails( auth_token = await current_app.mail_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # Figure out the client connector: match auth_token.client: diff --git a/api/blueprints/message/sms/list.py b/api/blueprints/message/sms/list.py index dab5c38..c883f96 100644 --- a/api/blueprints/message/sms/list.py +++ b/api/blueprints/message/sms/list.py @@ -157,10 +157,7 @@ async def list_sms_messages( # If the session token is invalid/expired: if kwargs.get("session_info") is None: - return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED - ) + return constants.API_RESPONSE_UNAUTHORIZED # ┏┓ ┓ • ┏┓┓ ┓ # ┃┃┓┏┏┏┓┏┓┏┓┏┣┓┓┏┓ ┃ ┣┓┏┓┏┃┏ @@ -171,13 +168,15 @@ async def list_sms_messages( auth_tokens = await current_app.sms_controller.get_tokens_from_keys( mongo_data_conn = current_app.data_mongo, token_keys = inbound_data.tokenKeys, - limit = len(inbound_data.tokenKeys) + limit = len(inbound_data.tokenKeys), + must_be_active = False ) + if not auth_tokens: return constants.API_RESPONSE_NO_AUTH_TOKEN token_ids = [ObjectId(t.authTokenId) for t in auth_tokens] # Check if these tokens belong to the user claiming ownership: if not await token_check.is_authorized( - mongo_conn = current_app.data_mongo, + mongo_data_conn = current_app.data_mongo, user_info = CoreUserInfoModel(**kwargs["session_info"]), token_ids = token_ids ): return ResponseModel( diff --git a/api/blueprints/message/sms/send_v2.py b/api/blueprints/message/sms/send_v2.py index 12e550c..9022be3 100644 --- a/api/blueprints/message/sms/send_v2.py +++ b/api/blueprints/message/sms/send_v2.py @@ -222,13 +222,10 @@ async def send_sms_messages_api( # Get the token from the token key: auth_token = await current_app.sms_controller.get_token_from_key( mongo_data_conn = current_app.data_mongo, - token_key = inbound_data.tokenKey - ) - if auth_token is None: return ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = f"No such token key." + token_key = inbound_data.tokenKey, + must_be_active = True ) + if not auth_token: return constants.API_RESPONSE_NO_AUTH_TOKEN # ┏┓ ┓ ┏┳┓┓ ┏┓┳┳┓┏┓ # ┗┓┏┓┏┓┏┫ ┃ ┣┓┏┓ ┗┓┃┃┃┗┓ diff --git a/controllers_v2/core/auth_token.py b/controllers_v2/core/auth_token.py index 7dbc610..3dc937f 100644 --- a/controllers_v2/core/auth_token.py +++ b/controllers_v2/core/auth_token.py @@ -416,7 +416,6 @@ class CoreAuthTokenController(CoreBaseModel): """ This is to simply modify the status of an account to efficiently activate/deactivate it. - NOTE: The operation succeeds ONLY IF the new status of the account is different from the existing status. :param sql_conn: The database connection (MariaDB) to use to perform the action. :param mongo_data_conn: The database connection (MongoDB) to use to perform the action. :param token_key: The identifier granted by the 'generate_token_key' method. @@ -428,12 +427,12 @@ class CoreAuthTokenController(CoreBaseModel): # Fetch the token from the key: additional_filter = additional_filter or {} - # additional_filter["status"] = {"$ne": new_status} if self._service_type is not None: additional_filter["serviceType"] = self._service_type if self._client is not None: additional_filter["client"] = self._client auth_token = await self.get_token_from_key( mongo_data_conn = mongo_data_conn, token_key = token_key, + must_be_active = False, additional_filter = additional_filter ) @@ -462,6 +461,7 @@ class CoreAuthTokenController(CoreBaseModel): self, mongo_data_conn: AsyncMongo, token_id: ObjectId | str = None, + must_be_active: bool = True, additional_filter: dict = None ) -> CoreAuthTokenModel | None: @@ -469,6 +469,7 @@ class CoreAuthTokenController(CoreBaseModel): To retrieve stored tokens from the database. One token at a time. :param mongo_data_conn: The database connection (MongoDB) to use to perform the action. :param token_id: The identifier of the document that holds the token's details. + :param must_be_active: Set this to False if you want to allow pending and disabled accounts to be retrieved. :param additional_filter: Any addition filters to use. :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. @@ -480,6 +481,7 @@ class CoreAuthTokenController(CoreBaseModel): for k, v in self._base_filter.items(): filter_json[k] = v if additional_filter: for k, v in additional_filter.items(): filter_json[k] = v + if must_be_active: filter_json["status"] = "active" # If there is some filtering possible, we fetch the token: token = await mongo_data_conn.find_one( @@ -494,6 +496,7 @@ class CoreAuthTokenController(CoreBaseModel): self, mongo_data_conn: AsyncMongo, token_key: ObjectId | str = None, + must_be_active: bool = True, additional_filter: dict = None ) -> CoreAuthTokenModel | None: @@ -501,6 +504,7 @@ class CoreAuthTokenController(CoreBaseModel): To retrieve stored tokens from the database. One token at a time. :param mongo_data_conn: The database connection (MongoDB) to use to perform the action. :param token_key: The identifier granted by the 'generate_token_key' method. + :param must_be_active: Set this to False if you want to allow pending and disabled accounts to be retrieved. :param additional_filter: Any addition filters to use. :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. @@ -512,6 +516,7 @@ class CoreAuthTokenController(CoreBaseModel): for k, v in self._base_filter.items(): filter_json[k] = v if additional_filter: for k, v in additional_filter.items(): filter_json[k] = v + if must_be_active: filter_json["status"] = "active" # If there is some filtering possible, we fetch the token: token = await mongo_data_conn.find_one( @@ -554,6 +559,7 @@ class CoreAuthTokenController(CoreBaseModel): mongo_data_conn: AsyncMongo, token_ids: List[ObjectId | str] = None, limit: int = 100, + must_be_active: bool = True, additional_filter: dict = None ) -> List[CoreAuthTokenModel]: @@ -562,6 +568,7 @@ class CoreAuthTokenController(CoreBaseModel): :param mongo_data_conn: The database connection (MongoDB) to use to perform the action. :param token_ids: The identifier of the document that holds the token's details. :param limit: The max. no. of records to pick. + :param must_be_active: Set this to False if you want to allow pending and disabled accounts to be retrieved. :param additional_filter: Any addition filters to use. :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. @@ -573,6 +580,7 @@ class CoreAuthTokenController(CoreBaseModel): for k, v in self._base_filter.items(): filter_json[k] = v if additional_filter: for k, v in additional_filter.items(): filter_json[k] = v + if must_be_active: filter_json["status"] = "active" # If there is some filtering possible, we fetch the token: tokens = await mongo_data_conn.find_many( @@ -589,6 +597,7 @@ class CoreAuthTokenController(CoreBaseModel): mongo_data_conn: AsyncMongo, token_keys: List[ObjectId | str] = None, limit: int = 100, + must_be_active: bool = True, additional_filter: dict = None ) -> List[CoreAuthTokenModel]: @@ -597,6 +606,7 @@ class CoreAuthTokenController(CoreBaseModel): :param mongo_data_conn: The database connection (MongoDB) to use to perform the action. :param token_keys: the identifiers granted by the 'generate_token_key' method. :param limit: The max. no. of records to pick. + :param must_be_active: Set this to False if you want to allow pending and disabled accounts to be retrieved. :param additional_filter: Any addition filters to use. :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. @@ -608,6 +618,7 @@ class CoreAuthTokenController(CoreBaseModel): for k, v in self._base_filter.items(): filter_json[k] = v if additional_filter: for k, v in additional_filter.items(): filter_json[k] = v + if must_be_active: filter_json["status"] = "active" # If there is some filtering possible, we fetch the token: tokens = await mongo_data_conn.find_many( diff --git a/shared/constants.py b/shared/constants.py index 0f6c718..b4db920 100644 --- a/shared/constants.py +++ b/shared/constants.py @@ -36,6 +36,10 @@ import sys sys.path.append(".") sys.path.append("..") +# My utils: +from utils_v2.api.codes import StatusCodes, HttpCodes +from utils_v2.api.response import ResponseModel + # System-level activities: import os @@ -50,6 +54,20 @@ import urllib # ***************************************************************************************************************** +# Project variables: APP_VERSION = "1.0.0" PROJECT_NAME = "utils" MODULE_NAME = "converse" + +# Standard responses: +API_RESPONSE_UNAUTHORIZED = ResponseModel( + status_code = StatusCodes.FAILED, + http_code = HttpCodes.UNAUTHORIZED, + message = "The account does not belong to this user." +) +API_RESPONSE_NO_AUTH_TOKEN = ResponseModel( + status_code = StatusCodes.FAILED, + http_code = HttpCodes.NOT_FOUND, + message = "No such integration(s) found." +) +