Commit dbee2adc authored by Ilham Maulana's avatar Ilham Maulana 💻

fix: shifting auth api to simple jwt

parent 91432e03
from rest_framework import permissions
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.tokens import RefreshToken
class IsStaffUser(permissions.BasePermission):
class IsStaffUser(IsAuthenticated):
def has_permission(self, request, view):
if request.method != "POST" and not request.user.is_staff:
return False
elif request.method != "POST" and not request.user.is_authenticated:
return False
refresh_token = request.session.get("refresh_token")
return True
return bool(
refresh_token is not None
and request.user
and request.user.is_authenticated
and request.user.is_staff
)
class IsNotStaffUser(permissions.BasePermission):
class IsNotStaffUser(IsAuthenticated):
def has_permission(self, request, view):
if request.method != "POST" and request.user.is_staff:
return False
elif request.method != "POST" and not request.user.is_authenticated:
return False
return True
refresh_token = request.session.get("refresh_token")
return bool(
refresh_token is not None
and request.user
and request.user.is_authenticated
and not request.user.is_staff
)
from django.contrib.auth import authenticate
from rest_framework import serializers
from users.models import User, Librarian, Member, LibrarianLoginHistory
......@@ -40,7 +41,18 @@ class LibrarianSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user_data = validated_data.pop("user")
user_data["is_staff"] = True
username = user_data.get("username")
email = user_data.get("email")
is_username = User.objects.filter(username=username)
is_email = User.objects.filter(email=email)
if is_username.exists() and is_email.exists():
raise serializers.ValidationError("Username or Email is already exists")
user = User.objects.create_user(**user_data)
user.set_password(user_data.get("password"))
user.save()
librarian = Librarian.objects.create(user=user, **validated_data)
return librarian
......@@ -90,6 +102,8 @@ class MemberSerializer(serializers.ModelSerializer):
user_data = validated_data.pop("user")
user_data["is_staff"] = False
user = User.objects.create_user(**user_data)
user.set_password(user_data.get("password"))
user.save()
member = Member.objects.create(user=user, **validated_data)
return member
......
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth import authenticate
from django.contrib.auth.tokens import default_token_generator
from django.core.mail import send_mail
from rest_framework import views, viewsets, status
from rest_framework.response import Response
from rest_framework.filters import SearchFilter
from rest_framework_simplejwt.views import TokenObtainPairView
from .serializers import (
User,
......@@ -39,8 +41,17 @@ class LibrarianViewSet(viewsets.ModelViewSet):
return Response(serializer.data, status=status.HTTP_200_OK)
class LibrarianLoginHistoryViewSet(viewsets.ModelViewSet):
permission_classes = [IsStaffUser]
queryset = LibrarianLoginHistory.objects.all().order_by("date")
serializer_class = LoginHistorySerializer
filter_backends = [SearchFilter]
search_fields = ["librarian__name"]
class MemberViewSet(viewsets.ModelViewSet):
permission_classes = [IsNotStaffUser]
permission_classes = [IsStaffUser]
queryset = Member.objects.all().order_by("created_at")
serializer_class = MemberSerializer
......@@ -70,146 +81,85 @@ class MemberViewSet(viewsets.ModelViewSet):
return Response(serializer.data, status=status.HTTP_200_OK)
class LoginBaseView(views.APIView):
class LoginBaseView(TokenObtainPairView):
user = None
def post(self, request):
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
username = request.data.get("username")
password = request.data.get("password")
user = authenticate(username=username, password=password)
if request.user.is_authenticated:
if user is None:
return Response(
{"message": "Login failed, user is already authenticated"},
{"message": "Invalid username or password"},
status=status.HTTP_403_FORBIDDEN,
)
if username is None or password is None:
return Response(
{"message": "Login failed, username or password cannot be empty"},
status=status.HTTP_400_BAD_REQUEST,
)
user = authenticate(request, username=username, password=password)
if user is not None:
self.user = user
request.data["token"] = user.get_session_auth_hash()
request.data["message"] = "Login successful"
return Response(request.data, status=status.HTTP_200_OK)
else:
return Response(
{"message": "Login failed, invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED,
)
request.session["refresh_token"] = response.data.get("refresh")
return response
class LibrarianLoginView(LoginBaseView):
def post(self, request):
response = super().post(request)
if response.status_code == status.HTTP_200_OK:
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
if response.status_code == 200:
if not self.user.is_staff:
return Response(
{"message": "Login as librarian failed, account is not staff"},
{"message": "Account does not have access"},
status=status.HTTP_403_FORBIDDEN,
)
else:
login(request, self.user)
librarian = Librarian.objects.get(user=self.user)
LibrarianLoginHistory.objects.create(librarian=librarian)
pass
return response
class LibrarianLoginHistoryViewSet(viewsets.ModelViewSet):
permission_classes = [IsStaffUser]
queryset = LibrarianLoginHistory.objects.all().order_by("date")
serializer_class = LoginHistorySerializer
filter_backends = [SearchFilter]
search_fields = ["librarian__name"]
class LibrarianViewSet(viewsets.ModelViewSet):
permission_classes = [IsStaffUser]
queryset = Librarian.objects.all().order_by("created_at")
serializer_class = LibrarianSerializer
class LibrarianRegisterView(views.APIView):
filter_backends = [SearchFilter]
search_fields = [
"user__username",
"user__email",
"user__first_name",
"user__last_name",
]
def update(self, request, pk):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
def post(self, request):
data = request.data
data["message"] = "Register as librarian success"
serializer = LibrarianSerializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
class MemberLoginView(LoginBaseView):
def post(self, request):
response = super().post(request)
if response.status_code == status.HTTP_200_OK:
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
if response.status_code == 200:
if self.user.is_staff:
return Response(
{"message": "Login failed, invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED,
{"message": "Account does not have access"},
status=status.HTTP_403_FORBIDDEN,
)
else:
login(request, self.user)
pass
return response
class LogoutBasedView(views.APIView):
def get(self, request):
if not request.user.is_authenticated:
return Response(
{"message": "Logout failed, user is unauthorized"},
status=status.HTTP_401_UNAUTHORIZED,
)
return Response({"message": "Logout success"}, status=status.HTTP_200_OK)
class LibrarianLogoutView(LogoutBasedView):
class LogoutView(views.APIView):
def get(self, request):
response = super().get(request)
if response.status_code == status.HTTP_200_OK:
if request.user.is_staff:
logout(request)
else:
refresh = request.session.get("refresh_token")
if refresh is None:
return Response(
{"message": "Logout failed, user is unauthorized"},
status=status.HTTP_401_UNAUTHORIZED,
{"detail": "You do not have permission to perform this action."},
status=status.HTTP_403_FORBIDDEN,
)
return response
class MemberLogoutView(LogoutBasedView):
def get(self, request):
response = super().get(request)
if response.status_code == status.HTTP_200_OK:
if not request.user.is_staff:
logout(request)
else:
return Response(
{"message": "Logout failed, user is unauthorized"},
status=status.HTTP_401_UNAUTHORIZED,
)
del request.session["refresh_token"]
return response
return Response({"message": "Logout success"}, status=status.HTTP_200_OK)
class MemberChangePasswordView(views.APIView):
......
......@@ -4,12 +4,12 @@ from rest_framework import routers
from .auth.views import (
LibrarianViewSet,
LibrarianLoginView,
LibrarianLogoutView,
LibrarianRegisterView,
LibrarianLoginHistoryViewSet,
MemberViewSet,
MemberLoginView,
MemberLogoutView,
MemberChangePasswordView,
LogoutView,
TokenResetPasswordView,
ResetPasswordConfirmView,
)
......@@ -56,10 +56,12 @@ urlpatterns = [
),
path("librarians/auth/login", LibrarianLoginView.as_view(), name="librarian_login"),
path(
"librarians/auth/logout", LibrarianLogoutView.as_view(), name="librarian_logout"
"librarians/auth/register",
LibrarianRegisterView.as_view(),
name="librarian_register",
),
path("auth/logout", LogoutView.as_view(), name="librarian_logout"),
path("members/auth/login", MemberLoginView.as_view(), name="member_login"),
path("members/auth/logout/", MemberLogoutView.as_view(), name="member_logout"),
path(
"members/<int:member_id>/change-password",
MemberChangePasswordView.as_view(),
......
......@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
from django.utils.timezone import timedelta
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
......@@ -44,6 +45,7 @@ INSTALLED_APPS = [
"dashboard.apps.DashboardConfig",
# 3rd party
"rest_framework",
"rest_framework_simplejwt",
"django_filters",
]
......@@ -53,14 +55,21 @@ INSTALLED_APPS = [
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
"SLIDING_TOKEN_LIFETIME": timedelta(days=30),
"SLIDING_TOKEN_REFRESH_LIFETIME_LATE_USER": timedelta(days=1),
"SLIDING_TOKEN_LIFETIME_LATE_USER": timedelta(days=30),
}
# end 3rd party config
MIDDLEWARE = [
......
......@@ -23,6 +23,10 @@ from django.contrib.auth.views import (
PasswordResetConfirmView,
PasswordResetCompleteView,
)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
from dashboard.views import UpcomingLoanView, OverduedLoanView
from users.views import (
......@@ -42,6 +46,8 @@ urlpatterns = [
path("upcoming-loans/", UpcomingLoanView.as_view(), name="upcoming_loans"),
path("overdued-loans/", OverduedLoanView.as_view(), name="overdued_loans"),
# auth
path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("auth/login/", LibrarianLoginView.as_view(), name="librarian_login"),
path("auth/logout/", LibrarianLogoutView.as_view(), name="librarian_logout"),
path("auth/sign-up/", LibrarianSignUpView.as_view(), name="librarian_logout"),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment