Improve the frontend modals
This commit is contained in:
@@ -12,7 +12,7 @@ from datetime import datetime, timezone
|
||||
from app.core.database import get_db, get_background_db_session
|
||||
from app.schemas.auth import UserResponse, PasswordChange
|
||||
from app.schemas.users import UserUpdate, BatchUserRequest, OwnerUserCreate
|
||||
from app.services.user_service import UserService
|
||||
from app.services.user_service import UserService, EnhancedUserService
|
||||
from app.models.users import User
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@@ -24,133 +24,15 @@ from shared.auth.decorators import (
|
||||
get_current_user_dep,
|
||||
require_admin_role_dep
|
||||
)
|
||||
from shared.routing import RouteBuilder
|
||||
from shared.security import create_audit_logger, AuditSeverity, AuditAction
|
||||
|
||||
logger = structlog.get_logger()
|
||||
router = APIRouter(tags=["users"])
|
||||
route_builder = RouteBuilder('auth')
|
||||
|
||||
# Initialize audit logger
|
||||
audit_logger = create_audit_logger("auth-service")
|
||||
|
||||
|
||||
@router.get(route_builder.build_base_route("me", include_tenant_prefix=False), response_model=UserResponse)
|
||||
async def get_current_user_info(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get current user information - FIXED VERSION"""
|
||||
try:
|
||||
logger.debug(f"Getting user info for: {current_user}")
|
||||
|
||||
# Handle both User object (direct auth) and dict (from gateway headers)
|
||||
if isinstance(current_user, dict):
|
||||
# Coming from gateway headers - need to fetch user from DB
|
||||
user_id = current_user.get("user_id")
|
||||
if not user_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid user context"
|
||||
)
|
||||
|
||||
# ✅ FIX: Fetch full user from database to get the real role
|
||||
from app.repositories import UserRepository
|
||||
user_repo = UserRepository(User, db)
|
||||
user = await user_repo.get_by_id(user_id)
|
||||
|
||||
logger.debug(f"Fetched user from DB - Role: {user.role}, Email: {user.email}")
|
||||
|
||||
# ✅ FIX: Return role from database, not from JWT headers
|
||||
return UserResponse(
|
||||
id=str(user.id),
|
||||
email=user.email,
|
||||
full_name=user.full_name,
|
||||
is_active=user.is_active,
|
||||
is_verified=user.is_verified,
|
||||
phone=user.phone,
|
||||
language=user.language or "es",
|
||||
timezone=user.timezone or "Europe/Madrid",
|
||||
created_at=user.created_at,
|
||||
last_login=user.last_login,
|
||||
role=user.role, # ✅ CRITICAL: Use role from database, not headers
|
||||
tenant_id=current_user.get("tenant_id")
|
||||
)
|
||||
else:
|
||||
# Direct User object (shouldn't happen in microservice architecture)
|
||||
logger.debug(f"Direct user object received - Role: {current_user.role}")
|
||||
return UserResponse(
|
||||
id=str(current_user.id),
|
||||
email=current_user.email,
|
||||
full_name=current_user.full_name,
|
||||
is_active=current_user.is_active,
|
||||
is_verified=current_user.is_verified,
|
||||
phone=current_user.phone,
|
||||
language=current_user.language or "es",
|
||||
timezone=current_user.timezone or "Europe/Madrid",
|
||||
created_at=current_user.created_at,
|
||||
last_login=current_user.last_login,
|
||||
role=current_user.role, # ✅ Use role from database
|
||||
tenant_id=None
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Get user info error: {e}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to get user information"
|
||||
)
|
||||
|
||||
@router.put(route_builder.build_base_route("me", include_tenant_prefix=False), response_model=UserResponse)
|
||||
async def update_current_user(
|
||||
user_update: UserUpdate,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Update current user information"""
|
||||
try:
|
||||
user_id = current_user.get("user_id") if isinstance(current_user, dict) else current_user.id
|
||||
from app.repositories import UserRepository
|
||||
user_repo = UserRepository(User, db)
|
||||
|
||||
# Prepare update data
|
||||
update_data = {}
|
||||
if user_update.full_name is not None:
|
||||
update_data["full_name"] = user_update.full_name
|
||||
if user_update.phone is not None:
|
||||
update_data["phone"] = user_update.phone
|
||||
if user_update.language is not None:
|
||||
update_data["language"] = user_update.language
|
||||
if user_update.timezone is not None:
|
||||
update_data["timezone"] = user_update.timezone
|
||||
|
||||
updated_user = await user_repo.update(user_id, update_data)
|
||||
return UserResponse(
|
||||
id=str(updated_user.id),
|
||||
email=updated_user.email,
|
||||
full_name=updated_user.full_name,
|
||||
is_active=updated_user.is_active,
|
||||
is_verified=updated_user.is_verified,
|
||||
phone=updated_user.phone,
|
||||
language=updated_user.language,
|
||||
timezone=updated_user.timezone,
|
||||
created_at=updated_user.created_at,
|
||||
last_login=updated_user.last_login,
|
||||
role=updated_user.role, # ✅ Include role
|
||||
tenant_id=current_user.get("tenant_id") if isinstance(current_user, dict) else None
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Update user error: {e}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to update user"
|
||||
)
|
||||
|
||||
@router.delete(route_builder.build_base_route("delete/{user_id}", include_tenant_prefix=False))
|
||||
@router.delete("/api/v1/auth/users/{user_id}")
|
||||
async def delete_admin_user(
|
||||
background_tasks: BackgroundTasks,
|
||||
user_id: str = Path(..., description="User ID"),
|
||||
@@ -244,7 +126,7 @@ async def execute_admin_user_deletion(user_id: str, requesting_user_id: str):
|
||||
result=result)
|
||||
|
||||
|
||||
@router.get(route_builder.build_base_route("delete/{user_id}/deletion-preview", include_tenant_prefix=False))
|
||||
@router.get("/api/v1/auth/users/{user_id}/deletion-preview")
|
||||
async def preview_user_deletion(
|
||||
user_id: str = Path(..., description="User ID"),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
@@ -294,7 +176,7 @@ async def preview_user_deletion(
|
||||
return preview
|
||||
|
||||
|
||||
@router.get(route_builder.build_base_route("users/{user_id}", include_tenant_prefix=False), response_model=UserResponse)
|
||||
@router.get("/api/v1/auth/users/{user_id}", response_model=UserResponse)
|
||||
async def get_user_by_id(
|
||||
user_id: str = Path(..., description="User ID"),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
@@ -353,7 +235,7 @@ async def get_user_by_id(
|
||||
)
|
||||
|
||||
|
||||
@router.post(route_builder.build_base_route("users/create-by-owner", include_tenant_prefix=False), response_model=UserResponse)
|
||||
@router.post("/api/v1/auth/users/create-by-owner", response_model=UserResponse)
|
||||
async def create_user_by_owner(
|
||||
user_data: OwnerUserCreate,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
@@ -448,7 +330,7 @@ async def create_user_by_owner(
|
||||
)
|
||||
|
||||
|
||||
@router.post(route_builder.build_base_route("users/batch", include_tenant_prefix=False), response_model=Dict[str, Any])
|
||||
@router.post("/api/v1/auth/users/batch", response_model=Dict[str, Any])
|
||||
async def get_users_batch(
|
||||
request: BatchUserRequest,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
@@ -526,3 +408,75 @@ async def get_users_batch(
|
||||
detail="Failed to fetch users"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/v1/auth/users/{user_id}/activity")
|
||||
async def get_user_activity(
|
||||
user_id: str = Path(..., description="User ID"),
|
||||
current_user = Depends(get_current_user_dep),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Get user activity information.
|
||||
|
||||
This endpoint returns detailed activity information for a user including:
|
||||
- Last login timestamp
|
||||
- Account creation date
|
||||
- Active session count
|
||||
- Last activity timestamp
|
||||
- User status information
|
||||
|
||||
**Permissions:** User can view their own activity, admins can view any user's activity
|
||||
"""
|
||||
try:
|
||||
# Validate UUID format
|
||||
try:
|
||||
uuid.UUID(user_id)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid user ID format"
|
||||
)
|
||||
|
||||
# Check permissions - user can view their own activity, admins can view any
|
||||
if current_user["user_id"] != user_id:
|
||||
# Check if current user has admin privileges
|
||||
user_role = current_user.get("role", "user")
|
||||
if user_role not in ["admin", "super_admin", "manager"]:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Insufficient permissions to view this user's activity"
|
||||
)
|
||||
|
||||
# Initialize enhanced user service
|
||||
from app.core.config import settings
|
||||
from shared.database.base import create_database_manager
|
||||
database_manager = create_database_manager(settings.DATABASE_URL, "tenant-service")
|
||||
user_service = EnhancedUserService(database_manager)
|
||||
|
||||
# Get user activity data
|
||||
activity_data = await user_service.get_user_activity(user_id)
|
||||
|
||||
if "error" in activity_data:
|
||||
if activity_data["error"] == "User not found":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found"
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to get user activity: {activity_data['error']}"
|
||||
)
|
||||
|
||||
logger.debug("Retrieved user activity", user_id=user_id)
|
||||
|
||||
return activity_data
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Get user activity error", user_id=user_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to get user activity information"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user