|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import logging |
| 4 | + |
1 | 5 | from fastapi import APIRouter, Depends |
2 | 6 | from fastapi import status as http_status |
3 | 7 | from starlette.responses import JSONResponse |
4 | 8 |
|
5 | 9 | from app import settings |
6 | 10 | from app.api.users.model import CreateUserData, CreateUserResponse |
| 11 | +from app.api.users.services.optscale_users_registration import ( |
| 12 | + add_new_user, |
| 13 | + validate_email_and_add_invited_user, |
| 14 | +) |
7 | 15 | from app.core.auth_jwt_bearer import JWTBearer |
8 | | -from app.core.exceptions import OptScaleAPIResponseError, format_error_response |
| 16 | +from app.core.exceptions import ( |
| 17 | + APIResponseError, |
| 18 | + InvitationDoesNotExist, |
| 19 | + UserAccessTokenError, |
| 20 | + format_error_response, |
| 21 | +) |
9 | 22 | from app.optscale_api.users_api import OptScaleUserAPI |
10 | 23 |
|
| 24 | +logger = logging.getLogger(__name__) |
11 | 25 | router = APIRouter() |
12 | 26 |
|
13 | 27 |
|
14 | 28 | @router.post( |
15 | 29 | path="", |
16 | 30 | status_code=http_status.HTTP_201_CREATED, |
17 | 31 | response_model=CreateUserResponse, |
18 | | - dependencies=[Depends(JWTBearer())], |
| 32 | + dependencies=[], |
19 | 33 | ) |
20 | | -async def create_user(data: CreateUserData, user_api: OptScaleUserAPI = Depends()): |
| 34 | +async def create_user( |
| 35 | + data: CreateUserData, |
| 36 | + optscale_user_api: OptScaleUserAPI = Depends(), |
| 37 | + jwt_token: dict = Depends(JWTBearer(allow_unauthenticated=True)), |
| 38 | +): |
21 | 39 | """ |
22 | | - Create a FinOps user |
23 | | - This endpoint allows the creation of a new user by interacting with the OptScale API. |
| 40 | + This endpoint registers users in OptScale. |
| 41 | + It can be consumed in two ways: |
| 42 | + 1. If a JWT Token is provided, the user will be created and verified. |
| 43 | + 2. IF no Authentication is provided, the given user will be created ONLY |
| 44 | + if an invitation exists with the provided email address. If an invitation exists, |
| 45 | + the user will be created but not auto-verified. The user has to perform |
| 46 | + the verification action. |
| 47 | +
|
24 | 48 | It returns the created user's details. |
25 | 49 |
|
| 50 | + :param jwt_token: a JWT token or None |
26 | 51 | :param data: The input data required to create a user. |
27 | | - :param user_api: An instance of OptScaleOrgAPI for managing organization operations. |
| 52 | + :param optscale_user_api: An instance of OptScaleOrgAPI for managing organization operations. |
28 | 53 | Dependency injection via `Depends()`. |
29 | 54 |
|
30 | 55 | :return: A response model containing the details of the newly created user. |
@@ -62,17 +87,32 @@ async def create_user(data: CreateUserData, user_api: OptScaleUserAPI = Depends( |
62 | 87 | JWTBearer: Ensures that the request is authenticated using a valid JWT. |
63 | 88 | """ |
64 | 89 | try: |
65 | | - response = await user_api.create_user( |
66 | | - email=str(data.email), |
67 | | - display_name=data.display_name, |
68 | | - password=data.password, |
69 | | - admin_api_key=settings.admin_token, |
70 | | - verified=True, |
71 | | - ) |
| 90 | + if jwt_token is None: |
| 91 | + response = await validate_email_and_add_invited_user( |
| 92 | + email=str(data.email), |
| 93 | + display_name=data.display_name, |
| 94 | + password=data.password, |
| 95 | + admin_token=settings.admin_token, |
| 96 | + optscale_user_api=optscale_user_api, |
| 97 | + ) |
| 98 | + logger.info(f"Invited User successfully registered: {response}") |
| 99 | + else: |
| 100 | + response = await add_new_user( |
| 101 | + email=str(data.email), |
| 102 | + display_name=data.display_name, |
| 103 | + password=data.password, |
| 104 | + admin_token=settings.admin_token, |
| 105 | + optscale_user_api=optscale_user_api, |
| 106 | + ) |
| 107 | + logger.info(f"User successfully created: {response}") |
72 | 108 | return JSONResponse( |
73 | 109 | status_code=response.get("status_code", http_status.HTTP_201_CREATED), |
74 | 110 | content=response.get("data", {}), |
75 | 111 | ) |
76 | 112 |
|
77 | | - except OptScaleAPIResponseError as error: |
| 113 | + except ( |
| 114 | + APIResponseError, |
| 115 | + UserAccessTokenError, |
| 116 | + InvitationDoesNotExist, |
| 117 | + ) as error: |
78 | 118 | return format_error_response(error) |
0 commit comments