From 06e5d86981d7face2a2b20df4d930091cc8c949e Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Tue, 17 Sep 2024 14:19:52 +0530 Subject: [PATCH] more apis --- .../api/userdetails/user_email_verify_get.py | 8 +-- .../api/userdetails/user_email_verify_put.py | 10 +-- .../user_email_verify_token_post.py | 16 +++-- .../dashboard/api/userdetails/user_get.py | 44 ++++-------- .../api/userdetails/user_password_put.py | 68 ++++++------------- .../dashboard/api/userdetails/user_put.py | 4 -- .../recipe/dashboard/interfaces.py | 11 +-- supertokens_python/recipe/dashboard/utils.py | 31 --------- 8 files changed, 57 insertions(+), 135 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py index 1b8ff544..2462b9ff 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py @@ -19,10 +19,10 @@ async def handle_user_email_verify_get( user_context: Dict[str, Any], ) -> Union[UserEmailVerifyGetAPIResponse, FeatureNotEnabledError]: req = api_options.request - user_id = req.get_query_param("userId") + recipe_user_id = req.get_query_param("recipeUserId") - if user_id is None: - raise_bad_input_exception("Missing required parameter 'userId'") + if recipe_user_id is None: + raise_bad_input_exception("Missing required parameter 'recipeUserId'") try: EmailVerificationRecipe.get_instance_or_throw() @@ -30,6 +30,6 @@ async def handle_user_email_verify_get( return FeatureNotEnabledError() is_verified = await is_email_verified( - RecipeUserId(user_id), user_context=user_context + RecipeUserId(recipe_user_id), user_context=user_context ) return UserEmailVerifyGetAPIResponse(is_verified) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py index e7a1e470..56206839 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py @@ -27,12 +27,12 @@ async def handle_user_email_verify_put( user_context: Dict[str, Any], ) -> UserEmailVerifyPutAPIResponse: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore - user_id = request_body.get("userId") + recipe_user_id = request_body.get("recipeUserId") verified = request_body.get("verified") - if user_id is None or not isinstance(user_id, str): + if recipe_user_id is None or not isinstance(recipe_user_id, str): raise_bad_input_exception( - "Required parameter 'userId' is missing or has an invalid type" + "Required parameter 'recipeUserId' is missing or has an invalid type" ) if verified is None or not isinstance(verified, bool): @@ -43,7 +43,7 @@ async def handle_user_email_verify_put( if verified: token_response = await create_email_verification_token( tenant_id=tenant_id, - recipe_user_id=RecipeUserId(user_id), + recipe_user_id=RecipeUserId(recipe_user_id), email=None, user_context=user_context, ) @@ -62,6 +62,6 @@ async def handle_user_email_verify_put( raise Exception("Should not come here") else: - await unverify_email(RecipeUserId(user_id), user_context=user_context) + await unverify_email(RecipeUserId(recipe_user_id), user_context=user_context) return UserEmailVerifyPutAPIResponse() diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py index 1392915c..8707053d 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py @@ -1,4 +1,5 @@ from typing import Any, Dict, Union +from supertokens_python.asyncio import get_user from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.emailverification.asyncio import ( @@ -26,17 +27,22 @@ async def handle_email_verify_token_post( UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse, ]: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore - user_id = request_body.get("userId") + recipe_user_id = request_body.get("recipeUserId") - if user_id is None or not isinstance(user_id, str): + if recipe_user_id is None or not isinstance(recipe_user_id, str): raise_bad_input_exception( - "Required parameter 'userId' is missing or has an invalid type" + "Required parameter 'recipeUserId' is missing or has an invalid type" ) + user = await get_user(recipe_user_id, user_context) + + if user is None: + raise_bad_input_exception("User not found") + res = await send_email_verification_email( tenant_id=tenant_id, - user_id=user_id, - recipe_user_id=RecipeUserId(user_id), + user_id=user.id, + recipe_user_id=RecipeUserId(recipe_user_id), email=None, user_context=user_context, ) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_get.py index f4559f48..9d0dcef3 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_get.py @@ -1,19 +1,19 @@ from typing import Union, Dict, Any +from supertokens_python.asyncio import get_user from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.recipe.dashboard.utils import get_user_for_recipe_id +from supertokens_python.recipe.dashboard.utils import ( + UserWithMetadata, +) from supertokens_python.recipe.usermetadata import UserMetadataRecipe from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata -from supertokens_python.types import RecipeUserId from ...interfaces import ( APIInterface, APIOptions, UserGetAPINoUserFoundError, UserGetAPIOkResponse, - UserGetAPIRecipeNotInitialisedError, ) -from ...utils import is_recipe_initialised, is_valid_recipe_id async def handle_user_get( @@ -21,47 +21,31 @@ async def handle_user_get( _tenant_id: str, api_options: APIOptions, _user_context: Dict[str, Any], -) -> Union[ - UserGetAPINoUserFoundError, - UserGetAPIOkResponse, - UserGetAPIRecipeNotInitialisedError, -]: +) -> Union[UserGetAPINoUserFoundError, UserGetAPIOkResponse,]: user_id = api_options.request.get_query_param("userId") - recipe_id = api_options.request.get_query_param("recipeId") if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - if recipe_id is None: - raise_bad_input_exception("Missing required parameter 'recipeId'") - - if not is_valid_recipe_id(recipe_id): - raise_bad_input_exception("Invalid recipe id") - - if not is_recipe_initialised(recipe_id): - return UserGetAPIRecipeNotInitialisedError() - - user_response = await get_user_for_recipe_id( - RecipeUserId(user_id), recipe_id, _user_context - ) - if user_response.user is None: + user_response = await get_user(user_id, _user_context) + if user_response is None: return UserGetAPINoUserFoundError() - user = user_response.user + user_with_metadata: UserWithMetadata = UserWithMetadata().from_user(user_response) try: UserMetadataRecipe.get_instance() except Exception: - user.first_name = "FEATURE_NOT_ENABLED" - user.last_name = "FEATURE_NOT_ENABLED" + user_with_metadata.first_name = "FEATURE_NOT_ENABLED" + user_with_metadata.last_name = "FEATURE_NOT_ENABLED" - return UserGetAPIOkResponse(recipe_id, user) + return UserGetAPIOkResponse(user_with_metadata) user_metadata = await get_user_metadata(user_id, user_context=_user_context) first_name = user_metadata.metadata.get("first_name", "") last_name = user_metadata.metadata.get("last_name", "") - user.first_name = first_name - user.last_name = last_name + user_with_metadata.first_name = first_name + user_with_metadata.last_name = last_name - return UserGetAPIOkResponse(recipe_id, user) + return UserGetAPIOkResponse(user_with_metadata) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py index bc72c61b..1ed63365 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py @@ -1,17 +1,12 @@ -from typing import Any, Dict, List, Union +from typing import Any, Dict, Union from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.emailpassword import EmailPasswordRecipe -from supertokens_python.recipe.emailpassword.constants import FORM_FIELD_PASSWORD_ID from supertokens_python.recipe.emailpassword.interfaces import ( + PasswordPolicyViolationError, UnknownUserIdError, - PasswordResetTokenInvalidError, ) -from supertokens_python.recipe.emailpassword.asyncio import ( - create_reset_password_token, - reset_password_using_token, -) -from supertokens_python.recipe.emailpassword.types import NormalisedFormField +from supertokens_python.types import RecipeUserId from ...interfaces import ( APIInterface, @@ -28,52 +23,33 @@ async def handle_user_password_put( user_context: Dict[str, Any], ) -> Union[UserPasswordPutAPIResponse, UserPasswordPutAPIInvalidPasswordErrorResponse]: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore - user_id = request_body.get("userId") + recipe_user_id = request_body.get("recipeUserId") new_password = request_body.get("newPassword") - if user_id is None or not isinstance(user_id, str): - raise_bad_input_exception("Missing required parameter 'userId'") + if recipe_user_id is None or not isinstance(recipe_user_id, str): + raise_bad_input_exception("Missing required parameter 'recipeUserId'") if new_password is None or not isinstance(new_password, str): raise_bad_input_exception("Missing required parameter 'newPassword'") - async def reset_password( - form_fields: List[NormalisedFormField], - ) -> Union[ - UserPasswordPutAPIResponse, UserPasswordPutAPIInvalidPasswordErrorResponse - ]: - password_form_field = [ - field for field in form_fields if field.id == FORM_FIELD_PASSWORD_ID - ][0] - - password_validation_error = await password_form_field.validate( - new_password, tenant_id - ) - - if password_validation_error is not None: - return UserPasswordPutAPIInvalidPasswordErrorResponse( - password_validation_error - ) - - password_reset_token = await create_reset_password_token( - tenant_id, user_id, "", user_context + email_password_recipe = EmailPasswordRecipe.get_instance() + update_response = ( + await email_password_recipe.recipe_implementation.update_email_or_password( + recipe_user_id=RecipeUserId(recipe_user_id), + email=None, + password=new_password, + apply_password_policy=True, + tenant_id_for_password_policy=tenant_id, + user_context=user_context, ) + ) - if isinstance(password_reset_token, UnknownUserIdError): - # Techincally it can but its an edge case so we assume that it wont - # UNKNOWN_USER_ID_ERROR - raise Exception("Should never come here") - - password_reset_response = await reset_password_using_token( - tenant_id, password_reset_token.token, new_password, user_context + if isinstance(update_response, PasswordPolicyViolationError): + return UserPasswordPutAPIInvalidPasswordErrorResponse( + error=update_response.failure_reason ) - if isinstance(password_reset_response, PasswordResetTokenInvalidError): - # RESET_PASSWORD_INVALID_TOKEN_ERROR - raise Exception("Should not come here") + if isinstance(update_response, UnknownUserIdError): + raise Exception("Should never come here") - return UserPasswordPutAPIResponse() - - return await reset_password( - EmailPasswordRecipe.get_instance().config.sign_up_feature.form_fields, - ) + return UserPasswordPutAPIResponse() diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_put.py index 537e6e9b..ea0c7f34 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_put.py @@ -3,7 +3,6 @@ from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.dashboard.utils import ( get_user_for_recipe_id, - is_valid_recipe_id, ) from supertokens_python.recipe.emailpassword import EmailPasswordRecipe from supertokens_python.recipe.emailpassword.asyncio import ( @@ -195,9 +194,6 @@ async def handle_user_put( "Required parameter 'recipeId' is missing or has an invalid type" ) - if not is_valid_recipe_id(recipe_id): - raise_bad_input_exception("Invalid recipe id") - if first_name is None and not isinstance(first_name, str): raise_bad_input_exception( "Required parameter 'firstName' is missing or has an invalid type" diff --git a/supertokens_python/recipe/dashboard/interfaces.py b/supertokens_python/recipe/dashboard/interfaces.py index 9c60692f..c4c2aa51 100644 --- a/supertokens_python/recipe/dashboard/interfaces.py +++ b/supertokens_python/recipe/dashboard/interfaces.py @@ -140,14 +140,12 @@ def to_json(self) -> Dict[str, Any]: class UserGetAPIOkResponse(APIResponse): status: str = "OK" - def __init__(self, recipe_id: str, user: UserWithMetadata): - self.recipe_id = recipe_id + def __init__(self, user: UserWithMetadata): self.user = user def to_json(self) -> Dict[str, Any]: return { "status": self.status, - "recipeId": self.recipe_id, "user": self.user.to_json(), } @@ -159,13 +157,6 @@ def to_json(self) -> Dict[str, Any]: return {"status": self.status} -class UserGetAPIRecipeNotInitialisedError(APIResponse): - status: str = "RECIPE_NOT_INITIALISED" - - def to_json(self) -> Dict[str, Any]: - return {"status": self.status} - - class FeatureNotEnabledError(APIResponse): status: str = "FEATURE_NOT_ENABLED_ERROR" diff --git a/supertokens_python/recipe/dashboard/utils.py b/supertokens_python/recipe/dashboard/utils.py index 310b3c09..7e053dbd 100644 --- a/supertokens_python/recipe/dashboard/utils.py +++ b/supertokens_python/recipe/dashboard/utils.py @@ -182,10 +182,6 @@ def get_api_if_matched(path: NormalisedURLPath, method: str) -> Optional[str]: return None -def is_valid_recipe_id(recipe_id: str) -> bool: - return recipe_id in ("emailpassword", "thirdparty", "passwordless") - - class GetUserForRecipeIdHelperResult: def __init__( self, user: Optional[AccountLinkingUser] = None, recipe: Optional[str] = None @@ -265,33 +261,6 @@ async def _get_user_for_recipe_id( return GetUserForRecipeIdHelperResult(user=user, recipe=recipe) -def is_recipe_initialised(recipeId: str) -> bool: - isRecipeInitialised: bool = False - - if recipeId == EmailPasswordRecipe.recipe_id: - try: - EmailPasswordRecipe.get_instance() - isRecipeInitialised = True - except Exception: - pass - - elif recipeId == PasswordlessRecipe.recipe_id: - try: - PasswordlessRecipe.get_instance() - isRecipeInitialised = True - except Exception: - pass - - elif recipeId == ThirdPartyRecipe.recipe_id: - try: - ThirdPartyRecipe.get_instance() - isRecipeInitialised = True - except Exception: - pass - - return isRecipeInitialised - - async def validate_api_key( req: BaseRequest, config: DashboardConfig, _user_context: Dict[str, Any] ) -> bool: