(20250104) Breeze authorization cycle ready for testing on live server.

This commit is contained in:
2025-01-04 16:19:46 +05:30
parent 4fb628eec4
commit e2385c3163
7 changed files with 302 additions and 4 deletions
@@ -46,6 +46,7 @@ from controllers_v2.finstitutions.trading.base import TradingController
# Models: # Models:
from models.core.auth_token import CoreAuthTokenModel from models.core.auth_token import CoreAuthTokenModel
from utils_v2.trading.icici_breeze.models.auth_tokens import ICICIBreezeAuthTokens
from models.api.finstitutions.trading.symbols.list import ( from models.api.finstitutions.trading.symbols.list import (
TradingSymbolListRequestData, TradingSymbolListRequestData,
TradingSymbolListBrokerResponse, TradingSymbolListBrokerResponse,
@@ -194,7 +195,83 @@ class ICICIBreezeTradingController(TradingController):
:return: A structured response to capture the process of callback handling. :return: A structured response to capture the process of callback handling.
""" """
raise NotImplementedError # Start by assuming failure:
response = TradingOAuthCallbackResponse()
icici_auth_token = None
# Check if the callback URL was configured properly:
if not client_user_id:
response.message = "Your callback URL hasn't been configured properly."
return response
# Get the token from the database:
condition = mongo_data_conn.dict_to_dot_notation({"auth": {"userId": client_user_id}})
auth_token = await self.get_token_from_filter(
mongo_data_conn = mongo_data_conn,
filter_json = condition
)
# If not such auth token exists:
if not auth_token:
response.message = (
f"We couldn't find such an integration in our system. "
"Please add this integration first and then try again."
)
return response
# Get the access token and user information from ICICI Breeze:
breeze_session_token = inbound_data.get("apisession")
try:
breeze = BreezeConnect(api_key = auth_token.auth["apiKey"])
breeze.generate_session(
api_secret = auth_token.auth["apiSecret"],
session_token = breeze_session_token
)
session_data = breeze.get_customer_details(api_session = breeze_session_token)
session_data = session_data.get("Success")
icici_auth_token = ICICIBreezeAuthTokens(**session_data)
except Exception as exception:
response.message = f"Client exception: {exception}"
response.exception = exception
return response
# Ensure that the client user id of the incoming callback and the one given in Zerodha's session data match:
if icici_auth_token.userId != client_user_id:
response.message = (
f"We were expecting authorization for the account '{client_user_id}', "
f"but ICICI says the authorization was granted for the account '{icici_auth_token.userId}'. "
"This could be because of a misconfigured callback URL."
)
return response
# Prepare the inputs to save to the database:
auth_url = await self.get_authorization_url(api_key = auth_token.auth["apiKey"])
icici_auth_token.sessionToken = breeze_session_token
auth_token.token = icici_auth_token.model_dump()
# Save the additional auth info to the database:
success = await self.set_token(
sql_conn = sql_conn,
mongo_data_conn = mongo_data_conn,
token_key = auth_token.key,
auth_token = auth_token,
token_notes = {
"apiKey": auth_token.auth["apiKey"],
"authUrl": auth_url
},
display_name = icici_auth_token.userId,
display_picture = icici_auth_token.displayPictureUrl
)
# If saving the token fails:
if not success:
response.message = "Something went wrong towards the end of the authorization cycle."
return response
# Done here:
response.success = True
response.message = "Authorization cycle successfully completed."
return response
# ┏┳┓ ┓• ┏┓ ┓ ┓ # ┏┳┓ ┓• ┏┓ ┓ ┓
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏ # ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏
@@ -224,7 +224,7 @@ class ZerodhaKiteTradingController(TradingController):
# If not such auth token exists: # If not such auth token exists:
if not auth_token: if not auth_token:
response.message = ( response.message = (
f"No such integration found in our system. " f"We couldn't find such an integration in our system. "
"Please add this integration first and then try again." "Please add this integration first and then try again."
) )
return response return response
@@ -238,8 +238,8 @@ class ZerodhaKiteTradingController(TradingController):
) )
zerodha_auth_token = ZerodhaKiteAuthTokens(**session_data) zerodha_auth_token = ZerodhaKiteAuthTokens(**session_data)
except Exception as exception: except Exception as exception:
response.message = f"Client exception: {exception}"
response.exception = exception response.exception = exception
response.message = str(exception)
return response return response
# Ensure that the client user id of the incoming callback and the one given in Zerodha's session data match: # Ensure that the client user id of the incoming callback and the one given in Zerodha's session data match:
+21
View File
@@ -0,0 +1,21 @@
# To work with ICICI Breeze's platform:
from breeze_connect import BreezeConnect
from utils_v2.string import json
api_key = r"2678j1551CSkQ96I5T1862k1685t0b2d"
api_secret = r"kQWD507T9R1169I7AR3473+54@1940P5"
session_token = r"50114591"
print("Init")
breeze = BreezeConnect(api_key = api_key)
print("Creating session.")
breeze.generate_session(
api_secret = api_secret,
session_token = session_token
)
# Getting Customer details:
customer_details = breeze.get_customer_details(api_session = session_token)
print(customer_details)
print("CUSTOMER:", json.to_string(customer_details, default=str))
@@ -0,0 +1,200 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Saturday, 4th Jan., 2025.
OBJECTIVE:
To provide a data model for describing the tokens to be used for ICICI Breeze.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")
# For making data behaviour_models:
from pydantic import BaseModel, Field, field_validator, model_validator, AwareDatetime
from typing import Optional, Literal, Union, Dict, List, Any
# Related to Google:
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# My utils:
from utils_v2.string import json
from utils_v2.string import regex
from utils_v2.date_time import date_time
# To work with date and time:
import datetime
import dateparser
# To make API calls:
import httpx
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
class ICICIBreezeAuthTokens(BaseModel):
userId: str = Field(
description = "The id of the user as assigned by ICICI Breeze.",
alias = "idirect_userid"
)
name: str = Field(
description = "The name of the user.",
alias = "idirect_user_name"
)
displayName: str | None = Field(
description = "The short display name of the user.",
default = None,
alias = "idirect_user_name"
)
displayPictureUrl: str | None = Field(
description = "The display picture of the user.",
default = None,
alias = "avatar_url"
)
loginTs: AwareDatetime = Field(
description = "The time (utc) at which this user logged in.",
alias = "idirect_lastlogin_time"
)
sessionToken: str | None = Field(
description = "The main access token to be used in actual requests.",
default = None
)
# ┏┓ ┏•
# ┃ ┏┓┏┓╋┓┏┓
# ┗┛┗┛┛┗┛┗┗┫
# ┛
class Config:
extra = "ignore"
populate_by_name = True
# ┓┏ ┓• ┓ •
# ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓
# ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗
@field_validator("loginTs", mode = "before")
def parse_dates(cls, value):
if not isinstance(value, datetime.datetime):
parsed = date_time.parse_date_time(
value,
date_formats = ["%d-%b-%Y %H:%M:%S", "%Y-%m-%d %H:%M:%S"],
timezone = date_time.TIMEZONE_IST
)
value = parsed if isinstance(parsed, datetime.datetime) else dateparser.parse(value)
if isinstance(value, datetime.datetime): value = date_time.to_timezone(value, date_time.TIMEZONE_UTC)
return value
# ┏┓ •
# ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏
# ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛
# ┛
pass
# ┏┓ ┏┓
# ┃ ┓┏┏╋┏┓┏┳┓ ┣ ┓┏┏┓┏┏
# ┗┛┗┻┛┗┗┛┛┗┗ ┻ ┗┻┛┗┗┛
pass
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
print("BHOPLI & MUCHHI")
sample_token = {
"exg_trade_date": {
"NSE": "06-Jan-2025",
"BSE": "06-Jan-2025",
"FNO": "06-Jan-2025",
"NDX": "06-Jan-2025"
},
"exg_status": {
"NSE": "C",
"BSE": "C",
"FNO": "Y",
"NDX": "C"
},
"segments_allowed": {
"Trading": "Y",
"Equity": "Y",
"Derivatives": "Y",
"Currency": "Y"
},
"idirect_userid": "BHUSHaI4",
"idirect_user_name": "BHUSHAN C THAKKAR",
"idirect_ORD_TYP": "N",
"idirect_lastlogin_time": "04-Jan-2025 15:41:53",
"mf_holding_mode_popup_flg": "N",
"commodity_exchange_status": "Y",
"commodity_trade_date": "06-Jan-2025",
"commodity_allowed": "C"
}
model = ICICIBreezeAuthTokens(**sample_token)
print(json.to_string(model.model_dump(), default = str))
@@ -10,7 +10,7 @@
OBJECTIVE: OBJECTIVE:
To provide a data model for describing the tokens to be used for Google's APIs. To provide a data model for describing the tokens to be used for Zerodha Kite.
REFERENCES: REFERENCES: