Add subcription feature 6
This commit is contained in:
@@ -1,26 +1,36 @@
|
||||
"""Fetches subscription data for JWT enrichment at login time"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
import httpx
|
||||
from typing import Dict, Any, Optional, List
|
||||
import logging
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from shared.clients.tenant_client import TenantServiceClient
|
||||
from shared.config.base import BaseServiceSettings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SubscriptionFetcher:
|
||||
def __init__(self, tenant_service_url: str):
|
||||
self.tenant_service_url = tenant_service_url.rstrip('/')
|
||||
logger.info("SubscriptionFetcher initialized with URL: %s", self.tenant_service_url)
|
||||
def __init__(self, config: BaseServiceSettings):
|
||||
"""
|
||||
Initialize SubscriptionFetcher with service configuration
|
||||
|
||||
Args:
|
||||
config: BaseServiceSettings containing service configuration
|
||||
"""
|
||||
self.tenant_client = TenantServiceClient(config)
|
||||
logger.info("SubscriptionFetcher initialized with TenantServiceClient")
|
||||
|
||||
async def get_user_subscription_context(
|
||||
self,
|
||||
user_id: str,
|
||||
service_token: str
|
||||
user_id: str
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Fetch user's tenant memberships and subscription data.
|
||||
Fetch user's tenant memberships and subscription data using shared tenant client.
|
||||
Called ONCE at login, not per-request.
|
||||
|
||||
This method uses the shared TenantServiceClient instead of direct HTTP calls,
|
||||
providing better error handling, circuit breaking, and consistency.
|
||||
|
||||
Returns:
|
||||
{
|
||||
@@ -39,103 +49,75 @@ class SubscriptionFetcher:
|
||||
try:
|
||||
logger.debug("Fetching subscription data for user: %s", user_id)
|
||||
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
# Get user's tenant memberships - corrected URL
|
||||
memberships_url = f"{self.tenant_service_url}/api/v1/tenants/members/user/{user_id}"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {service_token}",
|
||||
"Content-Type": "application/json"
|
||||
# Get user's tenant memberships using shared tenant client
|
||||
memberships = await self.tenant_client.get_user_memberships(user_id)
|
||||
|
||||
if not memberships:
|
||||
logger.info(f"User {user_id} has no tenant memberships - returning default subscription context")
|
||||
return {
|
||||
"tenant_id": None,
|
||||
"tenant_role": None,
|
||||
"subscription": {
|
||||
"tier": "starter",
|
||||
"status": "active",
|
||||
"valid_until": None
|
||||
},
|
||||
"tenant_access": []
|
||||
}
|
||||
|
||||
logger.debug("Fetching user memberships from URL: %s", memberships_url)
|
||||
response = await client.get(memberships_url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
logger.error(f"Failed to fetch user memberships: {response.status_code}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to fetch user memberships"
|
||||
)
|
||||
# Get primary tenant (first one, or the one with highest role)
|
||||
primary_membership = memberships[0]
|
||||
for membership in memberships:
|
||||
if membership.get("role") == "owner":
|
||||
primary_membership = membership
|
||||
break
|
||||
|
||||
memberships = response.json()
|
||||
|
||||
if not memberships:
|
||||
logger.info(f"User {user_id} has no tenant memberships - returning default subscription context")
|
||||
return {
|
||||
"tenant_id": None,
|
||||
"tenant_role": None,
|
||||
"subscription": {
|
||||
"tier": "starter",
|
||||
"status": "active",
|
||||
"valid_until": None
|
||||
},
|
||||
"tenant_access": []
|
||||
}
|
||||
primary_tenant_id = primary_membership["tenant_id"]
|
||||
primary_role = primary_membership["role"]
|
||||
|
||||
# Get primary tenant (first one, or the one with highest role)
|
||||
primary_membership = memberships[0]
|
||||
for membership in memberships:
|
||||
if membership.get("role") == "owner":
|
||||
primary_membership = membership
|
||||
break
|
||||
|
||||
primary_tenant_id = primary_membership["tenant_id"]
|
||||
primary_role = primary_membership["role"]
|
||||
|
||||
# Get subscription for primary tenant - FIXED: Use correct endpoint
|
||||
subscription_url = f"{self.tenant_service_url}/api/v1/tenants/subscriptions/{primary_tenant_id}/active"
|
||||
subscription_response = await client.get(subscription_url, headers=headers)
|
||||
|
||||
if subscription_response.status_code != 200:
|
||||
logger.error(f"Failed to fetch subscription for tenant {primary_tenant_id}: {subscription_response.status_code}")
|
||||
# Return with basic info but no subscription
|
||||
return {
|
||||
"tenant_id": primary_tenant_id,
|
||||
"tenant_role": primary_role,
|
||||
"subscription": None,
|
||||
"tenant_access": memberships
|
||||
}
|
||||
|
||||
subscription_data = subscription_response.json()
|
||||
|
||||
# Build tenant access list with subscription info
|
||||
tenant_access = []
|
||||
for membership in memberships:
|
||||
tenant_id = membership["tenant_id"]
|
||||
role = membership["role"]
|
||||
|
||||
# Get subscription for each tenant - FIXED: Use correct endpoint
|
||||
tenant_sub_url = f"{self.tenant_service_url}/api/v1/tenants/subscriptions/{tenant_id}/active"
|
||||
tenant_sub_response = await client.get(tenant_sub_url, headers=headers)
|
||||
|
||||
tier = "starter" # default
|
||||
if tenant_sub_response.status_code == 200:
|
||||
tenant_sub = tenant_sub_response.json()
|
||||
tier = tenant_sub.get("plan", "starter")
|
||||
|
||||
tenant_access.append({
|
||||
"id": tenant_id,
|
||||
"role": role,
|
||||
"tier": tier
|
||||
})
|
||||
# Get subscription for primary tenant using shared tenant client
|
||||
subscription_data = await self.tenant_client.get_subscription_details(primary_tenant_id)
|
||||
|
||||
if not subscription_data:
|
||||
logger.warning(f"No subscription data found for primary tenant {primary_tenant_id}")
|
||||
# Return with basic info but no subscription
|
||||
return {
|
||||
"tenant_id": primary_tenant_id,
|
||||
"tenant_role": primary_role,
|
||||
"subscription": {
|
||||
"tier": subscription_data.get("plan", "starter"),
|
||||
"status": subscription_data.get("status", "active"),
|
||||
"valid_until": subscription_data.get("valid_until", None)
|
||||
},
|
||||
"tenant_access": tenant_access
|
||||
"subscription": None,
|
||||
"tenant_access": memberships
|
||||
}
|
||||
|
||||
except httpx.HTTPError as e:
|
||||
logger.error(f"HTTP error fetching subscription data: {str(e)}", exc_info=True)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"HTTP error fetching subscription data: {str(e)}"
|
||||
)
|
||||
# Build tenant access list with subscription info
|
||||
tenant_access = []
|
||||
for membership in memberships:
|
||||
tenant_id = membership["tenant_id"]
|
||||
role = membership["role"]
|
||||
|
||||
# Get subscription for each tenant using shared tenant client
|
||||
tenant_sub = await self.tenant_client.get_subscription_details(tenant_id)
|
||||
|
||||
tier = "starter" # default
|
||||
if tenant_sub:
|
||||
tier = tenant_sub.get("plan", "starter")
|
||||
|
||||
tenant_access.append({
|
||||
"id": tenant_id,
|
||||
"role": role,
|
||||
"tier": tier
|
||||
})
|
||||
|
||||
return {
|
||||
"tenant_id": primary_tenant_id,
|
||||
"tenant_role": primary_role,
|
||||
"subscription": {
|
||||
"tier": subscription_data.get("plan", "starter"),
|
||||
"status": subscription_data.get("status", "active"),
|
||||
"valid_until": subscription_data.get("valid_until", None)
|
||||
},
|
||||
"tenant_access": tenant_access
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching subscription data: {str(e)}", exc_info=True)
|
||||
raise HTTPException(
|
||||
|
||||
Reference in New Issue
Block a user