From 018771cf7349aa7c79a518691fcf8f23f3313249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Voron?= Date: Wed, 15 Sep 2021 16:00:58 +0200 Subject: [PATCH] Add manager docstrings --- fastapi_users/manager.py | 201 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/fastapi_users/manager.py b/fastapi_users/manager.py index 999c50c9..7e882883 100644 --- a/fastapi_users/manager.py +++ b/fastapi_users/manager.py @@ -48,6 +48,19 @@ class InvalidPasswordException(FastAPIUsersException): class BaseUserManager(Generic[models.UC, models.UD]): + """ + User management logic. + + :attribute reset_password_token_secret: Secret to encode reset password token. + :attribute reset_password_token_lifetime_seconds: Lifetime of reset password token. + :attribute reset_password_token_audience: JWT audience of reset password token. + :attribute verification_token_secret: Secret to encode verification token. + :attribute verification_token_lifetime_seconds: Lifetime of verification token. + :attribute verification_token_audience: JWT audience of verification token. + + :param user_db_model: Pydantic model of a DB representation of a user. + :param user_db: Database adapter instance. + """ user_db_model: Type[models.UD] user_db: BaseUserDatabase[models.UD] @@ -69,6 +82,13 @@ class BaseUserManager(Generic[models.UC, models.UD]): self.user_db = user_db async def get(self, id: UUID4) -> models.UD: + """ + Get a user by id. + + :param id: Id. of the user to retrieve. + :raises UserNotExists: The user does not exist. + :return: A user. + """ user = await self.user_db.get(id) if user is None: @@ -77,6 +97,13 @@ class BaseUserManager(Generic[models.UC, models.UD]): return user async def get_by_email(self, user_email: str) -> models.UD: + """ + Get a user by e-mail. + + :param user_email: E-mail of the user to retrieve. + :raises UserNotExists: The user does not exist. + :return: A user. + """ user = await self.user_db.get_by_email(user_email) if user is None: @@ -85,6 +112,14 @@ class BaseUserManager(Generic[models.UC, models.UD]): return user async def get_by_oauth_account(self, oauth: str, account_id: str) -> models.UD: + """ + Get a user by OAuth account. + + :param oauth: Name of the OAuth client. + :param account_id: Id. of the account on the external OAuth service. + :raises UserNotExists: The user does not exist. + :return: A user. + """ user = await self.user_db.get_by_oauth_account(oauth, account_id) if user is None: @@ -95,6 +130,19 @@ class BaseUserManager(Generic[models.UC, models.UD]): async def create( self, user: models.UC, safe: bool = False, request: Optional[Request] = None ) -> models.UD: + """ + Create a user in database. + + Triggers the on_after_register handler on success. + + :param user: The UserCreate model to create. + :param safe: If True, sensitive values like is_superuser or is_verified + will be ignored during the creation, defaults to False. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :raises UserAlreadyExists: A user already exists with the same e-mail. + :return: A new user. + """ await self.validate_password(user.password, user) existing_user = await self.user_db.get_by_email(user.email) @@ -116,6 +164,22 @@ class BaseUserManager(Generic[models.UC, models.UD]): async def oauth_callback( self, oauth_account: models.BaseOAuthAccount, request: Optional[Request] = None ) -> models.UD: + """ + Handle the callback after a successfull OAuth authentication. + + If the user already exists with this OAuth account, the token is updated. + + If a user with the same e-mail already exists, + the OAuth account is linked to it. + + If the user does not exist, it is created and the on_after_register handler + is triggered. + + :param oauth_account: The new OAuth account to create. + :param request: Optional FastAPI request that + triggered the operation, defaults to None + :return: A user. + """ try: user = await self.get_by_oauth_account( oauth_account.oauth_name, oauth_account.account_id @@ -152,6 +216,17 @@ class BaseUserManager(Generic[models.UC, models.UD]): async def request_verify( self, user: models.UD, request: Optional[Request] = None ) -> None: + """ + Start a verification request. + + Triggers the on_after_request_verify handler on success. + + :param user: The user to verify. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :raises UserInactive: The user is inactive. + :raises UserAlreadyVerified: The user is already verified. + """ if not user.is_active: raise UserInactive() if user.is_verified: @@ -170,6 +245,20 @@ class BaseUserManager(Generic[models.UC, models.UD]): await self.on_after_request_verify(user, token, request) async def verify(self, token: str, request: Optional[Request] = None) -> models.UD: + """ + Validate a verification request. + + Changes the is_verified flag of the user to True. + + Triggers the on_after_verify handler on success. + + :param token: The verification token generated by request_verify. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :raises InvalidVerifyToken: The token is invalid or expired. + :raises UserAlreadyVerified: The user is already verified. + :return: The verified user. + """ try: data = decode_jwt( token, @@ -210,6 +299,16 @@ class BaseUserManager(Generic[models.UC, models.UD]): async def forgot_password( self, user: models.UD, request: Optional[Request] = None ) -> None: + """ + Start a forgot password request. + + Triggers the on_after_forgot_password handler on success. + + :param user: The user that forgot its password. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :raises UserInactive: The user is inactive. + """ if not user.is_active: raise UserInactive() @@ -224,6 +323,20 @@ class BaseUserManager(Generic[models.UC, models.UD]): async def reset_password( self, token: str, password: str, request: Optional[Request] = None ) -> models.UD: + """ + Reset the password of a user. + + Triggers the on_after_reset_password handler on success. + + :param token: The token generated by forgot_password. + :param password: The new password to set. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :raises InvalidResetPasswordToken: The token is invalid or expired. + :raises UserInactive: The user is inactive. + :raises InvalidPasswordException: The password is invalid. + :return: The user with updated password. + """ try: data = decode_jwt( token, @@ -261,6 +374,20 @@ class BaseUserManager(Generic[models.UC, models.UD]): safe: bool = False, request: Optional[Request] = None, ) -> models.UD: + """ + Update a user. + + Triggers the on_after_update handler on success + + :param user_update: The UserUpdate model containing + the changes to apply to the user. + :param user: The current user to update. + :param safe: If True, sensitive values like is_superuser or is_verified + will be ignored during the update, defaults to False + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + :return: The updated user. + """ if safe: updated_user_data = user_update.create_update_dict() else: @@ -270,16 +397,40 @@ class BaseUserManager(Generic[models.UC, models.UD]): return updated_user async def delete(self, user: models.UD) -> None: + """ + Delete a user. + + :param user: The user to delete. + """ await self.user_db.delete(user) async def validate_password( self, password: str, user: Union[models.UC, models.UD] ) -> None: + """ + Validate a password. + + *You should overload this method to add your own validation logic.* + + :param password: The password to validate. + :param user: The user associated to this password. + :raises InvalidPasswordException: The password is invalid. + :return: None if the password is valid. + """ return # pragma: no cover async def on_after_register( self, user: models.UD, request: Optional[Request] = None ) -> None: + """ + Perform logic after successful user registration. + + *You should overload this method to add your own logic.* + + :param user: The registered user + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def on_after_update( @@ -288,26 +439,74 @@ class BaseUserManager(Generic[models.UC, models.UD]): update_dict: Dict[str, Any], request: Optional[Request] = None, ) -> None: + """ + Perform logic after successful user update. + + *You should overload this method to add your own logic.* + + :param user: The updated user + :param update_dict: Dictionary with the updated user fields. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def on_after_request_verify( self, user: models.UD, token: str, request: Optional[Request] = None ) -> None: + """ + Perform logic after successful verification request. + + *You should overload this method to add your own logic.* + + :param user: The user to verify. + :param token: The verification token. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def on_after_verify( self, user: models.UD, request: Optional[Request] = None ) -> None: + """ + Perform logic after successful user verification. + + *You should overload this method to add your own logic.* + + :param user: The verified user. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def on_after_forgot_password( self, user: models.UD, token: str, request: Optional[Request] = None ) -> None: + """ + Perform logic after successful forgot password request. + + *You should overload this method to add your own logic.* + + :param user: The user that forgot its password. + :param token: The forgot password token. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def on_after_reset_password( self, user: models.UD, request: Optional[Request] = None ) -> None: + """ + Perform logic after successful password reset. + + *You should overload this method to add your own logic.* + + :param user: The user that reset its password. + :param request: Optional FastAPI request that + triggered the operation, defaults to None. + """ return # pragma: no cover async def authenticate( @@ -317,6 +516,8 @@ class BaseUserManager(Generic[models.UC, models.UD]): Authenticate and return a user following an email and a password. Will automatically upgrade password hash if necessary. + + :param credentials: The user credentials. """ try: user = await self.get_by_email(credentials.username)