Improve the frontend and fix TODOs
This commit is contained in:
@@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, HTTPException, status, Path, Query
|
||||
from typing import List, Dict, Any
|
||||
from uuid import UUID
|
||||
|
||||
from app.schemas.tenants import TenantMemberResponse
|
||||
from app.schemas.tenants import TenantMemberResponse, AddMemberWithUserCreate
|
||||
from app.services.tenant_service import EnhancedTenantService
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
from shared.routing.route_builder import RouteBuilder
|
||||
@@ -29,6 +29,116 @@ def get_enhanced_tenant_service():
|
||||
logger.error("Failed to create enhanced tenant service", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Service initialization failed")
|
||||
|
||||
@router.post(route_builder.build_base_route("{tenant_id}/members/with-user", include_tenant_prefix=False), response_model=TenantMemberResponse)
|
||||
@track_endpoint_metrics("tenant_add_member_with_user_creation")
|
||||
async def add_team_member_with_user_creation(
|
||||
member_data: AddMemberWithUserCreate,
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
|
||||
):
|
||||
"""
|
||||
Add a team member to tenant with optional user creation (pilot phase).
|
||||
|
||||
This endpoint supports two modes:
|
||||
1. Adding an existing user: Set user_id and create_user=False
|
||||
2. Creating a new user: Set create_user=True and provide email, full_name, password
|
||||
|
||||
In pilot phase, this allows owners to directly create users with passwords.
|
||||
In production, this will be replaced with an invitation-based flow.
|
||||
"""
|
||||
try:
|
||||
user_id_to_add = member_data.user_id
|
||||
|
||||
# If create_user is True, create the user first via auth service
|
||||
if member_data.create_user:
|
||||
logger.info(
|
||||
"Creating new user before adding to tenant",
|
||||
tenant_id=str(tenant_id),
|
||||
email=member_data.email,
|
||||
requested_by=current_user["user_id"]
|
||||
)
|
||||
|
||||
# Call auth service to create user
|
||||
from shared.clients.auth_client import AuthServiceClient
|
||||
from app.core.config import settings
|
||||
|
||||
auth_client = AuthServiceClient(settings)
|
||||
|
||||
# Map tenant role to user role
|
||||
# tenant roles: admin, member, viewer
|
||||
# user roles: admin, manager, user
|
||||
user_role_map = {
|
||||
"admin": "admin",
|
||||
"member": "manager",
|
||||
"viewer": "user"
|
||||
}
|
||||
user_role = user_role_map.get(member_data.role, "user")
|
||||
|
||||
try:
|
||||
user_create_data = {
|
||||
"email": member_data.email,
|
||||
"full_name": member_data.full_name,
|
||||
"password": member_data.password,
|
||||
"phone": member_data.phone,
|
||||
"role": user_role,
|
||||
"language": member_data.language or "es",
|
||||
"timezone": member_data.timezone or "Europe/Madrid"
|
||||
}
|
||||
|
||||
created_user = await auth_client.create_user_by_owner(user_create_data)
|
||||
user_id_to_add = created_user.get("id")
|
||||
|
||||
logger.info(
|
||||
"User created successfully",
|
||||
user_id=user_id_to_add,
|
||||
email=member_data.email,
|
||||
tenant_id=str(tenant_id)
|
||||
)
|
||||
|
||||
except Exception as auth_error:
|
||||
logger.error(
|
||||
"Failed to create user via auth service",
|
||||
error=str(auth_error),
|
||||
email=member_data.email
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to create user account: {str(auth_error)}"
|
||||
)
|
||||
|
||||
# Add the user (existing or newly created) to the tenant
|
||||
result = await tenant_service.add_team_member(
|
||||
str(tenant_id),
|
||||
user_id_to_add,
|
||||
member_data.role,
|
||||
current_user["user_id"]
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Team member added successfully",
|
||||
tenant_id=str(tenant_id),
|
||||
user_id=user_id_to_add,
|
||||
role=member_data.role,
|
||||
user_was_created=member_data.create_user
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Add team member with user creation failed",
|
||||
tenant_id=str(tenant_id),
|
||||
error=str(e)
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to add team member"
|
||||
)
|
||||
|
||||
|
||||
@router.post(route_builder.build_base_route("{tenant_id}/members", include_tenant_prefix=False), response_model=TenantMemberResponse)
|
||||
@track_endpoint_metrics("tenant_add_member")
|
||||
async def add_team_member(
|
||||
@@ -38,7 +148,7 @@ async def add_team_member(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
|
||||
):
|
||||
"""Add a team member to tenant with enhanced validation and role management"""
|
||||
"""Add an existing team member to tenant (legacy endpoint)"""
|
||||
|
||||
try:
|
||||
result = await tenant_service.add_team_member(
|
||||
|
||||
@@ -825,10 +825,53 @@ async def cancel_subscription(
|
||||
"""Cancel subscription for a tenant"""
|
||||
|
||||
try:
|
||||
# TODO: Add access control - verify user is owner/admin of tenant
|
||||
# In a real implementation, you would need to retrieve the subscription ID from the database
|
||||
# For now, this is a placeholder
|
||||
subscription_id = "sub_test" # This would come from the database
|
||||
# Verify user is owner/admin of tenant
|
||||
user_id = current_user.get('user_id')
|
||||
user_role = current_user.get('role', '').lower()
|
||||
|
||||
# Check if user is tenant owner or admin
|
||||
from app.services.tenant_service import EnhancedTenantService
|
||||
from shared.database.base import create_database_manager
|
||||
|
||||
tenant_service = EnhancedTenantService(create_database_manager())
|
||||
|
||||
# Verify tenant access and role
|
||||
async with tenant_service.database_manager.get_session() as session:
|
||||
await tenant_service._init_repositories(session)
|
||||
|
||||
# Get tenant member record
|
||||
member = await tenant_service.member_repo.get_member_by_user_and_tenant(
|
||||
str(user_id), str(tenant_id)
|
||||
)
|
||||
|
||||
if not member:
|
||||
logger.warning("User not member of tenant",
|
||||
user_id=user_id,
|
||||
tenant_id=str(tenant_id))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Access denied: You are not a member of this tenant"
|
||||
)
|
||||
|
||||
if member.role not in ['owner', 'admin']:
|
||||
logger.warning("Insufficient permissions to cancel subscription",
|
||||
user_id=user_id,
|
||||
tenant_id=str(tenant_id),
|
||||
role=member.role)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Access denied: Only owners and admins can cancel subscriptions"
|
||||
)
|
||||
|
||||
# Get subscription ID from database
|
||||
subscription = await tenant_service.subscription_repo.get_active_subscription(str(tenant_id))
|
||||
if not subscription or not subscription.stripe_subscription_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="No active subscription found for this tenant"
|
||||
)
|
||||
|
||||
subscription_id = subscription.stripe_subscription_id
|
||||
|
||||
result = await payment_service.cancel_subscription(subscription_id)
|
||||
|
||||
@@ -856,10 +899,40 @@ async def get_invoices(
|
||||
"""Get invoices for a tenant"""
|
||||
|
||||
try:
|
||||
# TODO: Add access control - verify user has access to tenant
|
||||
# In a real implementation, you would need to retrieve the customer ID from the database
|
||||
# For now, this is a placeholder
|
||||
customer_id = "cus_test" # This would come from the database
|
||||
# Verify user has access to tenant
|
||||
user_id = current_user.get('user_id')
|
||||
|
||||
from app.services.tenant_service import EnhancedTenantService
|
||||
from shared.database.base import create_database_manager
|
||||
|
||||
tenant_service = EnhancedTenantService(create_database_manager())
|
||||
|
||||
async with tenant_service.database_manager.get_session() as session:
|
||||
await tenant_service._init_repositories(session)
|
||||
|
||||
# Verify user is member of tenant
|
||||
member = await tenant_service.member_repo.get_member_by_user_and_tenant(
|
||||
str(user_id), str(tenant_id)
|
||||
)
|
||||
|
||||
if not member:
|
||||
logger.warning("User not member of tenant",
|
||||
user_id=user_id,
|
||||
tenant_id=str(tenant_id))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Access denied: You do not have access to this tenant"
|
||||
)
|
||||
|
||||
# Get subscription with customer ID
|
||||
subscription = await tenant_service.subscription_repo.get_active_subscription(str(tenant_id))
|
||||
if not subscription or not subscription.stripe_customer_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="No active subscription found for this tenant"
|
||||
)
|
||||
|
||||
customer_id = subscription.stripe_customer_id
|
||||
|
||||
invoices = await payment_service.get_invoices(customer_id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user