Skip to content

Commit

Permalink
feat: init getting user data from shad server (on login)
Browse files Browse the repository at this point in the history
  • Loading branch information
AmooHashem committed Jan 13, 2025
1 parent 2ac062d commit 13f9baf
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 13 deletions.
15 changes: 13 additions & 2 deletions apps/accounts/views/uuid_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from rest_framework import status
from rest_framework.response import Response

from proxies.Shad import get_user_data_from_shad


class UserIDLoginView(BaseLoginView):
user_data_field = 'username'
Expand All @@ -35,7 +37,7 @@ def post(self, request):

# Validate if user_id is a valid UUID
if not self.is_valid_uuid(user_id):
return Response({"error": "Invalid UserID format. Must be a valid UUID."}, status=status.HTTP_400_BAD_REQUEST)
return Response({"error": "Invalid UserID. Must be a valid UUID."}, status=status.HTTP_400_BAD_REQUEST)

# Pass the origin to handle_post
return self.handle_post(request, origin=origin)
Expand All @@ -46,10 +48,19 @@ def get_user_identifier(self, request):
def is_valid_uuid(self, value):
try:
uuid.UUID(str(value))
return True
except ValueError:
return False

try:
user_data = get_user_data_from_shad(
user_uuid=value,
landing_id=284
)
except ValueError as e:
return False

return True

@transaction.atomic
def handle_post(self, request, origin=""):
user_identifier = self.get_user_identifier(request)
Expand Down
82 changes: 72 additions & 10 deletions proxies/Shad.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import uuid
from django.conf import settings

from proxies.http_request_utils import post
from proxies.http_request_utils import get, post

SHAD_LOGIN_USERNAME = settings.SHAD_LOGIN_USERNAME
SHAD_LOGIN_PASSWORD = settings.SHAD_LOGIN_PASSWORD
SHAD_API_URL = 'https://shadapi.noyanet.com/api/v1'


SHAD_API_URL = 'https://shadapi.noyanet.com/api/v1'
class TokenManager:
_token = None

@classmethod
def set_token(cls, token):
cls._token = token

def login_to_Shad(landing_id=284):
@classmethod
def get_token(cls):
return cls._token


def _login_to_shad(landing_id):
"""
Authenticate with the Shad API and store the token.
Returns the full response from the login endpoint.
"""
url = f'{SHAD_API_URL}/account/login/'

payload = {
Expand All @@ -19,15 +32,64 @@ def login_to_Shad(landing_id=284):
"password": SHAD_LOGIN_PASSWORD,
}

return post(url, payload)
response = post(url, payload)

if response.get('data'):
TokenManager.set_token(response['data'])

def get_user_data(token, user_uuid):
url = f'{SHAD_API_URL}/ShadEvent?UserHashId={user_uuid}'
return response


def get_user_data_from_shad(user_uuid, landing_id):
"""
Validate UUID and get user data, handling token expiration automatically.
Args:
user_uuid: The user's UUID to fetch data for
landing_id: The landing ID for authentication
Returns:
API response with user data
Raises:
ValueError: If UUID is invalid, authentication fails, or response contains errors
"""
# First ensure we have a valid UUID
try:
uuid.UUID(str(user_uuid))
except ValueError:
raise ValueError("Invalid UUID format")

# Ensure we're logged in or try initial login
if not TokenManager.get_token():
login_response = _login_to_shad(landing_id)
if not login_response.get('data'):
raise ValueError("Initial login failed")

# Try to get user data
url = f'{SHAD_API_URL}/ShadEvent?UserHashId={user_uuid}'
headers = {
"Authorization": f"Bearer {token}"
"Authorization": f"Bearer {TokenManager.get_token()}"
}
params = {}

response = get(url, params, headers=headers)

# Check for expired token and try relogin once
if response.get('status') == 401 or response.get('error') == 'token_expired':
login_response = _login_to_shad(landing_id)
if not login_response.get('data'):
raise ValueError("Failed to refresh token")

# Retry the request with new token
response = get(url, params, headers={
"Authorization": f"Bearer {TokenManager.get_token()}"
})

status = response.get('status_code')
error_message = response.get('data').get('error')

if error_message or (isinstance(status, int) and status >= 400):
raise ValueError(f"API Error: {error_message} (Status: {status})")

payload = {}
return post(url, payload, headers=headers)
return response
3 changes: 2 additions & 1 deletion proxies/http_request_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ def get_retry_session(retries=5, backoff_factor=0.3,
return session


def get(url, params):
def get(url, params, headers=None):
try:
session = get_retry_session()
response = session.get(
url,
params=params,
headers=headers,
timeout=10
)
response.raise_for_status()
Expand Down

0 comments on commit 13f9baf

Please sign in to comment.