-
Notifications
You must be signed in to change notification settings - Fork 3
✨ Add api to login via email #71
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
base: main
Are you sure you want to change the base?
Changes from all commits
ebb3c91
40ae5be
da80e1b
84a8283
3730356
b814d4e
9e0fd3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,8 @@ | ||
| from django.urls import path | ||
|
|
||
| from users.v1.views import HelloWorldView, LoginUserView | ||
| from users.v1.views import LoginUserView, LoginWithEmailView | ||
|
|
||
| urlpatterns = [ | ||
| path('login', LoginUserView.as_view(), name='login_user'), | ||
| path('hello', HelloWorldView.as_view(), name='hello_world'), | ||
| path('login/email', LoginWithEmailView.as_view(), name='login_with_email'), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,10 +5,10 @@ | |
| from rest_framework_simplejwt.tokens import RefreshToken | ||
|
|
||
| from django.conf import settings | ||
| from django.contrib.auth import get_user_model | ||
| from django.contrib.auth import authenticate, get_user_model | ||
|
|
||
| from arbisoft_sessions_portal.services.google.google_user_info import GoogleUserInfoService | ||
| from users.v1.serializers import LoginUserSerializer | ||
| from users.v1.serializers import EmailLoginSerializer, LoginUserSerializer | ||
|
|
||
| user_model = get_user_model() | ||
|
|
||
|
|
@@ -111,15 +111,92 @@ def post(self, request): | |
| }) | ||
|
|
||
|
|
||
| class HelloWorldView(APIView): | ||
| """ View for testing the API """ | ||
| class LoginWithEmailView(APIView): | ||
| """ View for logging in the user with email """ | ||
|
|
||
| permission_classes = [] | ||
|
|
||
| @extend_schema( | ||
| responses={200: {"type": "string", "example": "Hello World"}} | ||
| request=EmailLoginSerializer, | ||
| responses={ | ||
| 200: { | ||
| "type": "object", | ||
| "properties": { | ||
| "refresh": { | ||
| "type": "string", | ||
| "description": "JWT refresh token", | ||
| "example": "eyJ0eXAiOiJKV1QiLCJhbGc..." | ||
| }, | ||
| "access": { | ||
| "type": "string", | ||
| "description": "JWT access token", | ||
| "example": "eyJ0eXAiOiJKV1QiLCJhbGc..." | ||
| }, | ||
| "user_info": { | ||
| "type": "object", | ||
| "properties": { | ||
| "full_name": { | ||
| "type": "string", | ||
| "example": "John Doe" | ||
| }, | ||
| "first_name": { | ||
| "type": "string", | ||
| "example": "John" | ||
| }, | ||
| "last_name": { | ||
| "type": "string", | ||
| "example": "Doe" | ||
| }, | ||
| "avatar": { | ||
| "type": ["string", "null"], | ||
| "format": "uri", | ||
| "example": None, | ||
| "description": "User avatar URL, can be null" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| 400: { | ||
| "type": "object", | ||
| "properties": { | ||
| "detail": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "Email and password are required", | ||
| "Invalid email or password" | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| description="Authenticate user using email and password and return JWT tokens", | ||
| ) | ||
| def get(self, request): | ||
| """ | ||
| This endpoint returns a simple "Hello World" response. | ||
| It can be used to verify that the API is up and running. | ||
| """ | ||
| return Response("Hello World") | ||
| def post(self, request): | ||
| """ Log in the user with email """ | ||
| serializer = EmailLoginSerializer(data=request.data) | ||
| serializer.is_valid(raise_exception=True) | ||
|
|
||
| email = serializer.validated_data['email'] | ||
| password = serializer.validated_data['password'] | ||
|
|
||
| # Django's default authentication backend uses the `username` field, not `email`. | ||
| # We first fetch the user by email, then authenticate using their username. | ||
| user = user_model.objects.filter(email=email).first() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Since email is unique, prefer |
||
| if user: | ||
| user = authenticate(username=user.username, password=password) | ||
|
|
||
| if not user: | ||
| raise ValidationError("Invalid email or password") | ||
|
|
||
| refresh = RefreshToken.for_user(user) | ||
| return Response({ | ||
| 'refresh': str(refresh), | ||
| 'access': str(refresh.access_token), | ||
| 'user_info': { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Consider including a stable identifier (e.g. user_id) in user_info to simplify client-side user state management. |
||
| 'full_name': user.get_full_name(), | ||
| 'first_name': user.first_name, | ||
| 'last_name': user.last_name, | ||
| 'avatar': None | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: |
||
| } | ||
| }) | ||
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.
Consider adding a response serializer (e.g.,
LoginResponseSerializer) instead of manually constructing the response dictionary and documenting it inline in@extend_schema.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.
Since this is not a serialized model and involves custom fields and calculations, I believe keeping it as is would be better for maintainability and readability.