-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature to deactivate a user #150
Merged
Freeman-kuch
merged 28 commits into
hngprojects:dev
from
joboy-dev:auth-deactivate-user
Jul 21, 2024
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
6a7a0f7
Implement user deactivation
joboy-dev bc8646c
Merge branch 'dev' of https://github.com/joboy-dev/hng_boilerplate_py…
joboy-dev 0536f3c
feat: user deactivation
joboy-dev eb81cfe
Merge branch 'dev' of https://github.com/joboy-dev/hng_boilerplate_py…
joboy-dev dfe0ae5
Made requested changes
joboy-dev 645d20b
Made requested changes
joboy-dev b286158
Added changes to email
joboy-dev 564c165
Feat: Add reactivation endpoint
joboy-dev 954e8cf
Feat: Add reactivation endpoint
joboy-dev 8e97391
Feat: Add reactivation endpoint
joboy-dev c05b866
Tests updated
joboy-dev 100afe3
Tests updated
joboy-dev b84aa80
Tests updated
joboy-dev 04f0c82
Tests updated
joboy-dev 7085ff2
Tests updated
joboy-dev c40f88a
Tests updated
joboy-dev e749528
Reconfigure tests
joboy-dev b9b4d57
Update user deactivation tests
joboy-dev d5c3842
Update user deactivation tests
joboy-dev e9ab50c
Update user deactivation tests
joboy-dev 8a3723f
Update user deactivation tests
joboy-dev 8da88ae
Update user deactivation tests
joboy-dev f0bd84b
Update user deactivation tests
joboy-dev ef09c50
Update user deactivation tests
joboy-dev 13e406e
Update tests to mock db
joboy-dev c96c68e
Update tests to mock db
joboy-dev eaac58a
Update to tests
joboy-dev 0a55da5
Update to tests
joboy-dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import smtplib | ||
from typing import List, Optional, Union | ||
|
||
from fastapi import HTTPException | ||
from api.utils.settings import settings | ||
|
||
|
||
class MailService: | ||
'''Class to send different emails for different services''' | ||
|
||
def send_mail(self, to: str, subject: str, body: str): | ||
'''Function to send email to a user either as a regular test or as html file''' | ||
|
||
try: | ||
with smtplib.SMTP(settings.MAIL_SERVER, settings.MAIL_PORT) as conn: | ||
conn.starttls() | ||
conn.login(user=settings.MAIL_USERNAME, password=settings.MAIL_PASSWORD) | ||
conn.sendmail( | ||
from_addr=settings.MAIL_FROM, | ||
to_addrs=to, | ||
msg=f"Subject:{subject}\n\n{body}" | ||
) | ||
|
||
except smtplib.SMTPException as smtp_error: | ||
raise HTTPException(500, f'SMTP ERROR- {smtp_error}') | ||
|
||
|
||
mail_service = MailService() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from fastapi import Depends, HTTPException, APIRouter, Request | ||
from jose import JWTError | ||
import jwt | ||
from sqlalchemy.orm import Session | ||
|
||
from api.core.dependencies.email import mail_service | ||
from api.utils.auth import create_access_token | ||
|
||
from api.utils.config import SECRET_KEY, ALGORITHM | ||
from ..models.user import User | ||
from api.v1.schemas.user import DeactivateUserSchema | ||
from api.db.database import get_db | ||
from api.utils.dependencies import get_current_user | ||
|
||
|
||
user = APIRouter(prefix='/api/v1/users', tags=['Users']) | ||
|
||
@user.patch('/accounts/deactivate', status_code=200) | ||
async def deactivate_account(request: Request, schema: DeactivateUserSchema, db: Session = Depends(get_db), user: User = Depends(get_current_user)): | ||
'''Endpoint to deactivate a user account''' | ||
|
||
# Generate an access token containing user credentials | ||
token = create_access_token(data={'username': f'{user.username}'}) | ||
|
||
if not user.is_active: | ||
raise HTTPException(400, 'User is inactive') | ||
|
||
if schema.confirmation == False: | ||
raise HTTPException(400, 'Confirmation required to deactivate account') | ||
|
||
user.is_active = False | ||
|
||
# Send aail to user | ||
mail_service.send_mail( | ||
to=user.email, | ||
subject='Account deactivation', | ||
body=f'Hello, {user.first_name},\n\nYour account has been deactivated successfully.\nTo reactivate your account if this was a mistake, please click the link below:\n{request.url.hostname}/api/users/accounts/reactivate?token={token}\n\nThis link expires after 15 minutes.' | ||
) | ||
|
||
# Commit changes to deactivate the user | ||
db.commit() | ||
|
||
return {"status_code": 200, "message": "Account deactivated successfully. Check email for confirmation"} | ||
|
||
|
||
@user.get('/accounts/reactivate', status_code=200) | ||
async def reactivate_account(request: Request, db: Session = Depends(get_db)): | ||
'''Endpoint to reactivate a user account''' | ||
|
||
# Get access token from query | ||
token = request.query_params.get('token') | ||
|
||
# Validate the token | ||
try: | ||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) | ||
username = payload.get('username') | ||
|
||
if username is None: | ||
raise HTTPException(400, 'Invalid token') | ||
|
||
except JWTError: | ||
raise HTTPException(400, 'Invalid token') | ||
|
||
user = db.query(User).filter(User.username == username).first() | ||
|
||
if user.is_active: | ||
raise HTTPException(400, 'User is already active') | ||
|
||
user.is_active = True | ||
|
||
# Send aail to user | ||
mail_service.send_mail( | ||
to=user.email, | ||
subject='Account reactivation', | ||
body=f'Hello, {user.first_name},\n\nYour account has been reactivated successfully' | ||
) | ||
|
||
# Commit changes to deactivate the user | ||
db.commit() | ||
|
||
return {"status_code": 200, "message": "Account reactivated successfully. Check email for confirmation"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from typing import Optional | ||
from pydantic import BaseModel | ||
|
||
|
||
class DeactivateUserSchema(BaseModel): | ||
'''Schema for deactivating a user''' | ||
|
||
reason: Optional[str] = None | ||
confirmation: bool | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A proper confirmation should be done by sending the user an email with a deactivation link
Boss @zxenonx what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had that before but the person working on adding the emailing template to the database doesn't have it ready so I was told to implement what I had, that a central service would be used for emailing
The endpoint to even send the email was available but the person too could not proceed without the one adding the templates to the database.
Also, the confirmation email would be sent after the account has been deactivated successfully.
@Dev-wonderful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was the one who said you should implement what you have. Anyway, I hope the confirmation would allow the user revert the deactivation with a time limit, since you have decided to deactivate successfully before sending a confirmation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
Let me see what I can do about that as quickly as possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dev-wonderful I have implemented the changes