diff --git a/.gitignore b/.gitignore
index ebb370b..def2155 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@ __pycache__/
*.pem
*.pyc
-*.pyd
\ No newline at end of file
+*.pyd
+
+/creds/
diff --git a/api/blueprints/finstitutions/trading/oauth/callback.py b/api/blueprints/finstitutions/trading/oauth/callback.py
index 623d92d..fd53062 100644
--- a/api/blueprints/finstitutions/trading/oauth/callback.py
+++ b/api/blueprints/finstitutions/trading/oauth/callback.py
@@ -57,7 +57,8 @@ from utils_v2.api.async_quart import (
only_whitelisted_ips,
limit_rate,
validate_input,
- handle_cancelled_request
+ handle_cancelled_request,
+ handle_failed_request
)
# GMail-related utils:
@@ -112,6 +113,22 @@ def init(blueprint_setup_state):
# ---------------------------------------------------------------------------------------------------------------------
+async def handle_auth_exception():
+
+ print("Hi! Cleaning up...")
+ return await render_template(
+ "/finstitutions/trading/oauth/oauth_failure_v2.html",
+ client = g.client_label,
+ failure_hint = (
+ f"Something went wrong (E). "
+ f"Please use log-id '{g.log_id}' to check with the support team."
+ )
+ )
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
@trading_oauth_callback_bp.route("/callback/", methods = ["POST", "GET"])
@set_api_version(api_version = "1.0.0")
@read_input(sanitize_headers = False, sanitize_data = False)
@@ -127,6 +144,7 @@ def init(blueprint_setup_state):
@log_chain_to_mongo(attr_name = "logs_mongo")
@should_not_be_under_maintenance(attr_name = "is_under_maintenance")
@handle_cancelled_request()
+@handle_failed_request(cleanup_coro = handle_auth_exception)
async def trading_oauth_callback(
trading_client: str = None,
inbound_headers: dict = None,
@@ -145,6 +163,13 @@ async def trading_oauth_callback(
:param kwargs: Any number of extra inputs supplied by the decorators.
:return: A standard response structure.
"""
+ # ┓┏ ┓┓ ┓┏ • ┓ ┓
+ # ┣┫┏┓┏┓┏┫┃┏┓ ┃┃┏┓┏┓┓┏┓┣┓┃┏┓┏
+ # ┛┗┗┻┛┗┗┻┗┗ ┗┛┗┻┛ ┗┗┻┗┛┗┗ ┛
+
+ # Store needed values in 'g':
+ g.log_id = kwargs.get("log_id")
+ g.client_label = "Zerodha (Kite)"
# Start by assuming failure:
success = None
@@ -165,17 +190,43 @@ async def trading_oauth_callback(
# ┛┗┗ ┛┣┛┗┛┛┗┛┗
# ┛
+ # # No valid client:
+ # if success is None: return ResponseModel(
+ # status_code = StatusCodes.FAILED,
+ # http_code = HttpCodes.BAD_REQUEST,
+ # message = f"Invalid/unimplemented client '{trading_client}'."
+ # )
+ #
+ # # When the client was valid:
+ # return ResponseModel(
+ # status_code = StatusCodes.OK if success else StatusCodes.FAILED,
+ # http_code = HttpCodes.SUCCESS if success else HttpCodes.INTERNAL_SERVER_ERROR,
+ # )
+
# No valid client:
- if success is None: return ResponseModel(
- status_code = StatusCodes.FAILED,
- http_code = HttpCodes.BAD_REQUEST,
- message = f"Invalid/unimplemented client '{trading_client}'."
+ if success is None: return await render_template(
+ "/finstitutions/trading/oauth/oauth_failure_v2.html",
+ client = g.client_label,
+ failure_hint = (
+ f"Invalid client '{g.client_label}' selected. "
+ f"Please use log-id '{g.log_id}' to check with the support team."
+ )
)
- # When the client was valid:
- return ResponseModel(
- status_code = StatusCodes.OK if success else StatusCodes.FAILED,
- http_code = HttpCodes.SUCCESS if success else HttpCodes.INTERNAL_SERVER_ERROR,
+ # Successful auth:
+ if success: return await render_template(
+ "/finstitutions/trading/oauth/oauth_success_v2.html",
+ client = g.client_label
+ )
+
+ # Failed auth:
+ if success is None: return await render_template(
+ "/finstitutions/trading/oauth/oauth_failure_v2.html",
+ client = g.client_label,
+ failure_hint = (
+ f"Something went wrong (NE). "
+ f"Please use log-id '{g.log_id}' to check with the support team."
+ )
)
diff --git a/api/blueprints/mail/oauth/callback.py b/api/blueprints/mail/oauth/callback.py
index a72d192..721d963 100644
--- a/api/blueprints/mail/oauth/callback.py
+++ b/api/blueprints/mail/oauth/callback.py
@@ -134,7 +134,7 @@ async def handle_gmail_callback() -> render_template:
# In case the user cancelled halfway through (on Google's screen):
if g.inbound_data.get("error") == "access_denied": return await render_template(
- "/mail/oauth/oauth_cancelled_v2.html",
+ "/message/mail/oauth/oauth_cancelled_v2.html",
mail_client = g.mail_client.title()
)
@@ -167,7 +167,7 @@ async def handle_gmail_callback() -> render_template:
(not auth_token) or
auth_token.clientUserId["email"] != str(google_tokens.email)
): return await render_template(
- "/mail/oauth/oauth_failure_v2.html",
+ "/message/mail/oauth/oauth_failure_v2.html",
mail_client = g.mail_client.title(),
failure_hint = (
f"We were expecting authorization from '{auth_token.clientUserId['email']}', "
@@ -224,13 +224,13 @@ async def handle_gmail_callback() -> render_template:
# Return an HTML response for success:
if tokens_saved: return await render_template(
- "/mail/oauth/oauth_success_v2.html",
+ "/message/mail/oauth/oauth_success_v2.html",
mail_client = g.mail_client.title()
)
# Return an HTML response for failure:
else: return await render_template(
- "/mail/oauth/oauth_failure_v2.html",
+ "/message/mail/oauth/oauth_failure_v2.html",
mail_client = g.mail_client.title(),
failure_hint = f"Unknown error. Please use log-id '{g.log_id}' to check with the support team."
)
@@ -292,7 +292,7 @@ async def mail_auth_callback(
# If something goes wrong:
except Exception as exception: return await render_template(
- "/mail/oauth/oauth_failure_v2.html",
+ "/message/mail/oauth/oauth_failure_v2.html",
mail_client = mail_client.title(),
failure_hint = (
f"An internal server error occurred. "
@@ -305,7 +305,7 @@ async def mail_auth_callback(
# ┛┗┗┻┛┗┗┻┗┗ ┻┛┗┗┛┗┻┗┗┗┻ ┗┛┗┗┗ ┛┗┗
return await render_template(
- "/mail/oauth/oauth_failure_v2.html",
+ "/message/mail/oauth/oauth_failure_v2.html",
mail_client = mail_client.title(),
failure_hint = (
f"Invalid client '{mail_client}' selected. "
diff --git a/api/main.py b/api/main.py
index 471a52e..62643ba 100644
--- a/api/main.py
+++ b/api/main.py
@@ -155,7 +155,7 @@ APP_VERSION = constants.APP_VERSION
# The Quart app:
-app = Quart(__name__, template_folder = r"../views")
+app = Quart(__name__, template_folder = r"../views_v2")
app = cors(app)
# Mail Blueprints:
diff --git a/controllers_v2/finstitutions/trading/zerodha_kite.py b/controllers_v2/finstitutions/trading/zerodha_kite.py
index a387135..4c87d27 100644
--- a/controllers_v2/finstitutions/trading/zerodha_kite.py
+++ b/controllers_v2/finstitutions/trading/zerodha_kite.py
@@ -220,6 +220,7 @@ class ZerodhaKiteTradingController(TradingController):
api_secret = auth_token.auth["apiSecret"]
)
zerodha_auth_token = ZerodhaKiteAuthTokens(**session_data)
+ print(zerodha_auth_token)
# Prepare the inputs to save to the database:
auth_url = await self.get_authorization_url(api_key = auth_token.auth["apiKey"])
diff --git a/kill.sh b/kill.sh
index 159505a..368f446 100644
--- a/kill.sh
+++ b/kill.sh
@@ -3,6 +3,7 @@
# Kill all the scripts:
echo "Killing the script."
pkill -9 -f "$(pwd)/api/main.py"
+pkill -9 -f "$(pwd)/wsocket/main.py"
# Get the name of the current directory,
# and kill the monitors of the above scripts:
diff --git a/run.sh b/run.sh
index 702cf79..b5caa9c 100644
--- a/run.sh
+++ b/run.sh
@@ -3,6 +3,7 @@
# Use this to run the microservice without any docker setup.
source .venv/bin/activate
python3 "$(pwd)/api/main.py" --host "0.0.0.0" --port 5106 --workers 4 --script-id "kps_cnv_KBC3MoaU" &
+python3 "$(pwd)/wsocket/main.py" &
deactivate
# All done:
diff --git a/socketio/main.py b/socketio/main.py
deleted file mode 100644
index 67d39f7..0000000
--- a/socketio/main.py
+++ /dev/null
@@ -1,202 +0,0 @@
-"""
-
- AUTHOR:
-
- Khushal P Soonderji
-
- DATE:
-
- Create: Saturday, 18th May, 2022
- Update: Thursday, 22nd Aug. 2024
-
- OBJECTIVE:
-
- To provide an easy way to work with '.json' data and files.
-
- REFERENCES:
-
- 1) https://www.w3schools.com/python/python_json.asp
-
- DOWNLOADS:
-
- N/A
-
-"""
-
-
-# *****************************************************************************************************************
-# ***** ****
-# *** IMPORT ***
-# ***** ****
-# *****************************************************************************************************************
-
-
-# To make sibling directories accessible for imports:
-import sys
-sys.path.append(".")
-sys.path.append("..")
-
-# System-level activities:
-import io
-
-# To work with the JSON standard:
-import json
-
-# To work with files:
-from utils_v2.system import files
-
-
-# *****************************************************************************************************************
-# ***** ****
-# *** MACROS / ONE-TIME INIT ***
-# ***** ****
-# *****************************************************************************************************************
-
-
-# --- Nothing Yet
-
-
-# *****************************************************************************************************************
-# ***** ****
-# *** VARIABLES ***
-# ***** ****
-# *****************************************************************************************************************
-
-
-# --- Nothing Yet
-
-
-# *****************************************************************************************************************
-# ***** ****
-# *** FUNCTIONS ***
-# ***** ****
-# *****************************************************************************************************************
-
-
-def from_string(json_data):
-
- """
- Decodes a JSON string to a pythonic variable like a dict.
- :param json_data: The JSON string to decode.
- :return: The decoded pythonic variable.
- """
-
- python_data = json.loads(json_data)
- return python_data
-
-
-# ---------------------------------------------------------------------------------------------------------------------
-
-
-def to_string(
- python_data,
- indent = 4,
- default = None,
- separators = None,
- no_space = False
-):
-
- """
- Converts the given pythonic data to a JSON string.
- :param python_data: The input data like a dict.
- :param indent: The tab-width for pretty presentation.
- :param default: The function to use on something that cannot be directly parsed into a JSON string.
- :param separators: Custom separators to use.
- :param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not
- good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT
- 'default'.
- :return: The JSON string representation of the input pythonic data.
- """
-
- if no_space:
- json_data = json.dumps(
- python_data,
- default = default,
- separators = (',', ':')
- )
-
- else:
- json_data = json.dumps(
- python_data,
- indent = indent,
- default = default,
- separators = separators
- )
-
- return json_data
-
-
-# ---------------------------------------------------------------------------------------------------------------------
-
-
-def from_file(file):
-
- """
- Reads a JSON file and returns it as a pythonic variable like a dict.
- :param file: The path to the file on the disk or a file held in RAM as a BytesIO object.
- :return: The decoded pythonic variable.
- """
-
- if isinstance(file, io.BytesIO):
- file.seek(0)
- json_data = file.getvalue()
- else: json_data = files.read_file(file)
- python_data = from_string(json_data)
- return python_data
-
-
-# ---------------------------------------------------------------------------------------------------------------------
-
-
-def to_file(
- file,
- python_data,
- indent = 4,
- default = None,
- separators = None,
- no_space = False
-):
-
- """
-
- :param file: Either a path to a file on disk, or a buffer in RAM in the form of a BytesIO object.
- :param python_data: The pythonic data to be converted to the JSON string.
- :param indent: The tab-width for pretty presentation.
- :param default: The function to use on something that cannot be directly parsed into a JSON string.
- :param separators: Custom separators to use.
- :param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not
- good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT
- 'default'.
- :return: True/False if a path was given, else the same BytesIO object with the written JSON data.
- """
-
- json_data = to_string(
- python_data,
- indent = indent,
- default = default,
- separators = separators,
- no_space = no_space
- )
-
- if isinstance(file, io.BytesIO):
- file.write(json_data.encode("utf-8"))
- file.seek(0)
- return file
-
- else:
- try:
- files.write_file(file, json_data, mode = "w")
- return True
- except: return False
-
-
-# *****************************************************************************************************************
-# ***** ****
-# *** MAIN PROGRAM ***
-# ***** ****
-# *****************************************************************************************************************
-
-
-if __name__ == "__main__":
-
- pass
diff --git a/views_v2/finstitutions/trading/oauth/oauth_cancelled_v2.html b/views_v2/finstitutions/trading/oauth/oauth_cancelled_v2.html
index 368e9a2..0bff500 100644
--- a/views_v2/finstitutions/trading/oauth/oauth_cancelled_v2.html
+++ b/views_v2/finstitutions/trading/oauth/oauth_cancelled_v2.html
@@ -101,7 +101,7 @@
!
Authorization Cancelled
-
It seems that the authorization for your {{ mail_client }} account was cancelled unexpectedly.
+
It seems that the authorization for your {{ client }} account was cancelled unexpectedly.
Please feel free to try again whenever you feel like it. You can close this tab at any time.