Commit 7e4a69d3 authored by Fahmi's avatar Fahmi

serializer update

parent 6fe4d040
# permissions.py
from rest_framework import permissions
class MemberReadOnlyPermission(permissions.BasePermission):
message = "Anda tidak memiliki izin untuk melakukan operasi ini."
def has_permission(self, request, view):
# Hanya izinkan metode GET (read) untuk pengguna dengan peran 'member'
if request.user.is_member and request.method in permissions.SAFE_METHODS:
return True
return False
class LibrarianPermission(permissions.BasePermission):
message = "Anda tidak memiliki izin untuk melakukan operasi ini."
def has_permission(self, request, view):
# Pastikan pengguna terotentikasi sebelum mengakses atribut is_librarian
if request.user.is_authenticated:
return request.user.is_librarian
return False
\ No newline at end of file
...@@ -3,6 +3,8 @@ from .models import * ...@@ -3,6 +3,8 @@ from .models import *
from rest_framework import serializers from rest_framework import serializers
from django.contrib.auth import authenticate, get_user_model from django.contrib.auth import authenticate, get_user_model
from datetime import date from datetime import date
from django.conf import settings
class UserLoginSerializer(serializers.Serializer): class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField() username = serializers.CharField()
...@@ -74,9 +76,11 @@ class UserProfileSerializer(serializers.ModelSerializer): ...@@ -74,9 +76,11 @@ class UserProfileSerializer(serializers.ModelSerializer):
class CategorySerializer(serializers.ModelSerializer): class CategorySerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Category model = Category
fields = '__all__' fields = ['name']
class BookSerializer(serializers.ModelSerializer): class BookSerializer(serializers.ModelSerializer):
category = CategorySerializer()
class Meta: class Meta:
model = Book model = Book
fields = '__all__' fields = '__all__'
...@@ -94,23 +98,57 @@ class LibrarianSerializer(serializers.ModelSerializer): ...@@ -94,23 +98,57 @@ class LibrarianSerializer(serializers.ModelSerializer):
model = Librarian model = Librarian
fields = '__all__' fields = '__all__'
from rest_framework import serializers
class BookLoanSerializer(serializers.ModelSerializer): class BookLoanSerializer(serializers.ModelSerializer):
book_image_url = serializers.SerializerMethodField()
book_title = serializers.SerializerMethodField()
member_name = serializers.SerializerMethodField()
loan_date = serializers.DateField(format='%Y-%m-%d', read_only=True)
due_date = serializers.DateField(format='%Y-%m-%d', read_only=True)
return_date = serializers.DateField(format='%Y-%m-%d', read_only=True)
class Meta: class Meta:
model = BookLoan model = BookLoan
fields = '__all__' fields = ['book_image_url', 'book_title', 'member_name', 'loan_date', 'due_date', 'return_date', 'is_returned']
def get_book_image_url(self, obj):
if obj.book.image:
request = self.context.get('request')
return request.build_absolute_uri(obj.book.image.url)
return None
def get_book_title(self, obj):
return obj.book.title
def get_member_name(self, obj):
return obj.member.name
class OverdueLoanSerializer(serializers.ModelSerializer): class OverdueLoanSerializer(serializers.ModelSerializer):
days_over = serializers.SerializerMethodField() days_over = serializers.SerializerMethodField()
book_title = serializers.CharField(source='book.title')
book_image_url = serializers.SerializerMethodField()
member_name = serializers.CharField(source='member.name')
class Meta: class Meta:
model = BookLoan model = BookLoan
fields = '__all__' fields = '__all__'
def get_book_image_url(self, obj):
if obj.book.image:
request = self.context.get('request')
return request.build_absolute_uri(obj.book.image.url)
return None
def get_days_over(self, obj): def get_days_over(self, obj):
return (date.today() - obj.due_date).days return (date.today() - obj.due_date).days
class NearOutstandingLoanSerializer(serializers.ModelSerializer): class NearOutstandingLoanSerializer(serializers.ModelSerializer):
days_left = serializers.SerializerMethodField() days_left = serializers.SerializerMethodField()
book_title = serializers.CharField(source='book.title') # Tambahkan informasi judul buku
book_image_url = serializers.SerializerMethodField()
member_name = serializers.CharField(source='member.name')
class Meta: class Meta:
model = BookLoan model = BookLoan
...@@ -118,3 +156,45 @@ class NearOutstandingLoanSerializer(serializers.ModelSerializer): ...@@ -118,3 +156,45 @@ class NearOutstandingLoanSerializer(serializers.ModelSerializer):
def get_days_left(self, obj): def get_days_left(self, obj):
return (obj.due_date - date.today()).days return (obj.due_date - date.today()).days
def get_book_image_url(self, obj):
if obj.book.image:
request = self.context.get('request')
return request.build_absolute_uri(obj.book.image.url)
return None
class MemberBookLoanSerializer(serializers.ModelSerializer):
class Meta:
model = BookLoan
fields = ['book','due_date']
class MemberBookLoanByIdSerializer(serializers.ModelSerializer):
class Meta:
model = BookLoan
fields = ['due_date']
class BookMemberSerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField('get_book_image_url')
class Meta:
model = Book
fields = ['title', 'image']
def get_book_image_url(self, obj):
if obj.image:
return self.context['request'].build_absolute_uri(obj.image.url)
return None
class BookLoanMemberSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
request = self.context.get('request')
book_serializer = BookMemberSerializer(instance.book, context={'request': request})
return {
'book_info': book_serializer.data,
'due_date': instance.due_date,
'is_returned': instance.is_returned
}
class Meta:
model = BookLoan
fields = ['book_info', 'due_date', 'is_returned']
\ No newline at end of file
...@@ -2,18 +2,57 @@ ...@@ -2,18 +2,57 @@
from django.urls import include, path from django.urls import include, path
from api import views from api import views
from rest_framework.urlpatterns import format_suffix_patterns from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView
)
urlpatterns = [ urlpatterns = [
# path('login/', obtain_auth_token, name='login'),
path('register-member/', views.MemberRegistrationAPIView.as_view(), name='api_register_member'),
path('register-librarian/', views.LibrarianRegistrationAPIView.as_view(), name='api_register_librarian'),
path('category/', views.CategoryList.as_view()), path('category/', views.CategoryList.as_view()),
path('category/<int:pk>/', views.CategoryDetail.as_view()), path('category/<int:pk>/', views.CategoryDetail.as_view()),
path('book/', views.BookList.as_view()),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
path('book/', views.BookListNonAuth.as_view()),
path('auth/book/', views.BookList.as_view()),
path('book/search/', views.BookSearchView.as_view(), name='book-search-api'),
path('book/by-year/<int:year>/', views.BookListByYear.as_view(), name='book-list-by-year'),
path('book/by-category/<str:category>/', views.BookListByCategory.as_view(), name='book-list-by-category'),
path('book/by-custom/<int:year>/<str:category>/', views.BookListByYearAndCategory.as_view(), name='book-list-custom'),
path('book/<int:pk>/', views.BookDetail.as_view()), path('book/<int:pk>/', views.BookDetail.as_view()),
path('member/', views.MemberList.as_view()), path('member/', views.MemberList.as_view()),
path('member-login/', views.MemberLoginView.as_view(), name='member-login'),
path('member-logout/', views.MemberLogoutView.as_view(), name='member-logout-api'),
path('member/<int:pk>/', views.MemberDetail.as_view()), path('member/<int:pk>/', views.MemberDetail.as_view()),
path('librarian/', views.LibrarianList.as_view()),
path('librarian-login/', views.LibrarianLoginView.as_view(), name='librarian-login'),
path('librarian-logout/', views.LibrarianLogoutView.as_view(), name='member-logout-api'),
path('librarian/<int:pk>/', views.LibrarianDetail.as_view()),
path('bookloan/', views.BookLoanList.as_view()), path('bookloan/', views.BookLoanList.as_view()),
path('bookloan/<int:pk>/', views.BookLoanDetail.as_view()), path('bookloan/<int:pk>/', views.BookLoanDetail.as_view()),
path('member/book-loan/', views.LoanSelectedBook.as_view()),
path('member/list-book-loan/', views.BookLoanViewSet.as_view({'get': 'list'})),
path('member/book-loan/<int:id>/', views.LoanSelectedBookById.as_view()),
path('near-outstanding-books/', views.NearOutstandingLoansAPIView.as_view(), name='near-outstanding-books-api'),
path('overdue-books/', views.OverdueLoansAPIView.as_view(), name='overdue-books-api'),
path('change-password/', views.ChangePasswordView.as_view(), name='change-password-api'),
path('change-profile/', views.ChangeProfileView.as_view(), name='change-profile-api'),
] ]
......
...@@ -3,6 +3,7 @@ from django.views.decorators.csrf import csrf_exempt ...@@ -3,6 +3,7 @@ from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser from rest_framework.parsers import JSONParser
from library.models import * from library.models import *
from api.serializers import * from api.serializers import *
from rest_framework import viewsets
from datetime import date, timedelta from datetime import date, timedelta
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.response import Response from rest_framework.response import Response
...@@ -19,11 +20,15 @@ from rest_framework.authtoken.models import Token ...@@ -19,11 +20,15 @@ from rest_framework.authtoken.models import Token
from .permissions import * from .permissions import *
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate, login, get_user_model from django.contrib.auth import authenticate, login, get_user_model
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
#set Pagination #set Pagination
class MyPageNumberPagination(PageNumberPagination): class MyPageNumberPagination(PageNumberPagination):
page_size = 10 page_size = 10
page_size_query_param = 'page_size' page_size_query_param = 'page_size'
page_query_param = 'page'
#regist librarian #regist librarian
class LibrarianRegistrationAPIView(generics.CreateAPIView): class LibrarianRegistrationAPIView(generics.CreateAPIView):
...@@ -140,7 +145,7 @@ class ChangeProfileView(generics.UpdateAPIView): ...@@ -140,7 +145,7 @@ class ChangeProfileView(generics.UpdateAPIView):
#Category Create dan List #Category Create dan List
class CategoryList(generics.ListCreateAPIView): class CategoryList(generics.ListCreateAPIView):
permission_classes = [LibrarianPermission] permission_classes = [IsAuthenticated]
queryset = Category.objects.all() queryset = Category.objects.all()
serializer_class = CategorySerializer serializer_class = CategorySerializer
...@@ -152,12 +157,18 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): ...@@ -152,12 +157,18 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Category.objects.all() queryset = Category.objects.all()
serializer_class = CategorySerializer serializer_class = CategorySerializer
class BookListNonAuth(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
#Book Create dan List #Book Create dan List
class BookList(generics.ListCreateAPIView): class BookList(generics.ListCreateAPIView):
permission_classes = [MemberReadOnlyPermission|LibrarianPermission] # permission_classes = [MemberReadOnlyPermission|LibrarianPermission]
permission_classes = [IsAuthenticated]
queryset = Book.objects.all() queryset = Book.objects.all()
serializer_class = BookSerializer serializer_class = BookSerializer
pagination_class = MyPageNumberPagination
#Book Update, Detail, Delete #Book Update, Detail, Delete
class BookDetail(generics.RetrieveUpdateDestroyAPIView): class BookDetail(generics.RetrieveUpdateDestroyAPIView):
...@@ -196,15 +207,31 @@ class LibrarianDetail(generics.RetrieveUpdateDestroyAPIView): ...@@ -196,15 +207,31 @@ class LibrarianDetail(generics.RetrieveUpdateDestroyAPIView):
#BookLoan Create dan List #BookLoan Create dan List
class BookLoanList(generics.ListCreateAPIView): class BookLoanList(generics.ListCreateAPIView):
permission_classes = [LibrarianPermission] permission_classes = [IsAuthenticated, LibrarianPermission]
queryset = BookLoan.objects.all()
queryset = BookLoan.objects.all().select_related('book', 'member') # Include related objects
serializer_class = BookLoanSerializer serializer_class = BookLoanSerializer
pagination_class = MyPageNumberPagination pagination_class = MyPageNumberPagination
# def list(self, request, *args, **kwargs):
# book_loans = self.get_queryset()
# serializer = self.get_serializer(book_loans, many=True)
# # Memuat objek buku dan anggota terkait
# data = []
# for loan in serializer.data:
# book = Book.objects.get(id=loan['book'])
# member = Member.objects.get(id=loan['member'])
# loan['book_title'] = book.title
# loan['member_name'] = member.name
# data.append(loan)
# return Response(data)
#BookLoan Update, Detail, Delete #BookLoan Update, Detail, Delete
class BookLoanDetail(generics.RetrieveUpdateDestroyAPIView): class BookLoanDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [LibrarianPermission] permission_classes = [IsAuthenticated, LibrarianPermission]
queryset = BookLoan.objects.all() queryset = BookLoan.objects.all()
serializer_class = BookLoanSerializer serializer_class = BookLoanSerializer
...@@ -215,8 +242,8 @@ class BookSearchView(generics.ListAPIView): ...@@ -215,8 +242,8 @@ class BookSearchView(generics.ListAPIView):
serializer_class = BookSerializer serializer_class = BookSerializer
def get_queryset(self): def get_queryset(self):
book_name = self.request.query_params.get('book_name', '') title = self.request.query_params.get('title', '')
return Book.objects.filter(title__icontains=book_name) return Book.objects.filter(title__icontains=title)
#Book list By Year #Book list By Year
class BookListByYear(generics.ListAPIView): class BookListByYear(generics.ListAPIView):
...@@ -241,7 +268,7 @@ class BookListByYearAndCategory(generics.ListAPIView): ...@@ -241,7 +268,7 @@ class BookListByYearAndCategory(generics.ListAPIView):
#Book list By Category #Book list By Category
class BookListByCategory(generics.ListAPIView): class BookListByCategory(generics.ListAPIView):
permission_classes = [MemberReadOnlyPermission|LibrarianPermission] permission_classes = [IsAuthenticated]
serializer_class = BookSerializer serializer_class = BookSerializer
...@@ -265,7 +292,7 @@ class NearOutstandingLoansAPIView(APIView): ...@@ -265,7 +292,7 @@ class NearOutstandingLoansAPIView(APIView):
) )
) )
serializer = NearOutstandingLoanSerializer(near_outstanding_loans, many=True) serializer = NearOutstandingLoanSerializer(near_outstanding_loans, many=True, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
#overdue loan list #overdue loan list
...@@ -285,5 +312,60 @@ class OverdueLoansAPIView(APIView): ...@@ -285,5 +312,60 @@ class OverdueLoansAPIView(APIView):
for loan in over_due: for loan in over_due:
loan.dead = abs(loan.dead.days) loan.dead = abs(loan.dead.days)
serializer = OverdueLoanSerializer(over_due, many=True) serializer = OverdueLoanSerializer(over_due, many=True, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
# select bookloan
class LoanSelectedBook(APIView):
permission_classes = [IsAuthenticated]
serializer_class = MemberBookLoanSerializer
def post(self, request):
member = request.user.member
# Validasi data dari permintaan menggunakan serializer
serializer = MemberBookLoanSerializer(data=request.data)
if serializer.is_valid():
# Setel data yang diperlukan pada objek BookLoan
serializer.save( member=member)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# select bookloan by id
class LoanSelectedBookById(APIView):
permission_classes = [IsAuthenticated]
serializer_class = MemberBookLoanByIdSerializer
def post(self, request, id):
# Ambil objek buku berdasarkan book_id
book = get_object_or_404(Book, id=id)
member = request.user.member
# Periksa apakah buku sudah dipinjam
if BookLoan.objects.filter(book=book, member=member, is_returned=False).exists():
return Response({"message": "Buku sudah dipinjam."}, status=status.HTTP_400_BAD_REQUEST)
# Validasi data dari permintaan menggunakan serializer
serializer = MemberBookLoanByIdSerializer(data=request.data)
if serializer.is_valid():
# Setel data yang diperlukan pada objek BookLoan
serializer.save(book=book, member=member)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class BookLoanViewSet(viewsets.ViewSet):
permission_classes = [IsAuthenticated]
def list(self, request):
# Ambil semua objek BookLoan yang terkait dengan user (member) yang sedang login
book_loans = BookLoan.objects.filter(member=request.user.member)
# Serialize data BookLoan
serializer = BookLoanMemberSerializer(book_loans, many=True, context={'request': request})
# Kembalikan data BookLoan sebagai respons
return Response(serializer.data)
\ No newline at end of file
[{"model": "admin.logentry", "pk": 1, "fields": {"action_time": "2024-01-03T09:28:19.239Z", "user": 5, "content_type": 11, "object_id": "1", "object_repr": "Galang", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 2, "fields": {"action_time": "2024-01-03T10:09:58.034Z", "user": 5, "content_type": 9, "object_id": "1", "object_repr": "nunu", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 3, "fields": {"action_time": "2024-01-03T10:24:22.722Z", "user": 5, "content_type": 9, "object_id": "2", "object_repr": "Jumu", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 4, "fields": {"action_time": "2024-01-03T10:25:11.171Z", "user": 5, "content_type": 11, "object_id": "2", "object_repr": "admin", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 5, "fields": {"action_time": "2024-01-04T06:25:52.482Z", "user": 5, "content_type": 11, "object_id": "3", "object_repr": "Django", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 6, "fields": {"action_time": "2024-01-04T06:27:51.111Z", "user": 5, "content_type": 9, "object_id": "3", "object_repr": "Primus", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 7, "fields": {"action_time": "2024-01-04T09:03:26.799Z", "user": 5, "content_type": 6, "object_id": "5", "object_repr": "admin", "action_flag": 2, "change_message": "[{\"changed\": {\"fields\": [\"Email address\"]}}]"}}, {"model": "admin.logentry", "pk": 8, "fields": {"action_time": "2024-01-04T09:31:21.527Z", "user": 5, "content_type": 9, "object_id": "4", "object_repr": "devdev", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 9, "fields": {"action_time": "2024-01-05T02:06:26.558Z", "user": 5, "content_type": 9, "object_id": "5", "object_repr": "Bagasmin", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 10, "fields": {"action_time": "2024-01-05T04:17:39.881Z", "user": 5, "content_type": 6, "object_id": "2", "object_repr": "galangrambu12", "action_flag": 2, "change_message": "[{\"changed\": {\"fields\": [\"Groups\", \"Email address\"]}}]"}}, {"model": "admin.logentry", "pk": 11, "fields": {"action_time": "2024-01-05T07:10:28.542Z", "user": 5, "content_type": 11, "object_id": "4", "object_repr": "Fahmi", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 12, "fields": {"action_time": "2024-01-05T07:17:22.211Z", "user": 5, "content_type": 11, "object_id": "5", "object_repr": "Ninja", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 13, "fields": {"action_time": "2024-01-05T07:18:48.634Z", "user": 5, "content_type": 11, "object_id": "6", "object_repr": "Senopati", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 14, "fields": {"action_time": "2024-01-05T07:19:20.726Z", "user": 5, "content_type": 11, "object_id": "6", "object_repr": "Adminas", "action_flag": 2, "change_message": "[{\"changed\": {\"fields\": [\"Name\"]}}]"}}, {"model": "admin.logentry", "pk": 15, "fields": {"action_time": "2024-01-05T07:20:40.111Z", "user": 5, "content_type": 11, "object_id": "7", "object_repr": "Saputra", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 16, "fields": {"action_time": "2024-01-05T07:26:16.360Z", "user": 5, "content_type": 9, "object_id": "6", "object_repr": "Elyas", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 17, "fields": {"action_time": "2024-01-09T03:58:40.120Z", "user": 5, "content_type": 11, "object_id": "8", "object_repr": "Shuna", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "admin.logentry", "pk": 18, "fields": {"action_time": "2024-01-12T03:35:30.933Z", "user": 5, "content_type": 9, "object_id": "7", "object_repr": "member78", "action_flag": 1, "change_message": "[{\"added\": {}}]"}}, {"model": "auth.permission", "pk": 1, "fields": {"name": "Can add log entry", "content_type": 1, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change log entry", "content_type": 1, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete log entry", "content_type": 1, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can view log entry", "content_type": 1, "codename": "view_logentry"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can view permission", "content_type": 2, "codename": "view_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can view group", "content_type": 3, "codename": "view_group"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add content type", "content_type": 4, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change content type", "content_type": 4, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete content type", "content_type": 4, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can view content type", "content_type": 4, "codename": "view_contenttype"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can view session", "content_type": 5, "codename": "view_session"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can add user", "content_type": 6, "codename": "add_customuser"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can change user", "content_type": 6, "codename": "change_customuser"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can delete user", "content_type": 6, "codename": "delete_customuser"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can view user", "content_type": 6, "codename": "view_customuser"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add book", "content_type": 7, "codename": "add_book"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change book", "content_type": 7, "codename": "change_book"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete book", "content_type": 7, "codename": "delete_book"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can view book", "content_type": 7, "codename": "view_book"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can add category", "content_type": 8, "codename": "add_category"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can change category", "content_type": 8, "codename": "change_category"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can delete category", "content_type": 8, "codename": "delete_category"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can view category", "content_type": 8, "codename": "view_category"}}, {"model": "auth.permission", "pk": 33, "fields": {"name": "Can add member", "content_type": 9, "codename": "add_member"}}, {"model": "auth.permission", "pk": 34, "fields": {"name": "Can change member", "content_type": 9, "codename": "change_member"}}, {"model": "auth.permission", "pk": 35, "fields": {"name": "Can delete member", "content_type": 9, "codename": "delete_member"}}, {"model": "auth.permission", "pk": 36, "fields": {"name": "Can view member", "content_type": 9, "codename": "view_member"}}, {"model": "auth.permission", "pk": 37, "fields": {"name": "Can add login history", "content_type": 10, "codename": "add_loginhistory"}}, {"model": "auth.permission", "pk": 38, "fields": {"name": "Can change login history", "content_type": 10, "codename": "change_loginhistory"}}, {"model": "auth.permission", "pk": 39, "fields": {"name": "Can delete login history", "content_type": 10, "codename": "delete_loginhistory"}}, {"model": "auth.permission", "pk": 40, "fields": {"name": "Can view login history", "content_type": 10, "codename": "view_loginhistory"}}, {"model": "auth.permission", "pk": 41, "fields": {"name": "Can add librarian", "content_type": 11, "codename": "add_librarian"}}, {"model": "auth.permission", "pk": 42, "fields": {"name": "Can change librarian", "content_type": 11, "codename": "change_librarian"}}, {"model": "auth.permission", "pk": 43, "fields": {"name": "Can delete librarian", "content_type": 11, "codename": "delete_librarian"}}, {"model": "auth.permission", "pk": 44, "fields": {"name": "Can view librarian", "content_type": 11, "codename": "view_librarian"}}, {"model": "auth.permission", "pk": 45, "fields": {"name": "Can add book loan", "content_type": 12, "codename": "add_bookloan"}}, {"model": "auth.permission", "pk": 46, "fields": {"name": "Can change book loan", "content_type": 12, "codename": "change_bookloan"}}, {"model": "auth.permission", "pk": 47, "fields": {"name": "Can delete book loan", "content_type": 12, "codename": "delete_bookloan"}}, {"model": "auth.permission", "pk": 48, "fields": {"name": "Can view book loan", "content_type": 12, "codename": "view_bookloan"}}, {"model": "auth.permission", "pk": 49, "fields": {"name": "Can add member permission", "content_type": 13, "codename": "add_memberpermission"}}, {"model": "auth.permission", "pk": 50, "fields": {"name": "Can change member permission", "content_type": 13, "codename": "change_memberpermission"}}, {"model": "auth.permission", "pk": 51, "fields": {"name": "Can delete member permission", "content_type": 13, "codename": "delete_memberpermission"}}, {"model": "auth.permission", "pk": 52, "fields": {"name": "Can view member permission", "content_type": 13, "codename": "view_memberpermission"}}, {"model": "auth.permission", "pk": 53, "fields": {"name": "Can view buku", "content_type": 13, "codename": "view_buku"}}, {"model": "auth.permission", "pk": 54, "fields": {"name": "Can add Token", "content_type": 14, "codename": "add_token"}}, {"model": "auth.permission", "pk": 55, "fields": {"name": "Can change Token", "content_type": 14, "codename": "change_token"}}, {"model": "auth.permission", "pk": 56, "fields": {"name": "Can delete Token", "content_type": 14, "codename": "delete_token"}}, {"model": "auth.permission", "pk": 57, "fields": {"name": "Can view Token", "content_type": 14, "codename": "view_token"}}, {"model": "auth.permission", "pk": 58, "fields": {"name": "Can add token", "content_type": 15, "codename": "add_tokenproxy"}}, {"model": "auth.permission", "pk": 59, "fields": {"name": "Can change token", "content_type": 15, "codename": "change_tokenproxy"}}, {"model": "auth.permission", "pk": 60, "fields": {"name": "Can delete token", "content_type": 15, "codename": "delete_tokenproxy"}}, {"model": "auth.permission", "pk": 61, "fields": {"name": "Can view token", "content_type": 15, "codename": "view_tokenproxy"}}, {"model": "auth.permission", "pk": 62, "fields": {"name": "Can add blacklisted token", "content_type": 16, "codename": "add_blacklistedtoken"}}, {"model": "auth.permission", "pk": 63, "fields": {"name": "Can change blacklisted token", "content_type": 16, "codename": "change_blacklistedtoken"}}, {"model": "auth.permission", "pk": 64, "fields": {"name": "Can delete blacklisted token", "content_type": 16, "codename": "delete_blacklistedtoken"}}, {"model": "auth.permission", "pk": 65, "fields": {"name": "Can view blacklisted token", "content_type": 16, "codename": "view_blacklistedtoken"}}, {"model": "auth.permission", "pk": 66, "fields": {"name": "Can add outstanding token", "content_type": 17, "codename": "add_outstandingtoken"}}, {"model": "auth.permission", "pk": 67, "fields": {"name": "Can change outstanding token", "content_type": 17, "codename": "change_outstandingtoken"}}, {"model": "auth.permission", "pk": 68, "fields": {"name": "Can delete outstanding token", "content_type": 17, "codename": "delete_outstandingtoken"}}, {"model": "auth.permission", "pk": 69, "fields": {"name": "Can view outstanding token", "content_type": 17, "codename": "view_outstandingtoken"}}, {"model": "auth.group", "pk": 1, "fields": {"name": "Librarian", "permissions": []}}, {"model": "auth.group", "pk": 2, "fields": {"name": "Pustakawan", "permissions": []}}, {"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "library", "model": "customuser"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "library", "model": "book"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "library", "model": "category"}}, {"model": "contenttypes.contenttype", "pk": 9, "fields": {"app_label": "library", "model": "member"}}, {"model": "contenttypes.contenttype", "pk": 10, "fields": {"app_label": "library", "model": "loginhistory"}}, {"model": "contenttypes.contenttype", "pk": 11, "fields": {"app_label": "library", "model": "librarian"}}, {"model": "contenttypes.contenttype", "pk": 12, "fields": {"app_label": "library", "model": "bookloan"}}, {"model": "contenttypes.contenttype", "pk": 13, "fields": {"app_label": "library", "model": "memberpermission"}}, {"model": "contenttypes.contenttype", "pk": 14, "fields": {"app_label": "authtoken", "model": "token"}}, {"model": "contenttypes.contenttype", "pk": 15, "fields": {"app_label": "authtoken", "model": "tokenproxy"}}, {"model": "contenttypes.contenttype", "pk": 16, "fields": {"app_label": "token_blacklist", "model": "blacklistedtoken"}}, {"model": "contenttypes.contenttype", "pk": 17, "fields": {"app_label": "token_blacklist", "model": "outstandingtoken"}}, {"model": "sessions.session", "pk": "0ok5cf23fih7h0g2ohfcmtjqrnb5srfi", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2hBwWmBcuvcMZGAGqZo2Ke3KeHfbpAvdvvf-f6tI61Lj2mSOA6uL6tXplyXKTxl3wQ8a75PO07jMQ9J7og_b9G1ieV2P9u-gUqvbmhAseAghkQXpOEku4NiZkgwykrDfIIARhOxK8eBsjw7NOXQSANXnC_B3N70:1rOBgV:QqDPiIgfx8zZ9-PR2t59iCrqf9-DTtTmDuGNxzHAf6U", "expire_date": "2024-01-26T07:10:31.588Z"}}, {"model": "sessions.session", "pk": "89xoudzeej3jyuronhmctstuby1sc0oc", "fields": {"session_data": ".eJxVjEEOgjAQRe_StWk6hU7BpXvO0EyZqaCmTSisjHcXEha6_e-9_1aBtnUKW5UlzKyuChp1-R0jjU_JB-EH5XvRY8nrMkd9KPqkVQ-F5XU73b-Dieq012Q7B0LU9rYF7iL2CEgWhZwnBgDj0QlDHxOalGwiQd_A7jEYAqs-X_qMN8E:1rLJzj:bcGY6Uf3SGfgsnKg07I4y-0EfFbcoYehiDOABS00Sy8", "expire_date": "2024-01-18T09:26:31.230Z"}}, {"model": "sessions.session", "pk": "ca0wmawk8d2keobswcl364c8kp6ik6n6", "fields": {"session_data": "e30:1rKxKi:lkUkbwQZMWzYpywW4RHvU-v5ILjuoNNT69H7LSEiZLs", "expire_date": "2024-01-17T09:14:40.001Z"}}, {"model": "sessions.session", "pk": "kl0vpczf4pxy6j4by01fut3lshyy9hlz", "fields": {"session_data": "e30:1rKwba:Vg3obgbwLCVpt2D4eJBMQNhvcksmn8mMhWKOhCwPsWE", "expire_date": "2024-01-17T08:28:02.974Z"}}, {"model": "library.customuser", "pk": 1, "fields": {"password": "pbkdf2_sha256$600000$9hSplZ32xa6VVQXJQ41qLX$lZ91MCIgqBlUM0Ar9mJairfd1HQ8aomrFnh5/x+6r4c=", "last_login": "2024-01-05T07:10:41.245Z", "is_superuser": false, "username": "admin123", "first_name": "admin", "last_name": "Utama", "email": "admin123@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T03:59:10.504Z", "is_member": false, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 2, "fields": {"password": "pbkdf2_sha256$600000$68gAP9fbHVa8VWrVvyW2i3$4GVir6lgb1ehP/A7blcSwDQfDjIivrSdLs00exhi14Y=", "last_login": "2024-01-03T09:13:21Z", "is_superuser": false, "username": "galangrambu12", "first_name": "Galang", "last_name": "Rambu", "email": "galang@dev.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T08:10:29Z", "is_member": false, "is_librarian": true, "groups": [1], "user_permissions": []}}, {"model": "library.customuser", "pk": 3, "fields": {"password": "pbkdf2_sha256$600000$y1jEnPADcWHaB7HLF6RHp1$+18eqnLDe4ur/kcGxWDP99Ue1EMe6FoaySCXx2JB7e0=", "last_login": "2024-01-03T08:29:02.805Z", "is_superuser": false, "username": "dmspatan", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T08:28:02.715Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 4, "fields": {"password": "pbkdf2_sha256$600000$iHpI913cXtBgGRHF7OwJIJ$B3EnzbCB3uH0sR0YPZ1weEaqycOdwkm5N+pLkwp+AvE=", "last_login": "2024-01-03T09:15:22.792Z", "is_superuser": false, "username": "adminja123", "first_name": "ninja", "last_name": "Admin", "email": "adminja123@dev.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T09:14:39.483Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 5, "fields": {"password": "pbkdf2_sha256$600000$jAe4pUGNpXFDzJSBoMIVqP$RhgDrnKpS3Eei5F2QWwb6kdYM3k70zq0aYzWgyr9lZY=", "last_login": "2024-01-12T07:10:31.585Z", "is_superuser": true, "username": "admin", "first_name": "", "last_name": "", "email": "admin@dev.com", "is_staff": true, "is_active": true, "date_joined": "2024-01-03T09:22:20Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 6, "fields": {"password": "pbkdf2_sha256$600000$JaEHJOXkCkk4CGwftPVvYy$V0SBP/vvXr8MJi6KpLtG1iabnOadwH6HPtaTVGEOWeE=", "last_login": "2024-01-04T10:59:10.325Z", "is_superuser": false, "username": "nunura", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T10:06:27.904Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 7, "fields": {"password": "pbkdf2_sha256$600000$ENweAvHSIuCq7RNzBfGslP$ecx9VzmY8Ey9fWyre4+F9NPsK6HbFvyqV8YOssD7Kcc=", "last_login": "2024-01-03T10:22:53.822Z", "is_superuser": false, "username": "jumuan", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-03T10:22:53.566Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 8, "fields": {"password": "pbkdf2_sha256$600000$PSTxg6GGjDSOtmmQ27OFN0$rIaE306k9Wk1A6K/QM34IzFcynO4/s1oGkRuy/EfAGs=", "last_login": "2024-01-04T05:49:27.434Z", "is_superuser": false, "username": "slardar", "first_name": "Sala Dara", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T05:49:26.855Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 9, "fields": {"password": "pbkdf2_sha256$600000$6W9KobdDKO4TMSC6jZYgAr$F118sOK5Z5MHbYe8Tk3K2wBnNHSrr81GWQmYLZpJjgo=", "last_login": "2024-01-04T05:50:38.215Z", "is_superuser": false, "username": "mutmut", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T05:50:37.897Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 10, "fields": {"password": "pbkdf2_sha256$600000$0Q3xx75M6i8QqLRrNZgsae$e17vb+H5PCDCVs5QknbOR88dzEHNbabfAVdIYrEcIq4=", "last_login": "2024-01-04T05:52:21.955Z", "is_superuser": false, "username": "juggernaut", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T05:52:21.698Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 11, "fields": {"password": "gagal1234", "last_login": "2024-01-04T06:21:58.548Z", "is_superuser": false, "username": "django", "first_name": "", "last_name": "", "email": "django@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T06:21:58.540Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 12, "fields": {"password": "siprimus12", "last_login": "2024-01-04T06:22:53.378Z", "is_superuser": false, "username": "primus22", "first_name": "", "last_name": "", "email": "priprimus@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T06:22:53.370Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 13, "fields": {"password": "xamu3456", "last_login": "2024-01-04T09:26:31.228Z", "is_superuser": false, "username": "devadm", "first_name": "", "last_name": "", "email": "admdev@dev.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T09:26:31.180Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 14, "fields": {"password": "pbkdf2_sha256$600000$HQnLMPcE7GFkqX4QOymMjl$ahvTSHRHl8Lk2a5t/SdK7rJXGs15EY6bSsJaMNgQbxs=", "last_login": "2024-01-09T08:48:30.830Z", "is_superuser": false, "username": "admin12", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T09:42:48.184Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 15, "fields": {"password": "pbkdf2_sha256$600000$bRBzWwIBVigdjrhU166Zpz$YqxhuK8jhYAL0V1TPR1fROfAggMEe8SPUD4Nv7TK+rQ=", "last_login": null, "is_superuser": false, "username": "opaksing", "first_name": "", "last_name": "", "email": "opak@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T10:03:32.193Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 16, "fields": {"password": "pbkdf2_sha256$600000$w3oGsRg1jPWCXU3hxi6xG9$DjCysL6IbwEYnVh9dMKZUyJDXZWc6PfqVMzQEzx8jrE=", "last_login": "2024-01-04T10:53:28.052Z", "is_superuser": false, "username": "gabusbaru", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T10:53:27.794Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 17, "fields": {"password": "pbkdf2_sha256$600000$i62IV0QTcRIQxTHtWI8F06$W4hOSnPEnGkBA0wFwytAigGOZkDyX+rqtU9/dGYH9Lc=", "last_login": "2024-01-04T10:54:39.706Z", "is_superuser": false, "username": "admin777", "first_name": "Adminas", "last_name": "", "email": "admin777@min.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-04T10:54:39.163Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 18, "fields": {"password": "pbkdf2_sha256$600000$ggqcYXT5JrV6I9CVuZHCSE$tkDO6g4Y7eitywu+VWzoZajhmhfyNh+5DUwRKwfWoF8=", "last_login": "2024-01-05T07:06:50.078Z", "is_superuser": false, "username": "adminbaru", "first_name": "Saputra", "last_name": "", "email": "admin11@dev.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T07:04:39.181Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 19, "fields": {"password": "pbkdf2_sha256$600000$52YkeMrIgEOqfNT0kCRHSy$9tqtxr1Arz6V9bS+ff3qn8YHeVB7gpCxK62tM1d2hSY=", "last_login": "2024-01-05T07:26:35.427Z", "is_superuser": false, "username": "ecigraf", "first_name": "", "last_name": "", "email": "", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T07:24:33.995Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 20, "fields": {"password": "pbkdf2_sha256$600000$TiItBPrMqPo6v5fxC7kwVG$ZjTsJSYX+evMgyTDnYs4ye5FVWlPZmLOAxSZu4Vyacw=", "last_login": "2024-01-05T08:50:41.987Z", "is_superuser": false, "username": "librarian1", "first_name": "", "last_name": "", "email": "libradong@dev.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T08:50:41.476Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 21, "fields": {"password": "pbkdf2_sha256$600000$F96jsWLiXHAIWN0RFBa3jc$HIqBrGYGSYUpy0/jq3Z8g7DleqiLeWvefkrtuJL0NpQ=", "last_login": null, "is_superuser": false, "username": "rofi123", "first_name": "", "last_name": "", "email": "rofi@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T09:02:34.409Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 22, "fields": {"password": "pbkdf2_sha256$600000$Ogf04U4I5WUTYF6Eo9c7i1$PVWjcV+lZB/ZC032sPcIYlOPCu5tE9nSKStF40HRBSw=", "last_login": null, "is_superuser": false, "username": "ravintola123123", "first_name": "", "last_name": "", "email": "ravin@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T09:12:43.600Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 23, "fields": {"password": "pbkdf2_sha256$600000$gFhVQ0E6ynaqlLstFzJbNH$3Tkn2c3bGrN9eJWf5/QP9ASlQNbYZK9x4u0qu/ocJdI=", "last_login": "2024-01-05T09:32:21.149Z", "is_superuser": false, "username": "memberbaru1", "first_name": "", "last_name": "", "email": "barumember@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T09:24:56.630Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 24, "fields": {"password": "pbkdf2_sha256$600000$X5ZXSTGJ0hYx2n7uyUOJtp$1honLGaHRodGG454zShqBuybAOEQ3JtGIda5/u8SCtU=", "last_login": "2024-01-05T09:27:13.336Z", "is_superuser": false, "username": "librarianbaru12", "first_name": "", "last_name": "Langga", "email": "pustaka@libra.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T09:27:09.497Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 25, "fields": {"password": "pbkdf2_sha256$600000$Ze6lUoJc70bfa0luS7nzTJ$I+hfttVgLH5w48dCAdVRlmTYg0ZI8DnpBmSRluPhwM0=", "last_login": null, "is_superuser": false, "username": "memberlagi1", "first_name": "", "last_name": "", "email": "memberlagi12@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T10:53:26.939Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 26, "fields": {"password": "pbkdf2_sha256$600000$hMLk2wC5VENiZYRFpfnsFD$prfLc/PpOaKMhubR50/StmKKSX6hUXYUJcDL34HOK/k=", "last_login": null, "is_superuser": false, "username": "asd21", "first_name": "", "last_name": "", "email": "asd@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T11:17:47.503Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 27, "fields": {"password": "pbkdf2_sha256$600000$uAT80E8kthqgJ0NogdVwPy$PEt73gkLmYlDoSzlnCxhtkNZdu0pyi/ItdGKbfl6AYI=", "last_login": null, "is_superuser": false, "username": "member77", "first_name": "", "last_name": "", "email": "member77@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-05T11:44:39.860Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 28, "fields": {"password": "pbkdf2_sha256$600000$Wfh0BwyyWQ2unizkF6rp9d$NXz/Mga6xqXaxUFq0/Ng2xw1WIo7WoUim5/k2X8qXwo=", "last_login": null, "is_superuser": false, "username": "member78", "first_name": "Gadis", "last_name": "Meldi", "email": "adisga@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-08T02:32:21.510Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 29, "fields": {"password": "pbkdf2_sha256$600000$36SoJguErMrN3nT92etzYv$koU5kDAWcFB/yWqmnwF4P/SrKnCovqm2eiW6tAHBQUI=", "last_login": "2024-01-10T07:05:01.555Z", "is_superuser": false, "username": "librarian778", "first_name": "Shuna", "last_name": "Leo", "email": "leoshuna@gmailc.om", "is_staff": false, "is_active": true, "date_joined": "2024-01-08T02:36:46.268Z", "is_member": false, "is_librarian": true, "groups": [], "user_permissions": []}}, {"model": "library.customuser", "pk": 30, "fields": {"password": "pbkdf2_sha256$600000$qvHS2osGtEW4NH8M0CbiO6$QdulcKJtRZfaCNkp5eI9mRgDPX+Uzgi5sU5PI27UJug=", "last_login": null, "is_superuser": false, "username": "member781", "first_name": "", "last_name": "", "email": "member781@member.com", "is_staff": false, "is_active": true, "date_joined": "2024-01-10T06:47:40.946Z", "is_member": true, "is_librarian": false, "groups": [], "user_permissions": []}}, {"model": "library.category", "pk": 1, "fields": {"name": "Horror"}}, {"model": "library.category", "pk": 2, "fields": {"name": "Misteri"}}, {"model": "library.category", "pk": 3, "fields": {"name": "Pendidikan"}}, {"model": "library.category", "pk": 4, "fields": {"name": "Anime"}}, {"model": "library.category", "pk": 5, "fields": {"name": "Novel"}}, {"model": "library.category", "pk": 6, "fields": {"name": "Light Novel"}}, {"model": "library.category", "pk": 7, "fields": {"name": "Sejarah"}}, {"model": "library.category", "pk": 8, "fields": {"name": "Biografi"}}, {"model": "library.book", "pk": 1, "fields": {"title": "Two Piece", "author": "Eichiro Oda", "publisher": "Shonen Jump", "category": 4, "date_publish": 1999, "image": "book_images/peakpx-c.jpg", "isbn": "10104560"}}, {"model": "library.book", "pk": 2, "fields": {"title": "Lawang Sewu", "author": "Ki Pranata", "publisher": "Dunia Malam", "category": 5, "date_publish": 2003, "image": "book_images/peakpx-c_KYzWbMV.jpg", "isbn": "10104851"}}, {"model": "library.book", "pk": 4, "fields": {"title": "Misteri Akhir Zaman", "author": "R Tolkien", "publisher": "Panorama Picture", "category": 2, "date_publish": 2003, "image": "book_images/Buku-Misteri-Akhir-Zaman-cover-2.jpg", "isbn": "112004515"}}, {"model": "library.book", "pk": 5, "fields": {"title": "hunter x hunter", "author": "Togashi", "publisher": "Shonen Jump", "category": 4, "date_publish": 2001, "image": "", "isbn": "12109561"}}, {"model": "library.book", "pk": 6, "fields": {"title": "Baru", "author": "Ravintola", "publisher": "Jga", "category": 1, "date_publish": 2010, "image": "book_images/perpustakaan.jpg", "isbn": "14578546"}}, {"model": "library.book", "pk": 7, "fields": {"title": "BJ Habiebie", "author": "Samsudin", "publisher": "Terang", "category": 8, "date_publish": 2003, "image": "book_images/perpustakaan_S2Z63WG.jpg", "isbn": "456186461"}}, {"model": "library.book", "pk": 8, "fields": {"title": "Japan Feodal", "author": "Robert G", "publisher": "Braith", "category": 7, "date_publish": 1997, "image": "book_images/perpustakaan_Aenge5t.jpg", "isbn": "784569221"}}, {"model": "library.member", "pk": 1, "fields": {"user": 6, "name": "nunu", "address": "kemiri jalan 3", "email": "navrus66@gmail.com", "birth_place": "jakarta", "date_birth": "1994-12-23", "phone_number": "+6281213566175"}}, {"model": "library.member", "pk": 2, "fields": {"user": 7, "name": "Jumu", "address": "Kali Malang", "email": "jumuan@gmail.com", "birth_place": "Bekasi", "date_birth": "1977-12-13", "phone_number": "+628124561234"}}, {"model": "library.member", "pk": 3, "fields": {"user": 12, "name": "Primus", "address": "Majapahit 11", "email": "priprimus@gmail.com", "birth_place": "Asgrad", "date_birth": "1982-03-26", "phone_number": "+6283812467548"}}, {"model": "library.member", "pk": 4, "fields": {"user": 13, "name": "devdev", "address": "devdev", "email": "admdev@dev.com", "birth_place": "Cianjur", "date_birth": "1975-12-12", "phone_number": "+6281246952365"}}, {"model": "library.member", "pk": 5, "fields": {"user": 14, "name": "rofi rahmat", "address": "Tanjung Duren Timur", "email": "admin12@gmail.com", "birth_place": "jakarta", "date_birth": "1985-10-23", "phone_number": "+628386595412"}}, {"model": "library.member", "pk": 6, "fields": {"user": 19, "name": "Elyas", "address": "Gili Trawangan, Lombok", "email": "ecigraf@member.com", "birth_place": "Bima", "date_birth": "2001-03-24", "phone_number": "+628114563298"}}, {"model": "library.member", "pk": 7, "fields": {"user": 28, "name": "member78", "address": "jakarta", "email": "member78@gmail.com", "birth_place": "Asgrad", "date_birth": "1977-12-19", "phone_number": "+6285466351152"}}, {"model": "library.bookloan", "pk": 1, "fields": {"book": 1, "member": 1, "loan_date": "2024-01-03", "due_date": "2024-01-03", "return_date": "2024-01-11", "is_returned": true}}, {"model": "library.bookloan", "pk": 2, "fields": {"book": 1, "member": 3, "loan_date": "2024-01-04", "due_date": "2024-01-05", "return_date": "2024-01-11", "is_returned": true}}, {"model": "library.bookloan", "pk": 3, "fields": {"book": 2, "member": 1, "loan_date": "2024-01-05", "due_date": "2024-01-07", "return_date": "2024-01-11", "is_returned": true}}, {"model": "library.bookloan", "pk": 5, "fields": {"book": 1, "member": 3, "loan_date": "2024-01-05", "due_date": "2024-01-07", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 6, "fields": {"book": 5, "member": 6, "loan_date": "2024-01-08", "due_date": "2024-01-10", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 7, "fields": {"book": 4, "member": 4, "loan_date": "2024-01-08", "due_date": "2024-01-11", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 8, "fields": {"book": 5, "member": 3, "loan_date": "2024-01-09", "due_date": "2024-01-12", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 9, "fields": {"book": 4, "member": 3, "loan_date": "2024-01-10", "due_date": "2024-01-14", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 10, "fields": {"book": 5, "member": 2, "loan_date": "2024-01-10", "due_date": "2024-01-13", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 11, "fields": {"book": 4, "member": 3, "loan_date": "2024-01-10", "due_date": "2024-01-13", "return_date": "2024-01-10", "is_returned": true}}, {"model": "library.bookloan", "pk": 12, "fields": {"book": 6, "member": 7, "loan_date": "2024-01-12", "due_date": "2024-01-14", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 17, "fields": {"book": 2, "member": 7, "loan_date": "2024-01-12", "due_date": "2024-01-17", "return_date": null, "is_returned": false}}, {"model": "library.bookloan", "pk": 18, "fields": {"book": 6, "member": 7, "loan_date": "2024-01-12", "due_date": "2024-01-18", "return_date": null, "is_returned": false}}, {"model": "library.librarian", "pk": 1, "fields": {"user": 2, "name": "Gilang", "address": "Medan Raya II", "last_name": "Ramadhan S", "birth_place": "Jakarta", "date_birth": "1985-12-10", "phone_number": "+6281245748891"}}, {"model": "library.librarian", "pk": 2, "fields": {"user": 5, "name": "admin", "address": "kantor", "last_name": "admin juga", "birth_place": "jakarta", "date_birth": "2000-05-23", "phone_number": "+628454787141"}}, {"model": "library.librarian", "pk": 3, "fields": {"user": 11, "name": "Django", "address": "manca 11", "last_name": "Frame", "birth_place": "Batu Raden", "date_birth": "1978-03-21", "phone_number": "083869857456"}}, {"model": "library.librarian", "pk": 4, "fields": {"user": 1, "name": "Zidane12", "address": "Tangerang", "last_name": "Kareem", "birth_place": "Jakarta", "date_birth": "1995-03-16", "phone_number": "+6285698456987"}}, {"model": "library.librarian", "pk": 5, "fields": {"user": 4, "name": "Ninja", "address": "Konoha", "last_name": "Uzumaki", "birth_place": "Tsunagakure", "date_birth": "1999-02-22", "phone_number": "+628214569824"}}, {"model": "library.librarian", "pk": 6, "fields": {"user": 17, "name": "Adminas", "address": "jalan 77 Kaliurang", "last_name": "Ringo", "birth_place": "Slema", "date_birth": "2000-06-30", "phone_number": "+62854963214"}}, {"model": "library.librarian", "pk": 7, "fields": {"user": 18, "name": "Saputra11", "address": "bandung", "last_name": "Guntur", "birth_place": "Bandung", "date_birth": "2024-01-05", "phone_number": "+6285698456987"}}, {"model": "library.librarian", "pk": 8, "fields": {"user": 29, "name": "Shuna", "address": "Jura Tempest Rempokoku", "last_name": "Leo", "birth_place": "Rimuru City", "date_birth": "1977-12-13", "phone_number": "+628154787745"}}, {"model": "library.loginhistory", "pk": 1, "fields": {"librarian": 1, "login_time": "2024-01-03T03:59:10.758Z"}}, {"model": "library.loginhistory", "pk": 2, "fields": {"librarian": 1, "login_time": "2024-01-03T06:25:55.056Z"}}, {"model": "library.loginhistory", "pk": 3, "fields": {"librarian": 1, "login_time": "2024-01-03T06:53:24.249Z"}}, {"model": "library.loginhistory", "pk": 4, "fields": {"librarian": 2, "login_time": "2024-01-03T08:21:03.323Z"}}, {"model": "library.loginhistory", "pk": 5, "fields": {"librarian": 2, "login_time": "2024-01-03T08:24:26.408Z"}}, {"model": "library.loginhistory", "pk": 6, "fields": {"librarian": 2, "login_time": "2024-01-03T08:24:58.149Z"}}, {"model": "library.loginhistory", "pk": 7, "fields": {"librarian": 2, "login_time": "2024-01-03T08:26:08.554Z"}}, {"model": "library.loginhistory", "pk": 8, "fields": {"librarian": 3, "login_time": "2024-01-03T08:28:02.976Z"}}, {"model": "library.loginhistory", "pk": 9, "fields": {"librarian": 3, "login_time": "2024-01-03T08:29:02.803Z"}}, {"model": "library.loginhistory", "pk": 10, "fields": {"librarian": 2, "login_time": "2024-01-03T09:13:21.434Z"}}, {"model": "library.loginhistory", "pk": 11, "fields": {"librarian": 4, "login_time": "2024-01-03T09:14:40.003Z"}}, {"model": "library.loginhistory", "pk": 12, "fields": {"librarian": 4, "login_time": "2024-01-03T09:15:22.790Z"}}, {"model": "library.loginhistory", "pk": 13, "fields": {"librarian": 5, "login_time": "2024-01-03T09:22:40.038Z"}}, {"model": "library.loginhistory", "pk": 14, "fields": {"librarian": 6, "login_time": "2024-01-03T10:06:28.229Z"}}, {"model": "library.loginhistory", "pk": 15, "fields": {"librarian": 5, "login_time": "2024-01-03T10:08:55.867Z"}}, {"model": "library.loginhistory", "pk": 16, "fields": {"librarian": 6, "login_time": "2024-01-03T10:11:56.842Z"}}, {"model": "library.loginhistory", "pk": 17, "fields": {"librarian": 6, "login_time": "2024-01-03T10:13:05.784Z"}}, {"model": "library.loginhistory", "pk": 18, "fields": {"librarian": 5, "login_time": "2024-01-03T10:14:53.472Z"}}, {"model": "library.loginhistory", "pk": 19, "fields": {"librarian": 7, "login_time": "2024-01-03T10:22:53.820Z"}}, {"model": "library.loginhistory", "pk": 20, "fields": {"librarian": 5, "login_time": "2024-01-03T10:23:15.198Z"}}, {"model": "library.loginhistory", "pk": 21, "fields": {"librarian": 5, "login_time": "2024-01-03T11:04:42.162Z"}}, {"model": "library.loginhistory", "pk": 22, "fields": {"librarian": 5, "login_time": "2024-01-03T11:07:25.465Z"}}, {"model": "library.loginhistory", "pk": 23, "fields": {"librarian": 5, "login_time": "2024-01-03T11:09:12.226Z"}}, {"model": "library.loginhistory", "pk": 24, "fields": {"librarian": 8, "login_time": "2024-01-04T05:49:27.432Z"}}, {"model": "library.loginhistory", "pk": 25, "fields": {"librarian": 9, "login_time": "2024-01-04T05:50:38.213Z"}}, {"model": "library.loginhistory", "pk": 26, "fields": {"librarian": 10, "login_time": "2024-01-04T05:52:21.953Z"}}, {"model": "library.loginhistory", "pk": 27, "fields": {"librarian": 11, "login_time": "2024-01-04T06:21:58.546Z"}}, {"model": "library.loginhistory", "pk": 28, "fields": {"librarian": 12, "login_time": "2024-01-04T06:22:53.376Z"}}, {"model": "library.loginhistory", "pk": 29, "fields": {"librarian": 5, "login_time": "2024-01-04T06:23:11.376Z"}}, {"model": "library.loginhistory", "pk": 30, "fields": {"librarian": 5, "login_time": "2024-01-04T08:58:45.907Z"}}, {"model": "library.loginhistory", "pk": 31, "fields": {"librarian": 13, "login_time": "2024-01-04T09:26:31.225Z"}}, {"model": "library.loginhistory", "pk": 32, "fields": {"librarian": 14, "login_time": "2024-01-04T09:43:28.611Z"}}, {"model": "library.loginhistory", "pk": 33, "fields": {"librarian": 14, "login_time": "2024-01-04T09:57:29.759Z"}}, {"model": "library.loginhistory", "pk": 34, "fields": {"librarian": 14, "login_time": "2024-01-04T09:57:59.410Z"}}, {"model": "library.loginhistory", "pk": 35, "fields": {"librarian": 16, "login_time": "2024-01-04T10:53:28.050Z"}}, {"model": "library.loginhistory", "pk": 36, "fields": {"librarian": 17, "login_time": "2024-01-04T10:54:39.704Z"}}, {"model": "library.loginhistory", "pk": 37, "fields": {"librarian": 5, "login_time": "2024-01-04T10:58:48.595Z"}}, {"model": "library.loginhistory", "pk": 38, "fields": {"librarian": 6, "login_time": "2024-01-04T10:59:10.323Z"}}, {"model": "library.loginhistory", "pk": 39, "fields": {"librarian": 5, "login_time": "2024-01-05T02:04:32.624Z"}}, {"model": "library.loginhistory", "pk": 40, "fields": {"librarian": 5, "login_time": "2024-01-05T02:11:46.808Z"}}, {"model": "library.loginhistory", "pk": 41, "fields": {"librarian": 14, "login_time": "2024-01-05T02:38:58.471Z"}}, {"model": "library.loginhistory", "pk": 42, "fields": {"librarian": 5, "login_time": "2024-01-05T04:00:01.200Z"}}, {"model": "library.loginhistory", "pk": 43, "fields": {"librarian": 14, "login_time": "2024-01-05T06:21:40.329Z"}}, {"model": "library.loginhistory", "pk": 44, "fields": {"librarian": 5, "login_time": "2024-01-05T06:28:56.624Z"}}, {"model": "library.loginhistory", "pk": 45, "fields": {"librarian": 5, "login_time": "2024-01-05T06:29:01.303Z"}}, {"model": "library.loginhistory", "pk": 46, "fields": {"librarian": 5, "login_time": "2024-01-05T06:31:03.831Z"}}, {"model": "library.loginhistory", "pk": 47, "fields": {"librarian": 14, "login_time": "2024-01-05T06:31:10.011Z"}}, {"model": "library.loginhistory", "pk": 48, "fields": {"librarian": 14, "login_time": "2024-01-05T06:33:31.016Z"}}, {"model": "library.loginhistory", "pk": 49, "fields": {"librarian": 14, "login_time": "2024-01-05T06:35:28.647Z"}}, {"model": "library.loginhistory", "pk": 50, "fields": {"librarian": 14, "login_time": "2024-01-05T06:36:43.665Z"}}, {"model": "library.loginhistory", "pk": 51, "fields": {"librarian": 14, "login_time": "2024-01-05T06:36:55.253Z"}}, {"model": "library.loginhistory", "pk": 52, "fields": {"librarian": 5, "login_time": "2024-01-05T06:48:27.621Z"}}, {"model": "library.loginhistory", "pk": 53, "fields": {"librarian": 5, "login_time": "2024-01-05T06:58:45.301Z"}}, {"model": "library.loginhistory", "pk": 54, "fields": {"librarian": 14, "login_time": "2024-01-05T06:58:57.391Z"}}, {"model": "library.loginhistory", "pk": 55, "fields": {"librarian": 18, "login_time": "2024-01-05T07:04:39.684Z"}}, {"model": "library.loginhistory", "pk": 56, "fields": {"librarian": 18, "login_time": "2024-01-05T07:06:50.077Z"}}, {"model": "library.loginhistory", "pk": 57, "fields": {"librarian": 5, "login_time": "2024-01-05T07:08:15.579Z"}}, {"model": "library.loginhistory", "pk": 58, "fields": {"librarian": 1, "login_time": "2024-01-05T07:08:38.562Z"}}, {"model": "library.loginhistory", "pk": 59, "fields": {"librarian": 1, "login_time": "2024-01-05T07:09:06.570Z"}}, {"model": "library.loginhistory", "pk": 60, "fields": {"librarian": 5, "login_time": "2024-01-05T07:09:49.738Z"}}, {"model": "library.loginhistory", "pk": 61, "fields": {"librarian": 1, "login_time": "2024-01-05T07:10:41.243Z"}}, {"model": "library.loginhistory", "pk": 62, "fields": {"librarian": 5, "login_time": "2024-01-05T07:15:58.745Z"}}, {"model": "library.loginhistory", "pk": 63, "fields": {"librarian": 19, "login_time": "2024-01-05T07:24:34.271Z"}}, {"model": "library.loginhistory", "pk": 64, "fields": {"librarian": 19, "login_time": "2024-01-05T07:24:47.851Z"}}, {"model": "library.loginhistory", "pk": 65, "fields": {"librarian": 5, "login_time": "2024-01-05T07:25:05.954Z"}}, {"model": "library.loginhistory", "pk": 66, "fields": {"librarian": 19, "login_time": "2024-01-05T07:26:35.425Z"}}, {"model": "library.loginhistory", "pk": 67, "fields": {"librarian": 5, "login_time": "2024-01-05T07:30:27.103Z"}}, {"model": "library.loginhistory", "pk": 68, "fields": {"librarian": 14, "login_time": "2024-01-05T07:31:29.038Z"}}, {"model": "library.loginhistory", "pk": 69, "fields": {"librarian": 5, "login_time": "2024-01-05T07:47:53.615Z"}}, {"model": "library.loginhistory", "pk": 70, "fields": {"librarian": 5, "login_time": "2024-01-05T07:49:29.087Z"}}, {"model": "library.loginhistory", "pk": 71, "fields": {"librarian": 14, "login_time": "2024-01-05T07:52:12.739Z"}}, {"model": "library.loginhistory", "pk": 72, "fields": {"librarian": 5, "login_time": "2024-01-05T08:12:43.949Z"}}, {"model": "library.loginhistory", "pk": 73, "fields": {"librarian": 14, "login_time": "2024-01-05T08:13:22.943Z"}}, {"model": "library.loginhistory", "pk": 74, "fields": {"librarian": 5, "login_time": "2024-01-05T08:14:10.729Z"}}, {"model": "library.loginhistory", "pk": 75, "fields": {"librarian": 14, "login_time": "2024-01-05T08:30:09.087Z"}}, {"model": "library.loginhistory", "pk": 76, "fields": {"librarian": 5, "login_time": "2024-01-05T08:34:38.146Z"}}, {"model": "library.loginhistory", "pk": 77, "fields": {"librarian": 20, "login_time": "2024-01-05T08:50:41.985Z"}}, {"model": "library.loginhistory", "pk": 78, "fields": {"librarian": 23, "login_time": "2024-01-05T09:25:01.102Z"}}, {"model": "library.loginhistory", "pk": 79, "fields": {"librarian": 24, "login_time": "2024-01-05T09:27:13.334Z"}}, {"model": "library.loginhistory", "pk": 80, "fields": {"librarian": 23, "login_time": "2024-01-05T09:32:21.147Z"}}, {"model": "library.loginhistory", "pk": 81, "fields": {"librarian": 5, "login_time": "2024-01-05T09:32:55.581Z"}}, {"model": "library.loginhistory", "pk": 82, "fields": {"librarian": 14, "login_time": "2024-01-05T09:34:17.606Z"}}, {"model": "library.loginhistory", "pk": 83, "fields": {"librarian": 14, "login_time": "2024-01-05T09:34:40.405Z"}}, {"model": "library.loginhistory", "pk": 84, "fields": {"librarian": 5, "login_time": "2024-01-05T10:38:09.466Z"}}, {"model": "library.loginhistory", "pk": 85, "fields": {"librarian": 5, "login_time": "2024-01-05T10:42:47.871Z"}}, {"model": "library.loginhistory", "pk": 86, "fields": {"librarian": 5, "login_time": "2024-01-05T11:05:01.155Z"}}, {"model": "library.loginhistory", "pk": 87, "fields": {"librarian": 5, "login_time": "2024-01-08T03:17:46.922Z"}}, {"model": "library.loginhistory", "pk": 88, "fields": {"librarian": 29, "login_time": "2024-01-09T07:25:11.103Z"}}, {"model": "library.loginhistory", "pk": 89, "fields": {"librarian": 14, "login_time": "2024-01-09T08:48:30.828Z"}}, {"model": "library.loginhistory", "pk": 90, "fields": {"librarian": 29, "login_time": "2024-01-09T08:52:28.915Z"}}, {"model": "library.loginhistory", "pk": 91, "fields": {"librarian": 29, "login_time": "2024-01-10T06:49:57.892Z"}}, {"model": "library.loginhistory", "pk": 92, "fields": {"librarian": 29, "login_time": "2024-01-10T07:05:01.553Z"}}, {"model": "library.loginhistory", "pk": 93, "fields": {"librarian": 5, "login_time": "2024-01-12T03:33:34.738Z"}}, {"model": "library.loginhistory", "pk": 94, "fields": {"librarian": 5, "login_time": "2024-01-12T07:06:27.410Z"}}, {"model": "library.loginhistory", "pk": 95, "fields": {"librarian": 5, "login_time": "2024-01-12T07:10:31.583Z"}}, {"model": "authtoken.token", "pk": "927f8e91cd8cd4b144dc0721bec64bc30e6a025c", "fields": {"user": 6, "created": "2024-01-04T03:50:55.419Z"}}, {"model": "authtoken.token", "pk": "9b1774fb8142f29a4d7c4e1f6f04c2421435d876", "fields": {"user": 5, "created": "2024-01-04T04:33:06.756Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 1, "fields": {"user": 5, "jti": "1106ad756a6848e383e307d201698c90", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0MzM3MiwiaWF0IjoxNzA0MzU2OTcyLCJqdGkiOiIxMTA2YWQ3NTZhNjg0OGUzODNlMzA3ZDIwMTY5OGM5MCIsInVzZXJfaWQiOjV9.rk03eQG4RwEuvvCGIichT6ZkiXvsw60y_W2J5HytdQg", "created_at": "2024-01-04T08:29:32.680Z", "expires_at": "2024-01-05T08:29:32Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 2, "fields": {"user": 5, "jti": "57191e8023044a088c760f1d21ed5ee9", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0MzcxOSwiaWF0IjoxNzA0MzU3MzE5LCJqdGkiOiI1NzE5MWU4MDIzMDQ0YTA4OGM3NjBmMWQyMWVkNWVlOSIsInVzZXJfaWQiOjV9.mvs7pYA4QhdfYAuBdkXW2bO17a4e_6rv7jmTbduaZ5s", "created_at": "2024-01-04T08:35:19.642Z", "expires_at": "2024-01-05T08:35:19Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 3, "fields": {"user": 5, "jti": "da98077f60aa4e078857eb7aba6ff313", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0Mzc4OSwiaWF0IjoxNzA0MzU3Mzg5LCJqdGkiOiJkYTk4MDc3ZjYwYWE0ZTA3ODg1N2ViN2FiYTZmZjMxMyIsInVzZXJfaWQiOjV9.C4zIXVbH8KfNHM2CYbP1u6e_WeVKbVT6geTlW4JmAhI", "created_at": "2024-01-04T08:36:29.897Z", "expires_at": "2024-01-05T08:36:29Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 4, "fields": {"user": 5, "jti": "d50d82db24094b9d8641ba6a19196c87", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0NDE4MCwiaWF0IjoxNzA0MzU3NzgwLCJqdGkiOiJkNTBkODJkYjI0MDk0YjlkODY0MWJhNmExOTE5NmM4NyIsInVzZXJfaWQiOjV9.OZD8EMWLZO3dV2tERgvTkaXpuyUW04f9Nkf57IANMqo", "created_at": "2024-01-04T08:43:00.828Z", "expires_at": "2024-01-05T08:43:00Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 5, "fields": {"user": 5, "jti": "bd4a23ab7acc4b34a4a3629a789ff923", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0Nzk2MywiaWF0IjoxNzA0MzYxNTYzLCJqdGkiOiJiZDRhMjNhYjdhY2M0YjM0YTRhMzYyOWE3ODlmZjkyMyIsInVzZXJfaWQiOjV9._qm4YVqb-HZ2OpGRrT7oLWVHM319Y3x5WCKlCWgg24E", "created_at": "2024-01-04T09:46:03.637Z", "expires_at": "2024-01-05T09:46:03Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 6, "fields": {"user": 6, "jti": "f198982adf514f15bb339f5126dc22d6", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0ODU5MSwiaWF0IjoxNzA0MzYyMTkxLCJqdGkiOiJmMTk4OTgyYWRmNTE0ZjE1YmIzMzlmNTEyNmRjMjJkNiIsInVzZXJfaWQiOjZ9.vtOlas1GnkrIlk9JEocsIoKuzEWcMw-W_NxcSmn8LVk", "created_at": "2024-01-04T09:56:31.667Z", "expires_at": "2024-01-05T09:56:31Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 7, "fields": {"user": 15, "jti": "fcb5160e901643fc902ee8ae14620efc", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDQ0OTA0MCwiaWF0IjoxNzA0MzYyNjQwLCJqdGkiOiJmY2I1MTYwZTkwMTY0M2ZjOTAyZWU4YWUxNDYyMGVmYyIsInVzZXJfaWQiOjE1fQ.IC_h534_A4ZC_BGiGP07fGfea_bNB7m5XPJ1P_UcKSo", "created_at": "2024-01-04T10:04:00.499Z", "expires_at": "2024-01-05T10:04:00Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 8, "fields": {"user": 5, "jti": "52a83cb8634748399d8d48874e924e04", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzIzMCwiaWF0IjoxNzA0NDIwODMwLCJqdGkiOiI1MmE4M2NiODYzNDc0ODM5OWQ4ZDQ4ODc0ZTkyNGUwNCIsInVzZXJfaWQiOjV9.d40j87DQf3KjN_fJ0tFmZVUpr9aX4SOsfhEXHwdnt7Q", "created_at": "2024-01-05T02:13:50.194Z", "expires_at": "2024-01-06T02:13:50Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 9, "fields": {"user": 14, "jti": "cf706ac191034ca9b2bb11d1e8d148d6", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzI0NywiaWF0IjoxNzA0NDIwODQ3LCJqdGkiOiJjZjcwNmFjMTkxMDM0Y2E5YjJiYjExZDFlOGQxNDhkNiIsInVzZXJfaWQiOjE0fQ.jz-tDiy86eU1tEI_nFi08jOh4G-lZz7rQMp9hZwFwbc", "created_at": "2024-01-05T02:14:07.407Z", "expires_at": "2024-01-06T02:14:07Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 10, "fields": {"user": 14, "jti": "2f8ab4973051467aa739f5933b9b87a0", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzM0MiwiaWF0IjoxNzA0NDIwOTQyLCJqdGkiOiIyZjhhYjQ5NzMwNTE0NjdhYTczOWY1OTMzYjliODdhMCIsInVzZXJfaWQiOjE0fQ.QePLtCWG3JCXYvkXaWFQc9T2vBdhuwsiPBvwOQ3VnIY", "created_at": "2024-01-05T02:15:42.541Z", "expires_at": "2024-01-06T02:15:42Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 11, "fields": {"user": 14, "jti": "d5769646f0a4437284f1220154758e2e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzYwOSwiaWF0IjoxNzA0NDIxMjA5LCJqdGkiOiJkNTc2OTY0NmYwYTQ0MzcyODRmMTIyMDE1NDc1OGUyZSIsInVzZXJfaWQiOjE0fQ.1jriE0ej93Ku3gpNmrzRyWEyHp5zzajjl1u0frrwkNI", "created_at": "2024-01-05T02:20:09.456Z", "expires_at": "2024-01-06T02:20:09Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 12, "fields": {"user": 14, "jti": "1dba02f54c5e4fcc9c2c967eabf196b5", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzg2MCwiaWF0IjoxNzA0NDIxNDYwLCJqdGkiOiIxZGJhMDJmNTRjNWU0ZmNjOWMyYzk2N2VhYmYxOTZiNSIsInVzZXJfaWQiOjE0fQ.pXvo70N1l1ODaDV05NYT4hDrdx27coP6c5dDl6fICsw", "created_at": "2024-01-05T02:24:20.471Z", "expires_at": "2024-01-06T02:24:20Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 13, "fields": {"user": 5, "jti": "88d65f0e7d7048a6aff595f0792ee013", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwNzkxOSwiaWF0IjoxNzA0NDIxNTE5LCJqdGkiOiI4OGQ2NWYwZTdkNzA0OGE2YWZmNTk1ZjA3OTJlZTAxMyIsInVzZXJfaWQiOjV9.wMucvZnYf13si1cjFir6h7ezXXqYzH-u0UgV52Ychn4", "created_at": "2024-01-05T02:25:19.490Z", "expires_at": "2024-01-06T02:25:19Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 14, "fields": {"user": 5, "jti": "e0913e92f0cc4c4f9970aafbb765de97", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwODI2NSwiaWF0IjoxNzA0NDIxODY1LCJqdGkiOiJlMDkxM2U5MmYwY2M0YzRmOTk3MGFhZmJiNzY1ZGU5NyIsInVzZXJfaWQiOjV9.a7jCXCaC1ePYYevdOsfIjPOuVhy9W65pA1rZMD-c-p8", "created_at": "2024-01-05T02:31:05.999Z", "expires_at": "2024-01-06T02:31:05Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 15, "fields": {"user": 14, "jti": "fba4e5f6c66d47fdab529319f831abe6", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUwODMxNywiaWF0IjoxNzA0NDIxOTE3LCJqdGkiOiJmYmE0ZTVmNmM2NmQ0N2ZkYWI1MjkzMTlmODMxYWJlNiIsInVzZXJfaWQiOjE0fQ.OTFpXMHXnwDY8qB_3yxWG1xwAvAQjswE4-ncaew5cZA", "created_at": "2024-01-05T02:31:57.756Z", "expires_at": "2024-01-06T02:31:57Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 16, "fields": {"user": 5, "jti": "2f64d904651749e08c1a2bc07f85ee51", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUxNDM1NywiaWF0IjoxNzA0NDI3OTU3LCJqdGkiOiIyZjY0ZDkwNDY1MTc0OWUwOGMxYTJiYzA3Zjg1ZWU1MSIsInVzZXJfaWQiOjV9.kr3vY8ab6fbRgqg5Mwyqbvj0oKGYPru7OfKkR9JRcHs", "created_at": "2024-01-05T04:12:37.948Z", "expires_at": "2024-01-06T04:12:37Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 17, "fields": {"user": 5, "jti": "5f134c65c43e400aa992b1ff9492b72b", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUxNDM5OSwiaWF0IjoxNzA0NDI3OTk5LCJqdGkiOiI1ZjEzNGM2NWM0M2U0MDBhYTk5MmIxZmY5NDkyYjcyYiIsInVzZXJfaWQiOjV9.Wn9v8NvY50DLlXO2zpABi2sKlEvlmOdSPl0SbWK1pPo", "created_at": "2024-01-05T04:13:19.064Z", "expires_at": "2024-01-06T04:13:19Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 18, "fields": {"user": 14, "jti": "e6b3a52b86954e0896fc8c3384f29b37", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUxNDQ0NiwiaWF0IjoxNzA0NDI4MDQ2LCJqdGkiOiJlNmIzYTUyYjg2OTU0ZTA4OTZmYzhjMzM4NGYyOWIzNyIsInVzZXJfaWQiOjE0fQ.YrWWUbXIESgydIZeg8RfL_8GSVj2QipsxeAXYJrKqoo", "created_at": "2024-01-05T04:14:06.474Z", "expires_at": "2024-01-06T04:14:06Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 19, "fields": {"user": 5, "jti": "1221f8bbba754fda9f9cb6c0ebb2f105", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUxNDUzOCwiaWF0IjoxNzA0NDI4MTM4LCJqdGkiOiIxMjIxZjhiYmJhNzU0ZmRhOWY5Y2I2YzBlYmIyZjEwNSIsInVzZXJfaWQiOjV9.C8taBah937BfJ7HSkEG-wE4eHe1XLqZJU-zw17lgPWE", "created_at": "2024-01-05T04:15:38.401Z", "expires_at": "2024-01-06T04:15:38Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 20, "fields": {"user": 5, "jti": "8d4eae2ba8ad4ff7833bef43d8de52a1", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUyOTAwNywiaWF0IjoxNzA0NDQyNjA3LCJqdGkiOiI4ZDRlYWUyYmE4YWQ0ZmY3ODMzYmVmNDNkOGRlNTJhMSIsInVzZXJfaWQiOjV9.JNup4IOBqUb-pZGQMdbM9cR_0VG39ug4ohNl2g8HFPs", "created_at": "2024-01-05T08:16:47.129Z", "expires_at": "2024-01-06T08:16:47Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 21, "fields": {"user": 14, "jti": "3f51e30919ac440ca581ec2bf7a32bc2", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUyOTIxNCwiaWF0IjoxNzA0NDQyODE0LCJqdGkiOiIzZjUxZTMwOTE5YWM0NDBjYTU4MWVjMmJmN2EzMmJjMiIsInVzZXJfaWQiOjE0fQ.Iya0YMnqv_Uhaa3Fzf_m8PPwPnpxChGIh3Xc_XnzLCk", "created_at": "2024-01-05T08:20:14.603Z", "expires_at": "2024-01-06T08:20:14Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 22, "fields": {"user": 14, "jti": "eecfa23127174b12a4236399fbe92457", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzNzAyOSwiaWF0IjoxNzA0NDUwNjI5LCJqdGkiOiJlZWNmYTIzMTI3MTc0YjEyYTQyMzYzOTlmYmU5MjQ1NyIsInVzZXJfaWQiOjE0fQ.teoQVltWJCVc4SU2V-wypFnxZeUMKJQ0dDUomc33Cus", "created_at": "2024-01-05T10:30:29.882Z", "expires_at": "2024-01-06T10:30:29Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 23, "fields": {"user": 5, "jti": "8af58df9087d468cbcb69400655a8762", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzNzc5MiwiaWF0IjoxNzA0NDUxMzkyLCJqdGkiOiI4YWY1OGRmOTA4N2Q0NjhjYmNiNjk0MDA2NTVhODc2MiIsInVzZXJfaWQiOjV9.BXpZsBiSODntbvhnq29puhDiJ-Bz1EcQczMfbiHJz-Y", "created_at": "2024-01-05T10:43:12.327Z", "expires_at": "2024-01-06T10:43:12Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 24, "fields": {"user": 5, "jti": "c79c47eda902422d8d05f6707f73355e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzNzk0MiwiaWF0IjoxNzA0NDUxNTQyLCJqdGkiOiJjNzljNDdlZGE5MDI0MjJkOGQwNWY2NzA3ZjczMzU1ZSIsInVzZXJfaWQiOjV9.JmvUzaViVce3rTxOFZmTlbi9-QB5blgnDUVgidmZE4Q", "created_at": "2024-01-05T10:45:42.686Z", "expires_at": "2024-01-06T10:45:42Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 25, "fields": {"user": 25, "jti": "71b3ce210ec148c290a22457673b910b", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzODQ5MCwiaWF0IjoxNzA0NDUyMDkwLCJqdGkiOiI3MWIzY2UyMTBlYzE0OGMyOTBhMjI0NTc2NzNiOTEwYiIsInVzZXJfaWQiOjI1fQ.W7jjkNP_Xfl-HF2vuSzTKecXQPqkK9mND2DteNpQP8w", "created_at": "2024-01-05T10:54:50.845Z", "expires_at": "2024-01-06T10:54:50Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 26, "fields": {"user": 5, "jti": "85b0e4109fd84afea135fdee824ed5fb", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzOTE5OCwiaWF0IjoxNzA0NDUyNzk4LCJqdGkiOiI4NWIwZTQxMDlmZDg0YWZlYTEzNWZkZWU4MjRlZDVmYiIsInVzZXJfaWQiOjV9.jvpqgTbfzSOGWYILgdSdKeCNX31plDZ8tx7jjFFPfqE", "created_at": "2024-01-05T11:06:38.376Z", "expires_at": "2024-01-06T11:06:38Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 27, "fields": {"user": 25, "jti": "9d2c109fc8c14ca791f54ebed7d5070b", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzOTQ0MywiaWF0IjoxNzA0NDUzMDQzLCJqdGkiOiI5ZDJjMTA5ZmM4YzE0Y2E3OTFmNTRlYmVkN2Q1MDcwYiIsInVzZXJfaWQiOjI1fQ.NZTqFLtb8T98uDQsT7YSk0x9rKf13q0_FSOYTFPERzk", "created_at": "2024-01-05T11:10:43.360Z", "expires_at": "2024-01-06T11:10:43Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 28, "fields": {"user": 5, "jti": "2c275d64cb054b32b373a49f19cb0607", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzOTUwNSwiaWF0IjoxNzA0NDUzMTA1LCJqdGkiOiIyYzI3NWQ2NGNiMDU0YjMyYjM3M2E0OWYxOWNiMDYwNyIsInVzZXJfaWQiOjV9.C_rVaohBT2riBwIFlVF7eOupSewIicCOOp3W6dWkRfk", "created_at": "2024-01-05T11:11:45.373Z", "expires_at": "2024-01-06T11:11:45Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 29, "fields": {"user": 25, "jti": "f7a5c03bfc924edab1f4f279cddd5cf3", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzOTU3NywiaWF0IjoxNzA0NDUzMTc3LCJqdGkiOiJmN2E1YzAzYmZjOTI0ZWRhYjFmNGYyNzljZGRkNWNmMyIsInVzZXJfaWQiOjI1fQ.znAMmrQz2Pdul2EQtX91PmKWLKUb15ZNoBpG45UTlTc", "created_at": "2024-01-05T11:12:57.272Z", "expires_at": "2024-01-06T11:12:57Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 30, "fields": {"user": 5, "jti": "383a56471fad47d4a6896cbd62f5b3f1", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDUzOTY2NSwiaWF0IjoxNzA0NDUzMjY1LCJqdGkiOiIzODNhNTY0NzFmYWQ0N2Q0YTY4OTZjYmQ2MmY1YjNmMSIsInVzZXJfaWQiOjV9.72t51ttWCoLIo7EpXde8Gnlmu5OIgpIc0w_8pdQIebc", "created_at": "2024-01-05T11:14:25.034Z", "expires_at": "2024-01-06T11:14:25Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 31, "fields": {"user": 26, "jti": "d871fa62404246cf8574c15200dd32d7", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDU0MDI2MywiaWF0IjoxNzA0NDUzODYzLCJqdGkiOiJkODcxZmE2MjQwNDI0NmNmODU3NGMxNTIwMGRkMzJkNyIsInVzZXJfaWQiOjI2fQ.5JGef5hAjn1-_toK2NgGiEkdcgl61R4XZ5xmC7RW9RA", "created_at": "2024-01-05T11:24:23.436Z", "expires_at": "2024-01-06T11:24:23Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 32, "fields": {"user": 26, "jti": "d34e73a92cf94985b976e883a32255c6", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDU0MDQxMSwiaWF0IjoxNzA0NDU0MDExLCJqdGkiOiJkMzRlNzNhOTJjZjk0OTg1Yjk3NmU4ODNhMzIyNTVjNiIsInVzZXJfaWQiOjI2fQ.kHFF4hIvabIZiTtup7J7O5J6CLagBTQZM0agFL34W1Y", "created_at": "2024-01-05T11:26:51.422Z", "expires_at": "2024-01-06T11:26:51Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 33, "fields": {"user": 5, "jti": "e3f65af9793f42958fd42788b646b0fb", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDU0MDQ0MiwiaWF0IjoxNzA0NDU0MDQyLCJqdGkiOiJlM2Y2NWFmOTc5M2Y0Mjk1OGZkNDI3ODhiNjQ2YjBmYiIsInVzZXJfaWQiOjV9.bqL9XV0ShCH5Ik50NqP9HGUcZL5-oLW7kqFCYBWRDv0", "created_at": "2024-01-05T11:27:22.982Z", "expires_at": "2024-01-06T11:27:22Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 34, "fields": {"user": 27, "jti": "62b5934ec49a45f6a6b796e9146dd40e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDU0MTU1NCwiaWF0IjoxNzA0NDU1MTU0LCJqdGkiOiI2MmI1OTM0ZWM0OWE0NWY2YTZiNzk2ZTkxNDZkZDQwZSIsInVzZXJfaWQiOjI3fQ.oQy9sRGxS2R-rpw1JeET9cTYz69nevXw8n64DXQaUV0", "created_at": "2024-01-05T11:45:54.850Z", "expires_at": "2024-01-06T11:45:54Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 35, "fields": {"user": 27, "jti": "773768bb79964ebc942e558c53b7e29f", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDU0MTkwMiwiaWF0IjoxNzA0NDU1NTAyLCJqdGkiOiI3NzM3NjhiYjc5OTY0ZWJjOTQyZTU1OGM1M2I3ZTI5ZiIsInVzZXJfaWQiOjI3fQ.1FcH_ILoa7cX1hAFzccbcFo2DMLgBpQ2OIW-klPLSPk", "created_at": "2024-01-05T11:51:42.327Z", "expires_at": "2024-01-06T11:51:42Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 36, "fields": {"user": 28, "jti": "9a62923c37b44e8da33322e1fb00d9ea", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2NzU4MCwiaWF0IjoxNzA0NjgxMTgwLCJqdGkiOiI5YTYyOTIzYzM3YjQ0ZThkYTMzMzIyZTFmYjAwZDllYSIsInVzZXJfaWQiOjI4fQ.kp6BfprFLOwAW4sbiuRQUFbZEgiJilvXkJbLP-L9Idk", "created_at": "2024-01-08T02:33:00.381Z", "expires_at": "2024-01-09T02:33:00Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 37, "fields": {"user": 29, "jti": "1b716bf7f11d4efda5156e1772569d11", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2ODE4NiwiaWF0IjoxNzA0NjgxNzg2LCJqdGkiOiIxYjcxNmJmN2YxMWQ0ZWZkYTUxNTZlMTc3MjU2OWQxMSIsInVzZXJfaWQiOjI5fQ.Bgk-24VSJztwUR9p6yWnSY5MpnrJGjPi1DCMr1sixDw", "created_at": "2024-01-08T02:43:06.493Z", "expires_at": "2024-01-09T02:43:06Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 38, "fields": {"user": 29, "jti": "83a0598fa52a466fb75c37bfe68e3dbd", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2ODgxMiwiaWF0IjoxNzA0NjgyNDEyLCJqdGkiOiI4M2EwNTk4ZmE1MmE0NjZmYjc1YzM3YmZlNjhlM2RiZCIsInVzZXJfaWQiOjI5fQ.wgxb0IA-N4rYW5ZIci0LhPpA08ttAuOpXFP0u7gCyq4", "created_at": "2024-01-08T02:53:32.876Z", "expires_at": "2024-01-09T02:53:32Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 39, "fields": {"user": 29, "jti": "7560f8aeb04948e5933ba8821e5add8a", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2ODg3OCwiaWF0IjoxNzA0NjgyNDc4LCJqdGkiOiI3NTYwZjhhZWIwNDk0OGU1OTMzYmE4ODIxZTVhZGQ4YSIsInVzZXJfaWQiOjI5fQ.g_YJzKfASHtETvIh3FGdjLkIk51iMoFp8YhjHOeaMBw", "created_at": "2024-01-08T02:54:38.134Z", "expires_at": "2024-01-09T02:54:38Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 40, "fields": {"user": 29, "jti": "c335a97044bf440fb397f06d3aeecb3a", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2ODg5OSwiaWF0IjoxNzA0NjgyNDk5LCJqdGkiOiJjMzM1YTk3MDQ0YmY0NDBmYjM5N2YwNmQzYWVlY2IzYSIsInVzZXJfaWQiOjI5fQ._sG8GevCmbGOPV8hctFrHhIuxmijsvEigdp3KFuj8KA", "created_at": "2024-01-08T02:54:59.413Z", "expires_at": "2024-01-09T02:54:59Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 41, "fields": {"user": 29, "jti": "fbf79eb3bb6a4a43a64110165b314e12", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2ODkxOSwiaWF0IjoxNzA0NjgyNTE5LCJqdGkiOiJmYmY3OWViM2JiNmE0YTQzYTY0MTEwMTY1YjMxNGUxMiIsInVzZXJfaWQiOjI5fQ.JIN2kTbzBNla5zqdvfBf2DwCWUQp50crern0-KuiKWk", "created_at": "2024-01-08T02:55:19.396Z", "expires_at": "2024-01-09T02:55:19Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 42, "fields": {"user": 29, "jti": "ad124bcbadb645e19ac28e0485a30cde", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2OTI0NiwiaWF0IjoxNzA0NjgyODQ2LCJqdGkiOiJhZDEyNGJjYmFkYjY0NWUxOWFjMjhlMDQ4NWEzMGNkZSIsInVzZXJfaWQiOjI5fQ.V9rshCdDlWmErskykkgOhp3V8fKnnU0RMCUZlsmrc9c", "created_at": "2024-01-08T03:00:46.013Z", "expires_at": "2024-01-09T03:00:46Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 43, "fields": {"user": 29, "jti": "aa7544b9e480420ea177b2319778c32e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc2OTU5OSwiaWF0IjoxNzA0NjgzMTk5LCJqdGkiOiJhYTc1NDRiOWU0ODA0MjBlYTE3N2IyMzE5Nzc4YzMyZSIsInVzZXJfaWQiOjI5fQ.S3lGIMwn8uoSl-xy5jSo1F0gGW-9NIDq-2jEy1izLJw", "created_at": "2024-01-08T03:06:39.359Z", "expires_at": "2024-01-09T03:06:39Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 44, "fields": {"user": 29, "jti": "0ba9a9fef0844e94a12cd97c03b653e5", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc3MDIzMywiaWF0IjoxNzA0NjgzODMzLCJqdGkiOiIwYmE5YTlmZWYwODQ0ZTk0YTEyY2Q5N2MwM2I2NTNlNSIsInVzZXJfaWQiOjI5fQ.rHb4UXVOME6ar-jGtVGismyqnDPDW_uyzv5yyTX5_bk", "created_at": "2024-01-08T03:17:13.086Z", "expires_at": "2024-01-09T03:17:13Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 45, "fields": {"user": 28, "jti": "ca8f96bc134c48f9b472acbe2bdaa08b", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc3MjAyNiwiaWF0IjoxNzA0Njg1NjI2LCJqdGkiOiJjYThmOTZiYzEzNGM0OGY5YjQ3MmFjYmUyYmRhYTA4YiIsInVzZXJfaWQiOjI4fQ.yFLzofFTHpWpE_Bmuvl7MlpcsuIzBXbjEIVO6zarHl4", "created_at": "2024-01-08T03:47:06.858Z", "expires_at": "2024-01-09T03:47:06Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 46, "fields": {"user": 28, "jti": "0291d2218f184406ba07b5c8d573312e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc3MjM5NSwiaWF0IjoxNzA0Njg1OTk1LCJqdGkiOiIwMjkxZDIyMThmMTg0NDA2YmEwN2I1YzhkNTczMzEyZSIsInVzZXJfaWQiOjI4fQ.UPjcCrGEZt9bacjYAeUBlugHRBOkNHOxpNgNTGLQsPo", "created_at": "2024-01-08T03:53:15.786Z", "expires_at": "2024-01-09T03:53:15Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 47, "fields": {"user": 28, "jti": "bb6d24bdbe4d42f2ba811d11a551000c", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc3MjY2OCwiaWF0IjoxNzA0Njg2MjY4LCJqdGkiOiJiYjZkMjRiZGJlNGQ0MmYyYmE4MTFkMTFhNTUxMDAwYyIsInVzZXJfaWQiOjI4fQ.O6-8BTK1zIyL7IESGH_aXkNNVMA41GQPZpv82pXrq0Y", "created_at": "2024-01-08T03:57:48.759Z", "expires_at": "2024-01-09T03:57:48Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 48, "fields": {"user": 29, "jti": "97da8cdc638c47a0b50f60a4928caac1", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc4MTIyOCwiaWF0IjoxNzA0Njk0ODI4LCJqdGkiOiI5N2RhOGNkYzYzOGM0N2EwYjUwZjYwYTQ5MjhjYWFjMSIsInVzZXJfaWQiOjI5fQ.anG2Jq4y6FCJlXtmr_vNhkygs3G14ajEPejvh6IaGvE", "created_at": "2024-01-08T06:20:28.996Z", "expires_at": "2024-01-09T06:20:28Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 49, "fields": {"user": 29, "jti": "36b96e7813414d138878bb39cf9dbf5c", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDc4Njg1MiwiaWF0IjoxNzA0NzAwNDUyLCJqdGkiOiIzNmI5NmU3ODEzNDE0ZDEzODg3OGJiMzljZjlkYmY1YyIsInVzZXJfaWQiOjI5fQ.sJML_fCTQKdh_C2JMb4fKUUJuWqoOPVYHmPK7O-_fG4", "created_at": "2024-01-08T07:54:12.945Z", "expires_at": "2024-01-09T07:54:12Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 50, "fields": {"user": 28, "jti": "df4eff50e908404491875c0ab862316c", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDg1NTc0NSwiaWF0IjoxNzA0NzY5MzQ1LCJqdGkiOiJkZjRlZmY1MGU5MDg0MDQ0OTE4NzVjMGFiODYyMzE2YyIsInVzZXJfaWQiOjI4fQ.owHQYkdXQ5gymsBxAIhPkKldaV84jrrdMIcXOcVS2gs", "created_at": "2024-01-09T03:02:25.282Z", "expires_at": "2024-01-10T03:02:25Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 51, "fields": {"user": 29, "jti": "8b14fc3bedc341758aff365104577aac", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDg1NTc4OSwiaWF0IjoxNzA0NzY5Mzg5LCJqdGkiOiI4YjE0ZmMzYmVkYzM0MTc1OGFmZjM2NTEwNDU3N2FhYyIsInVzZXJfaWQiOjI5fQ.ZpgFwxh65DWTk8l8uswp3Enbqzq9VAOtBqU2L7a_ScM", "created_at": "2024-01-09T03:03:09.359Z", "expires_at": "2024-01-10T03:03:09Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 52, "fields": {"user": 29, "jti": "0b084ced46a24e9d94733a0ad4e09d8e", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDk2MDAzOCwiaWF0IjoxNzA0ODczNjM4LCJqdGkiOiIwYjA4NGNlZDQ2YTI0ZTlkOTQ3MzNhMGFkNGUwOWQ4ZSIsInVzZXJfaWQiOjI5fQ.x3Wv3SR4HRqagZT-UuakYS70HNHn2dDRt5njM-X-PnM", "created_at": "2024-01-10T08:00:38.466Z", "expires_at": "2024-01-11T08:00:38Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 53, "fields": {"user": 29, "jti": "8eedc8b0927c4626a759816f88611ce7", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDk2MDg3MSwiaWF0IjoxNzA0ODc0NDcxLCJqdGkiOiI4ZWVkYzhiMDkyN2M0NjI2YTc1OTgxNmY4ODYxMWNlNyIsInVzZXJfaWQiOjI5fQ.5xSksmet5N-l11ZfG1aEm_62LpdR3Lr5-E_C8hv1mCA", "created_at": "2024-01-10T08:14:31.939Z", "expires_at": "2024-01-11T08:14:31Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 54, "fields": {"user": 29, "jti": "27a429f138714dd3acbf2418ce65cc8a", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDk2MTI0MywiaWF0IjoxNzA0ODc0ODQzLCJqdGkiOiIyN2E0MjlmMTM4NzE0ZGQzYWNiZjI0MThjZTY1Y2M4YSIsInVzZXJfaWQiOjI5fQ.UIDTHJfoif7rvt9mP2mEQcU0ALa31avoRo0SdPVOCro", "created_at": "2024-01-10T08:20:43.548Z", "expires_at": "2024-01-11T08:20:43Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 55, "fields": {"user": 29, "jti": "d46aee567cdd4077912d8617d453ed2f", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDk2MTYxNSwiaWF0IjoxNzA0ODc1MjE1LCJqdGkiOiJkNDZhZWU1NjdjZGQ0MDc3OTEyZDg2MTdkNDUzZWQyZiIsInVzZXJfaWQiOjI5fQ.wJk_WQ6Wj6uc2nQh1DwR8B0fYcWophk5JdskY1nPcag", "created_at": "2024-01-10T08:26:55.015Z", "expires_at": "2024-01-11T08:26:55Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 56, "fields": {"user": 29, "jti": "6c6052f8eb4e43bf93f06859fab7d239", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNDk2MjEyMCwiaWF0IjoxNzA0ODc1NzIwLCJqdGkiOiI2YzYwNTJmOGViNGU0M2JmOTNmMDY4NTlmYWI3ZDIzOSIsInVzZXJfaWQiOjI5fQ.Wgi3oDBH2HnuZY4jICopNcuXZuR4mQGJbJuHoUOGNUk", "created_at": "2024-01-10T08:35:20.041Z", "expires_at": "2024-01-11T08:35:20Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 57, "fields": {"user": 28, "jti": "a7fa0eb121d44018b63477a06172bf33", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNDk1NywiaWF0IjoxNzA1MDI4NTU3LCJqdGkiOiJhN2ZhMGViMTIxZDQ0MDE4YjYzNDc3YTA2MTcyYmYzMyIsInVzZXJfaWQiOjI4fQ.2yNMrUme6kvE-IgwK1aXVhxmUF4SmKHOneYKtL5zkTo", "created_at": "2024-01-12T03:02:37.700Z", "expires_at": "2024-01-13T03:02:37Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 58, "fields": {"user": 28, "jti": "682f96a5053d470f97ae95fd3b4aa0cc", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNTA1MSwiaWF0IjoxNzA1MDI4NjUxLCJqdGkiOiI2ODJmOTZhNTA1M2Q0NzBmOTdhZTk1ZmQzYjRhYTBjYyIsInVzZXJfaWQiOjI4fQ.iPuZsCP2dVvJFnXxL_CtmXgJt8pzwuY6fbMgNFbKMto", "created_at": "2024-01-12T03:04:11.031Z", "expires_at": "2024-01-13T03:04:11Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 59, "fields": {"user": 28, "jti": "6d803a1535e944cab676c31714621662", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNTI3MiwiaWF0IjoxNzA1MDI4ODcyLCJqdGkiOiI2ZDgwM2ExNTM1ZTk0NGNhYjY3NmMzMTcxNDYyMTY2MiIsInVzZXJfaWQiOjI4fQ.VP5ZZ3QRnLcy25mYZ2SPl_iPRsbLWmc8qN4BXOfh6O8", "created_at": "2024-01-12T03:07:52.259Z", "expires_at": "2024-01-13T03:07:52Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 60, "fields": {"user": 28, "jti": "ed52079f345c416294e14955e9173b23", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNTM2OSwiaWF0IjoxNzA1MDI4OTY5LCJqdGkiOiJlZDUyMDc5ZjM0NWM0MTYyOTRlMTQ5NTVlOTE3M2IyMyIsInVzZXJfaWQiOjI4fQ.WKUlwyDkiqyATbMNT7KzEqgV7j90ib9l3aL_LRObnzo", "created_at": "2024-01-12T03:09:29.369Z", "expires_at": "2024-01-13T03:09:29Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 61, "fields": {"user": 28, "jti": "d6cfa181abab438c9cd230c26ca67866", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNTQ3MCwiaWF0IjoxNzA1MDI5MDcwLCJqdGkiOiJkNmNmYTE4MWFiYWI0MzhjOWNkMjMwYzI2Y2E2Nzg2NiIsInVzZXJfaWQiOjI4fQ.Ua7RWwaBaiXG6dRPMbFCJaymBmuAAJu1aX-qb6vcPmE", "created_at": "2024-01-12T03:11:10.968Z", "expires_at": "2024-01-13T03:11:10Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 62, "fields": {"user": 28, "jti": "9e35d3b4d4884d068ccd90e54b6bd195", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNTg3NywiaWF0IjoxNzA1MDI5NDc3LCJqdGkiOiI5ZTM1ZDNiNGQ0ODg0ZDA2OGNjZDkwZTU0YjZiZDE5NSIsInVzZXJfaWQiOjI4fQ.EebtzRMebVxkz9IvcNacRJjcSl8ooe5L2CITidLrMdY", "created_at": "2024-01-12T03:17:57.006Z", "expires_at": "2024-01-13T03:17:57Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 63, "fields": {"user": 28, "jti": "ae31f77414f54f8eb952b26867595ef0", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNjIwNSwiaWF0IjoxNzA1MDI5ODA1LCJqdGkiOiJhZTMxZjc3NDE0ZjU0ZjhlYjk1MmIyNjg2NzU5NWVmMCIsInVzZXJfaWQiOjI4fQ.D1ZW4T-7F2K1_haeT2RwwWuuqzHlBYQx3nMrpcagjeY", "created_at": "2024-01-12T03:23:25.210Z", "expires_at": "2024-01-13T03:23:25Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 64, "fields": {"user": 28, "jti": "e5f8bdd0796e4faeab35ef1ae4aacf7f", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNjU0NSwiaWF0IjoxNzA1MDMwMTQ1LCJqdGkiOiJlNWY4YmRkMDc5NmU0ZmFlYWIzNWVmMWFlNGFhY2Y3ZiIsInVzZXJfaWQiOjI4fQ.vQYAZj-_EmxjJfcTrytxP8Q9FFxDupU7BT4ls5cWHBk", "created_at": "2024-01-12T03:29:05.866Z", "expires_at": "2024-01-13T03:29:05Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 65, "fields": {"user": 28, "jti": "d751726d729b41b49724c206db3099f4", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNjk1MiwiaWF0IjoxNzA1MDMwNTUyLCJqdGkiOiJkNzUxNzI2ZDcyOWI0MWI0OTcyNGMyMDZkYjMwOTlmNCIsInVzZXJfaWQiOjI4fQ.R26U0AGYKsOsq8quzjrsh4Rk9OzewMr2IHXqkhyU_0g", "created_at": "2024-01-12T03:35:52.130Z", "expires_at": "2024-01-13T03:35:52Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 66, "fields": {"user": 29, "jti": "b9784a09a9f945cc83c52f571f2628cf", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNzEwMiwiaWF0IjoxNzA1MDMwNzAyLCJqdGkiOiJiOTc4NGEwOWE5Zjk0NWNjODNjNTJmNTcxZjI2MjhjZiIsInVzZXJfaWQiOjI5fQ.BeCIlpcXryFNZe04Hl0EQrkJAwkqcewEP4wiIzz7bwk", "created_at": "2024-01-12T03:38:22.070Z", "expires_at": "2024-01-13T03:38:22Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 67, "fields": {"user": 28, "jti": "9e85833ba0064daf845b47e79ab76d3a", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNzI2OSwiaWF0IjoxNzA1MDMwODY5LCJqdGkiOiI5ZTg1ODMzYmEwMDY0ZGFmODQ1YjQ3ZTc5YWI3NmQzYSIsInVzZXJfaWQiOjI4fQ.F3FJ8p1WTf7pX0TrV5XxL7i1GxOemm3UH6R_5yITwrg", "created_at": "2024-01-12T03:41:09.534Z", "expires_at": "2024-01-13T03:41:09Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 68, "fields": {"user": 28, "jti": "4af041a9b99c473aad1fdf90bf277fde", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNzQ3NSwiaWF0IjoxNzA1MDMxMDc1LCJqdGkiOiI0YWYwNDFhOWI5OWM0NzNhYWQxZmRmOTBiZjI3N2ZkZSIsInVzZXJfaWQiOjI4fQ.7kHsesr7MUJ13faJ-Y8UFaBnHebMs2Igff_x8OHxM_8", "created_at": "2024-01-12T03:44:35.011Z", "expires_at": "2024-01-13T03:44:35Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 69, "fields": {"user": 28, "jti": "8fee00b8241d4ebea19c0ecf17aac03d", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExNzU5MCwiaWF0IjoxNzA1MDMxMTkwLCJqdGkiOiI4ZmVlMDBiODI0MWQ0ZWJlYTE5YzBlY2YxN2FhYzAzZCIsInVzZXJfaWQiOjI4fQ.p8ZDa9cS4AfU-EM7ROocvPNyxXrLvJ6Aqx7NHKdDGaQ", "created_at": "2024-01-12T03:46:30.116Z", "expires_at": "2024-01-13T03:46:30Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 70, "fields": {"user": 28, "jti": "6528e81ad78f4cf3b9c4cd5099a70425", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExODA4MCwiaWF0IjoxNzA1MDMxNjgwLCJqdGkiOiI2NTI4ZTgxYWQ3OGY0Y2YzYjljNGNkNTA5OWE3MDQyNSIsInVzZXJfaWQiOjI4fQ.4OgnXUc2m8w6GzesS9kZYYZLaiHD4BYe0GOfcwQmhxg", "created_at": "2024-01-12T03:54:40.397Z", "expires_at": "2024-01-13T03:54:40Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 71, "fields": {"user": 29, "jti": "f8934b8b3bd146eea04f49a44af4e785", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExODM4MywiaWF0IjoxNzA1MDMxOTgzLCJqdGkiOiJmODkzNGI4YjNiZDE0NmVlYTA0ZjQ5YTQ0YWY0ZTc4NSIsInVzZXJfaWQiOjI5fQ.Prou-C84CLG5juf6aS3MsrkoJBtmMfrdeSqKg3Lny5w", "created_at": "2024-01-12T03:59:43.530Z", "expires_at": "2024-01-13T03:59:43Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 72, "fields": {"user": 28, "jti": "c004b5e7188646fc8a33cf76c668b922", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExODQ4OCwiaWF0IjoxNzA1MDMyMDg4LCJqdGkiOiJjMDA0YjVlNzE4ODY0NmZjOGEzM2NmNzZjNjY4YjkyMiIsInVzZXJfaWQiOjI4fQ.3Rcx8AEUXtasgFvexqFokc6jwzFZ1WVhAbxw6fSr4Og", "created_at": "2024-01-12T04:01:28.619Z", "expires_at": "2024-01-13T04:01:28Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 73, "fields": {"user": 29, "jti": "1778d32d47d14a698efc018002751f41", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExODk4NSwiaWF0IjoxNzA1MDMyNTg1LCJqdGkiOiIxNzc4ZDMyZDQ3ZDE0YTY5OGVmYzAxODAwMjc1MWY0MSIsInVzZXJfaWQiOjI5fQ.q4kUrm-GxNu8keVUs_pMqOSef336kz9pN0ctOXMAbxk", "created_at": "2024-01-12T04:09:45.083Z", "expires_at": "2024-01-13T04:09:45Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 74, "fields": {"user": 28, "jti": "771248bda14a487fbe2fe44705e81797", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTExOTU4MiwiaWF0IjoxNzA1MDMzMTgyLCJqdGkiOiI3NzEyNDhiZGExNGE0ODdmYmUyZmU0NDcwNWU4MTc5NyIsInVzZXJfaWQiOjI4fQ.Qt3xXHbf2eQphUf5UjDqo85MC2sihsy8ZosBI892rv8", "created_at": "2024-01-12T04:19:42.856Z", "expires_at": "2024-01-13T04:19:42Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 75, "fields": {"user": 29, "jti": "e39f0feaa17841f7bb930aebc1680cf8", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTEyOTA4MCwiaWF0IjoxNzA1MDQyNjgwLCJqdGkiOiJlMzlmMGZlYWExNzg0MWY3YmI5MzBhZWJjMTY4MGNmOCIsInVzZXJfaWQiOjI5fQ.QLpKiSryn6_vJXdoGvYDFztI1gOMfC2hi546iw2i4sI", "created_at": "2024-01-12T06:58:00.861Z", "expires_at": "2024-01-13T06:58:00Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 76, "fields": {"user": 28, "jti": "bbd2cadc94ee4b99a26d3a8aede30436", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTEzMzI0NSwiaWF0IjoxNzA1MDQ2ODQ1LCJqdGkiOiJiYmQyY2FkYzk0ZWU0Yjk5YTI2ZDNhOGFlZGUzMDQzNiIsInVzZXJfaWQiOjI4fQ.p12WfQ-PhZLftZhuxxGKqiL-Ko8t7XdPn5DNh--msWY", "created_at": "2024-01-12T08:07:25.837Z", "expires_at": "2024-01-13T08:07:25Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 77, "fields": {"user": 28, "jti": "b7f224f7cd9142b4b6276d0d981bf795", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTEzMzU4NiwiaWF0IjoxNzA1MDQ3MTg2LCJqdGkiOiJiN2YyMjRmN2NkOTE0MmI0YjYyNzZkMGQ5ODFiZjc5NSIsInVzZXJfaWQiOjI4fQ.4aeMY4loDEEs0A9_hhXKWPaWf7sjSBrFJ2luGpHaDfw", "created_at": "2024-01-12T08:13:06.518Z", "expires_at": "2024-01-13T08:13:06Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 78, "fields": {"user": 28, "jti": "2ee01eed854f46d29bc251417da979b7", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTE0MDE2MSwiaWF0IjoxNzA1MDUzNzYxLCJqdGkiOiIyZWUwMWVlZDg1NGY0NmQyOWJjMjUxNDE3ZGE5NzliNyIsInVzZXJfaWQiOjI4fQ.YNStb-NWQ_XlkGn9xZGX1Pz5UcsBfbH_Y9ato2Qwk90", "created_at": "2024-01-12T10:02:41.448Z", "expires_at": "2024-01-13T10:02:41Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 79, "fields": {"user": 28, "jti": "74bd723cf4df4c029e83030c1312d4d2", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTE0MTk4OCwiaWF0IjoxNzA1MDU1NTg4LCJqdGkiOiI3NGJkNzIzY2Y0ZGY0YzAyOWU4MzAzMGMxMzEyZDRkMiIsInVzZXJfaWQiOjI4fQ.r7LCPnGbmBqpNRIw3CmqbvGwZD-U77fzCgpzu8xAcB8", "created_at": "2024-01-12T10:33:08.423Z", "expires_at": "2024-01-13T10:33:08Z"}}, {"model": "token_blacklist.outstandingtoken", "pk": 80, "fields": {"user": 29, "jti": "d7f9467c8cfe4d1896783db96ff05e4f", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNTE0MzEyMCwiaWF0IjoxNzA1MDU2NzIwLCJqdGkiOiJkN2Y5NDY3YzhjZmU0ZDE4OTY3ODNkYjk2ZmYwNWU0ZiIsInVzZXJfaWQiOjI5fQ.uhVaTeA9T2AcES_auqou4tNwWmprUwhIRw9cu3ojjTU", "created_at": "2024-01-12T10:52:00.766Z", "expires_at": "2024-01-13T10:52:00Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 1, "fields": {"token": 1, "blacklisted_at": "2024-01-04T08:30:12.977Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 2, "fields": {"token": 9, "blacklisted_at": "2024-01-05T02:15:26.756Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 3, "fields": {"token": 13, "blacklisted_at": "2024-01-05T02:27:07.233Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 4, "fields": {"token": 15, "blacklisted_at": "2024-01-05T02:32:36.211Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 5, "fields": {"token": 16, "blacklisted_at": "2024-01-05T04:15:27.871Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 6, "fields": {"token": 19, "blacklisted_at": "2024-01-05T04:16:41.497Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 7, "fields": {"token": 35, "blacklisted_at": "2024-01-05T11:52:25.322Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 8, "fields": {"token": 36, "blacklisted_at": "2024-01-08T02:34:26.343Z"}}, {"model": "token_blacklist.blacklistedtoken", "pk": 9, "fields": {"token": 39, "blacklisted_at": "2024-01-08T02:54:53.970Z"}}]
\ No newline at end of file
No preview for this file type
...@@ -10,6 +10,7 @@ For the full list of settings and their values, see ...@@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/ https://docs.djangoproject.com/en/4.2/ref/settings/
""" """
from datetime import timedelta
import os import os
from pathlib import Path from pathlib import Path
...@@ -26,7 +27,7 @@ SECRET_KEY = 'django-insecure-suaet%v3@p8i7&8z29^n0vq9tc=+qb@$azkes2fs^q3o#6y_&q ...@@ -26,7 +27,7 @@ SECRET_KEY = 'django-insecure-suaet%v3@p8i7&8z29^n0vq9tc=+qb@$azkes2fs^q3o#6y_&q
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ['10.0.2.2', '127.0.0.1']
# Application definition # Application definition
...@@ -41,6 +42,11 @@ INSTALLED_APPS = [ ...@@ -41,6 +42,11 @@ INSTALLED_APPS = [
'library', 'library',
'api', 'api',
'rest_framework', 'rest_framework',
'rest_framework.authtoken',
'phonenumber_field',
'rest_framework_simplejwt',
'rest_framework_simplejwt.token_blacklist',
'corsheaders',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
...@@ -51,6 +57,8 @@ MIDDLEWARE = [ ...@@ -51,6 +57,8 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'library.middleware.UserTypeMiddleware',
'corsheaders.middleware.CorsMiddleware',
] ]
ROOT_URLCONF = 'djangoproj.urls' ROOT_URLCONF = 'djangoproj.urls'
...@@ -64,6 +72,7 @@ TEMPLATES = [ ...@@ -64,6 +72,7 @@ TEMPLATES = [
'context_processors': [ 'context_processors': [
'django.template.context_processors.debug', 'django.template.context_processors.debug',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.template.context_processors.media',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
], ],
...@@ -120,9 +129,13 @@ USE_TZ = True ...@@ -120,9 +129,13 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.2/howto/static-files/ # https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/' STATIC_URL = 'static/'
STATICFILES_DIRS = [ # STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static') # os.path.join(BASE_DIR, 'static')
] # ]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
...@@ -134,5 +147,22 @@ LOGIN_URL='/login' ...@@ -134,5 +147,22 @@ LOGIN_URL='/login'
REST_FRAMEWORK = { REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 5 'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}
AUTH_USER_MODEL = 'library.CustomUser'
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=1),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
} }
\ No newline at end of file
...@@ -16,9 +16,14 @@ Including another URLconf ...@@ -16,9 +16,14 @@ Including another URLconf
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', include("library.urls")), path('', include("library.urls")),
path('api/', include('api.urls')), path('api/', include('api.urls')),
path('api-auth/', include('api.urls')),
] ]
from django.contrib import admin from django.contrib import admin
from .models import Book, Member, BookLoan, Librarian, LoginHistory from .models import Book, Member, BookLoan, Librarian, LoginHistory, CustomUser
# class PustakawanAdmin(admin.ModelAdmin):
# list_display = ('user',)
admin.site.register(Book) admin.site.register(Book)
admin.site.register(Member) admin.site.register(Member)
admin.site.register(BookLoan) admin.site.register(BookLoan)
admin.site.register(Librarian) admin.site.register(Librarian)
admin.site.register(LoginHistory) admin.site.register(LoginHistory)
admin.site.register(CustomUser)
\ No newline at end of file
from functools import wraps
from django.shortcuts import redirect
def librarian_required(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
# Gantilah dengan mekanisme otentikasi sesuai kebutuhan Anda
if request.user.is_authenticated and request.user.is_librarian == True:
return view_func(request, *args, **kwargs)
else:
return redirect('unauthorized')
return _wrapped_view
\ No newline at end of file
from imaplib import _Authenticator from imaplib import _Authenticator
from django import forms from django import forms
from .models import Book, Category, Member, BookLoan, Librarian from .models import *
from django.contrib.auth.forms import UserCreationForm, UserChangeForm from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm
from django.contrib.auth.models import User from django.contrib.auth.models import AbstractUser
from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.widgets import PhoneNumberPrefixWidget
class LoginForm(forms.Form): class CustomAuthenticationForm(AuthenticationForm):
username = forms.CharField(max_length=50) class Meta:
password = forms.CharField(widget=forms.PasswordInput) model = CustomUser
fields = ['username', 'password']
# class RegistrationForm(UserCreationForm):
# email = forms.EmailField(required=True)
# class Meta:
# model = User
# fields = ['username', 'email', 'password1', 'password2']
# def clean_email(self):
# email = self.cleaned_data['email']
# if User.objects.filter(email=email).exists():
# raise forms.ValidationError("Email is already in use.")
# return email
# def clean(self): class LibrarianRegistrationForm(UserCreationForm):
# cleaned_data = super().clean() class Meta:
# password1 = cleaned_data.get('password1') model = CustomUser
# password2 = cleaned_data.get('password2') fields = UserCreationForm.Meta.fields + ('email', 'is_librarian',)
# if password1 and password2 and password1 != password2: class MemberRegistrationForm(UserCreationForm):
# raise forms.ValidationError('Passwords do not match') class Meta:
model = CustomUser
fields = UserCreationForm.Meta.fields + ('email',)
# return cleaned_data
# class UserCreationForm(UserCreationForm): class BookForm(forms.ModelForm):
# class Meta: class Meta:
# model = User model = Book
# fields = UserCreationForm.Meta.fields + 'email' fields = '__all__'
class userCreat(UserCreationForm): class MemberForm(forms.ModelForm):
phone_number = PhoneNumberField(
widget=PhoneNumberPrefixWidget(attrs={'class': 'form-control'})
)
class Meta: class Meta:
model = User model = Member
fields = ['username', 'email', 'password1', 'password2'] fields = '__all__'
class LibrarianForm(forms.ModelForm): class LibrarianForm(forms.ModelForm):
phone_number = PhoneNumberField(
widget=PhoneNumberPrefixWidget(attrs={'class': 'form-control'})
)
class Meta: class Meta:
model = Librarian model = Librarian
fields = ['name'] fields = ['name', 'last_name', 'address', 'birth_place', 'date_birth', 'phone_number']
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.fields.update(UserCreationForm.base_fields)
# def is_valid(self):
# return super().is_valid() and UserCreationForm(self.cleaned_data).is_valid()
# def save(self, commit=True):
# user = UserCreationForm(self.cleaned_data).save(commit=False)
# user.save()
# librarian = super().save(commit=False)
# librarian.user = user
# if commit:
# librarian.save()
# return librarian
class LibrarianUpdateForm(UserChangeForm):
name = forms.CharField(max_length=100)
class MemberProfileUpdateForm(forms.ModelForm):
class Meta: class Meta:
model = User model = Member
fields = ['username', 'email', 'name'] fields = ['name', 'email', 'address', 'birth_place', 'date_birth', 'phone_number']
class BookForm(forms.ModelForm): class LibrarianProfileUpdateForm(forms.ModelForm):
class Meta: class Meta:
model = Book model = Librarian
fields = ['title', 'author', 'publisher', 'isbn'] fields = ['name', 'last_name', 'address', 'birth_place', 'date_birth', 'phone_number']
class MemberForm(forms.ModelForm):
class Meta:
model = Member
fields = ['name', 'address', 'email', 'phone_number']
class BookLoanForm(forms.ModelForm): class BookLoanForm(forms.ModelForm):
book = forms.ModelChoiceField(queryset=Book.objects.all(), label='Book') book = forms.ModelChoiceField(queryset=Book.objects.all(), label='Book')
......
# middleware.py
from django.utils.functional import SimpleLazyObject
from .models import CustomUser # Gantilah dengan model pengguna yang sesuai
def get_user_type(request):
if hasattr(request, '_cached_user_type'):
return request._cached_user_type
user_type = 'member' # Default ke anggota
if request.user.is_authenticated:
user_type = 'librarian' if request.user.is_librarian else 'member'
request._cached_user_type = user_type
return user_type
class UserTypeMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.user_type = SimpleLazyObject(lambda: get_user_type(request))
response = self.get_response(request)
return response
# Generated by Django 4.2.8 on 2023-12-19 07:31 # Generated by Django 4.2.8 on 2024-01-03 03:31
from django.conf import settings
import django.contrib.auth.models
import django.contrib.auth.validators
import django.core.validators
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration): class Migration(migrations.Migration):
...@@ -9,9 +14,36 @@ class Migration(migrations.Migration): ...@@ -9,9 +14,36 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
] ]
operations = [ operations = [
migrations.CreateModel(
name='CustomUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel( migrations.CreateModel(
name='Book', name='Book',
fields=[ fields=[
...@@ -19,17 +51,15 @@ class Migration(migrations.Migration): ...@@ -19,17 +51,15 @@ class Migration(migrations.Migration):
('title', models.CharField(max_length=100)), ('title', models.CharField(max_length=100)),
('author', models.CharField(max_length=100)), ('author', models.CharField(max_length=100)),
('publisher', models.CharField(max_length=100)), ('publisher', models.CharField(max_length=100)),
('date_publish', models.IntegerField(null=True)),
('isbn', models.CharField(max_length=13, unique=True)), ('isbn', models.CharField(max_length=13, unique=True)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Librarian', name='Category',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)), ('name', models.CharField(max_length=255)),
('username', models.CharField(max_length=50, unique=True)),
('password', models.CharField(max_length=100)),
('email', models.EmailField(max_length=254, unique=True)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
...@@ -39,16 +69,30 @@ class Migration(migrations.Migration): ...@@ -39,16 +69,30 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=100)), ('name', models.CharField(max_length=100)),
('address', models.TextField()), ('address', models.TextField()),
('email', models.EmailField(max_length=254, unique=True)), ('email', models.EmailField(max_length=254, unique=True)),
('phone_number', models.CharField(max_length=15)), ('birth_place', models.CharField(max_length=50, null=True)),
('date_birth', models.DateField(null=True)),
('phone_number', models.CharField(blank=True, max_length=17, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.", regex='^\\+?1?\\d{9,15}$')])),
('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='LoginHistory', name='LoginHistory',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('login_time', models.DateTimeField()), ('login_time', models.DateTimeField(default=django.utils.timezone.now)),
('logout_time', models.DateTimeField(blank=True, null=True)), ('librarian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('librarian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.librarian')), ],
),
migrations.CreateModel(
name='Librarian',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('address', models.TextField(null=True)),
('last_name', models.CharField(max_length=100, null=True)),
('birth_place', models.CharField(max_length=50, null=True)),
('date_birth', models.DateField(null=True)),
('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
...@@ -63,4 +107,9 @@ class Migration(migrations.Migration): ...@@ -63,4 +107,9 @@ class Migration(migrations.Migration):
('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.member')), ('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.member')),
], ],
), ),
migrations.AddField(
model_name='book',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.category'),
),
] ]
# Generated by Django 4.2.8 on 2024-01-03 07:03
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='librarian',
name='phone_number',
field=models.CharField(blank=True, max_length=17, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.", regex='^\\+?1?\\d{9,15}$')]),
),
]
# Generated by Django 4.2.8 on 2023-12-20 02:43
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('library', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='librarian',
name='email',
),
migrations.RemoveField(
model_name='librarian',
name='password',
),
migrations.RemoveField(
model_name='librarian',
name='username',
),
migrations.AddField(
model_name='librarian',
name='user',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]
# Generated by Django 4.2.8 on 2023-12-22 06:08 # Generated by Django 4.2.8 on 2024-01-03 08:08
from django.db import migrations, models from django.db import migrations, models
...@@ -6,18 +6,18 @@ from django.db import migrations, models ...@@ -6,18 +6,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('library', '0003_remove_loginhistory_logout_time_and_more'), ('library', '0002_librarian_phone_number'),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='bookloan', model_name='customuser',
name='is_late', name='is_librarian',
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
migrations.AddField( migrations.AddField(
model_name='bookloan', model_name='customuser',
name='late_fee', name='is_member',
field=models.IntegerField(default=0), field=models.BooleanField(default=False),
), ),
] ]
# Generated by Django 4.2.8 on 2023-12-20 04:19
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('library', '0002_remove_librarian_email_remove_librarian_password_and_more'),
]
operations = [
migrations.RemoveField(
model_name='loginhistory',
name='logout_time',
),
migrations.AlterField(
model_name='loginhistory',
name='librarian',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='loginhistory',
name='login_time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]
# Generated by Django 4.2.8 on 2023-12-28 06:52 # Generated by Django 4.2.8 on 2024-01-04 06:40
from django.db import migrations, models from django.db import migrations, models
...@@ -6,13 +6,13 @@ from django.db import migrations, models ...@@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('library', '0008_book_category'), ('library', '0003_customuser_is_librarian_customuser_is_member'),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='book', model_name='book',
name='date_publish', name='image',
field=models.DateField(null=True), field=models.ImageField(blank=True, null=True, upload_to='book_images/'),
), ),
] ]
# Generated by Django 4.2.8 on 2023-12-28 03:23 # Generated by Django 4.2.8 on 2024-01-04 06:41
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('library', '0007_category'), ('library', '0004_book_image'),
] ]
operations = [ operations = [
migrations.AddField( migrations.AlterField(
model_name='book', model_name='book',
name='category', name='image',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='library.category'), field=models.ImageField(null=True, upload_to='book_images/'),
preserve_default=False,
), ),
] ]
# Generated by Django 4.2.8 on 2023-12-22 06:28
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('library', '0004_bookloan_is_late_bookloan_late_fee'),
]
operations = [
migrations.RemoveField(
model_name='bookloan',
name='is_late',
),
]
# Generated by Django 4.2.8 on 2024-01-08 06:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0005_alter_book_image'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='is_member',
field=models.BooleanField(default=True),
),
]
# Generated by Django 4.2.8 on 2023-12-22 06:32
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('library', '0005_remove_bookloan_is_late'),
]
operations = [
migrations.RemoveField(
model_name='bookloan',
name='late_fee',
),
]
# Generated by Django 4.2.8 on 2023-12-27 10:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0006_remove_bookloan_late_fee'),
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
],
),
]
from django.shortcuts import redirect
class LibrarianRequiredMixin:
def dispatch(self, request, *args, **kwargs):
# Gantilah dengan mekanisme otentikasi sesuai kebutuhan Anda
if request.user.is_authenticated and request.user.is_librarian == True:
return super().dispatch(request, *args, **kwargs)
else:
return redirect('unauthorized')
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import AbstractUser, Group, Permission
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.signals import user_logged_in from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver from django.dispatch import receiver
import phonenumbers
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from phonenumbers import PhoneNumberFormat
# Create your models here. # Create your models here.
class CustomUser(AbstractUser):
is_member = models.BooleanField(default=True)
is_librarian = models.BooleanField(default=False)
class Category(models.Model): class Category(models.Model):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
...@@ -18,17 +25,39 @@ class Book(models.Model): ...@@ -18,17 +25,39 @@ class Book(models.Model):
author = models.CharField(max_length=100) author = models.CharField(max_length=100)
publisher = models.CharField(max_length=100) publisher = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE)
date_publish = models.DateField(null=True) date_publish = models.IntegerField(null=True)
image = models.ImageField(upload_to='book_images/', null=True)
isbn = models.CharField(max_length=13, unique=True) isbn = models.CharField(max_length=13, unique=True)
def is_available(self):
return not self.bookloan_set.filter(is_returned=False).exists()
def __str__(self): def __str__(self):
return self.title return self.title
class Member(models.Model): class Member(models.Model):
user = models.OneToOneField(CustomUser, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
address = models.TextField() address = models.TextField()
email = models.EmailField(unique=True) email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=15) birth_place = models.CharField(max_length=50, null=True)
date_birth = models.DateField(null=True)
phone_regex = RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed."
)
phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True)
def clean(self):
super().clean()
try:
parsed_number = phonenumbers.parse(self.phone_number, None)
if not phonenumbers.is_valid_number(parsed_number):
raise ValidationError("Invalid phone number.")
self.phone_number = phonenumbers.format_number(parsed_number, PhoneNumberFormat.E164)
except phonenumbers.NumberParseException:
raise ValidationError("Error parsing phone number.")
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -45,18 +74,48 @@ class BookLoan(models.Model): ...@@ -45,18 +74,48 @@ class BookLoan(models.Model):
return f"{self.book.title} - {self.member.name}" return f"{self.book.title} - {self.member.name}"
class Librarian(models.Model): class Librarian(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE) user = models.OneToOneField(CustomUser, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
address = models.TextField(null=True)
last_name = models.CharField(max_length=100, null=True)
birth_place = models.CharField(max_length=50, null=True)
date_birth = models.DateField(null=True)
phone_regex = RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed."
)
phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True)
def clean(self):
super().clean()
try:
parsed_number = phonenumbers.parse(self.phone_number, None)
if not phonenumbers.is_valid_number(parsed_number):
raise ValidationError("Invalid phone number.")
self.phone_number = phonenumbers.format_number(parsed_number, PhoneNumberFormat.E164)
except phonenumbers.NumberParseException:
raise ValidationError("Error parsing phone number.")
def __str__(self): def __str__(self):
return self.name return self.name
@receiver(user_logged_in, sender=User) @receiver(user_logged_in, sender=CustomUser)
def create_librarian_login_history(sender, user, **kwargs): def create_librarian_login_history(sender, user, **kwargs):
LoginHistory.objects.create(librarian=user) LoginHistory.objects.create(librarian=user)
# Setup librarian group and permissions
librarian_group, created = Group.objects.get_or_create(name='Librarian')
if created:
librarian_group.permissions.add(
Permission.objects.get(codename='add_book'),
Permission.objects.get(codename='change_book'),
Permission.objects.get(codename='delete_book'),
# Tambahkan izin lainnya sesuai kebutuhan
)
class LoginHistory(models.Model): class LoginHistory(models.Model):
librarian = models.ForeignKey(User, on_delete=models.CASCADE) librarian = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
login_time = models.DateTimeField(default=timezone.now) login_time = models.DateTimeField(default=timezone.now)
def __str__(self): def __str__(self):
......
...@@ -30,6 +30,14 @@ ...@@ -30,6 +30,14 @@
<a class="nav-link dropdown-toggle" id="navbarDropdown" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-user fa-fw"></i>{{request.user.username}}</a> <a class="nav-link dropdown-toggle" id="navbarDropdown" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-user fa-fw"></i>{{request.user.username}}</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown"> <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item">{{request.user.username}}</a></li> <li><a class="dropdown-item">{{request.user.username}}</a></li>
<li>
{% if request.user.is_member %}
<a class="dropdown-item" href="{% url 'update-usermember' %}">Edit</a>
{% else %}
<a class="dropdown-item" href="{% url 'update-userlibrarian' %}">Edit</a>
</li>
{% endif %}
<li><a class="dropdown-item" href="{% url 'update-password' %}">Change Password</a></li>
<li><a class="dropdown-item" href="{% url 'logout' %}">Logout</a></li> <li><a class="dropdown-item" href="{% url 'logout' %}">Logout</a></li>
</ul> </ul>
{% endif %} {% endif %}
...@@ -47,34 +55,49 @@ ...@@ -47,34 +55,49 @@
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
dashboard dashboard
</a> </a>
<a class="nav-link" href="{% url 'book_list' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'book-list' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Book List Book
</a> </a>
<a class="nav-link" href="{% url 'category_list' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Category
</a>
{% if request.user.is_librarian %}
<a class="nav-link" href="{% url 'member_list' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'member_list' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Member List Member
</a> </a>
<a class="nav-link" href="{% url 'book_loan_list' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'book_loan_list' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Book Loan List Book Loan
</a> </a>
<a class="nav-link" href="{% url 'librarian_list' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'librarian_list' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Librarian List Librarian
</a> </a>
<a class="nav-link" href="{% url 'category_list' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'near_outstanding_loans' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Category Outstanding Book Loan
</a>
<a class="nav-link" href="{% url 'overdue_loans' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Overdue Book Loan
</a> </a>
{% endif%}
{%else %} {%else %}
<a class="nav-link" href="{% url 'login' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'login' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div>
Log in Log in
</a> </a>
<a class="nav-link" href="{% url 'register' %}" aria-expanded="false"> <a class="nav-link" href="{% url 'member_registration' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div>
Register Member
</a>
<a class="nav-link" href="{% url 'librarian_registration' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div> <div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div>
register Register Librarian
</a> </a>
{% endif %} {% endif %}
</div> </div>
......
{% extends 'base.html' %}
{% block content %}
<h1>Confirm Delete</h1>
<p>Are you sure you want to delete "{{ book.title }}"?</p>
<form method="post">
{% csrf_token %}
<button type="submit">Delete</button>
<a href="{% url 'book-list' %}">Cancel</a>
</form>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Detail Book</div>
<div class="card-body">
<form>
<div class="mb-3">
<label for="id_title" class="form-label">Book Title</label>
<input readonly type="text" name="title" id="id_title" value="{{ book.title }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_category">Category:</label>
<input readonly type="text" name="category" id="id_title" value="{{ book.category.name }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_author" class="form-label">Author</label>
<input readonly type="text" name="author" id="id_author" value="{{ book.author }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_publisher" class="form-label">Publisher</label>
<input readonly type="text" name="publisher" id="id_publisher" value="{{ book.publisher }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_publish">Date Publish:</label>
<input readonly type="number" name="date_publish" id="id_date_publish" value="{{ book.date_publish }}" class="form-control" required>
</div>
<div class="mb-3">
<p>Image</p>
<img src="{{ book.image.url }}" width="200px" height="150px" alt="">
</div>
<div class="mb-3">
<label for="id_isbn" class="form-label">ISBN</label>
<input readonly type="text" name="isbn" id="id_isbn" value="{{ book.isbn }}" class="form-control" required>
</div>
<a class="btn btn-primary col-2 mx-2" href="{% url 'book-edit' book.pk %}"" role="button">Edit</a>
<a class="btn btn-danger col-2 mx-2" href="{% url 'book-delete' book.pk %}"" role="button">Delete</a>
<a class="btn btn-warning col-2 mx-2" href="{% url 'book-list' %}"" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
...@@ -11,32 +11,40 @@ ...@@ -11,32 +11,40 @@
<table id="datatablesSimple"> <table id="datatablesSimple">
<thead > <thead >
<tr> <tr>
<th>Image</th>
<th>Title</th> <th>Title</th>
<th>Category</th>
<th>Author</th> <th>Author</th>
<th>Publisher</th> <th>Date Publish</th>
<th>ISBN</th>
<th>Action</th> <th>Action</th>
</tr> </tr>
</thead> </thead>
<tfoot> <tfoot>
<tr> <tr>
<th>Image</th>
<th>Title</th> <th>Title</th>
<th>Category</th>
<th>Author</th> <th>Author</th>
<th>Publisher</th> <th>Date Publish</th>
<th>ISBN</th>
<th>Action</th> <th>Action</th>
</tr> </tr>
</tfoot> </tfoot>
<tbody> <tbody>
{% for book in books %} {% for book in books %}
<tr> <tr>
<td>
{% if book.image %}
<img src="{{ book.image.url }}" width="100px" height="70px" alt="">
{% endif %}
</td>
<td>{{ book.title }}</td> <td>{{ book.title }}</td>
<td>{{ book.category.name }}</td>
<td>{{ book.author }}</td> <td>{{ book.author }}</td>
<td>{{ book.publisher }}</td> <td>{{ book.date_publish }}</td>
<td>{{ book.isbn }}</td>
<td> <td>
<a class="btn btn-success col-2 mx-2" href="detail/{{book.id}}" role="button">Detail</a>
<a class="btn btn-secondary col-2 mx-2" href="edit/{{book.id}}" role="button">Edit</a> <a class="btn btn-secondary col-2 mx-2" href="edit/{{book.id}}" role="button">Edit</a>
<a class="btn btn-danger col-3 mx-2" href="delete/{{book.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{book.title}}?')">Delete</a> <a class="btn btn-danger col-2 mx-2" href="delete/{{book.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{book.title}}?')">Delete</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
...@@ -51,8 +51,6 @@ ...@@ -51,8 +51,6 @@
<div> <div>
<a class="btn btn-primary col-2 mx-3" href="{% url 'book_loan_new' %}" role="button">Add Book Loan</a> <a class="btn btn-primary col-2 mx-3" href="{% url 'book_loan_new' %}" role="button">Add Book Loan</a>
<a class="btn btn-primary col-2 mx-3" href="{% url 'near_outstanding_loans' %}" role="button">Outstanding Book Loan</a>
<a class="btn btn-primary col-2 mx-3" href="{% url 'overdue_loans' %}" role="button">Overdue Book Loan</a>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -9,17 +9,19 @@ ...@@ -9,17 +9,19 @@
<div class="card-body"> <div class="card-body">
<form method="post" action="{% url 'book_loan_new' %}"> <form method="post" action="{% url 'book_loan_new' %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="form-group mb-3">
<label for="id_book">Book:</label> <label for="id_book">Book:</label>
<select name="book" id="id_book" class="form-control" required> <select name="book" id="id_book" class="form-control" required>
<option selected>Select Book</option>
{% for book in books %} {% for book in books %}
<option value="{{ book.id }}">{{ book.title }}</option> <option value="{{ book.id }}">{{ book.title }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="mb-3"> <div class="form-group mb-3">
<label for="id_member">Member:</label> <label for="id_member">Member:</label>
<select name="member" id="id_member" class="form-control" required> <select name="member" id="id_member" class="form-control" required>
<option selected>Select Member</option>
{% for member in members %} {% for member in members %}
<option value="{{ member.id }}">{{ member.name }}</option> <option value="{{ member.id }}">{{ member.name }}</option>
{% endfor %} {% endfor %}
...@@ -30,6 +32,7 @@ ...@@ -30,6 +32,7 @@
<input type="date" name="due_date" id="id_due_date" class="form-control" required> <input type="date" name="due_date" id="id_due_date" class="form-control" required>
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Add Book Loan</button> <button type="submit" class="btn btn-primary" role="button">Add Book Loan</button>
<a class="btn btn-warning col-2 mx-2" href="{% url 'book_loan_list' %}" role="button">Back</a>
</form> </form>
</div> </div>
</div> </div>
......
...@@ -42,7 +42,8 @@ ...@@ -42,7 +42,8 @@
<form method="post" action="{% url 'book_loan_edit' id=book_loan.id %}"> <form method="post" action="{% url 'book_loan_edit' id=book_loan.id %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary col-1 mx-2">Save</button>
<a class="btn btn-warning col-1 mx-2" href="{% url 'book_loan_list' %}" role="button">Back</a>
</form> </form>
</div> </div>
......
...@@ -7,12 +7,20 @@ ...@@ -7,12 +7,20 @@
<div class="card"> <div class="card">
<div class="card-header bg-primary text-white">Add Book</div> <div class="card-header bg-primary text-white">Add Book</div>
<div class="card-body"> <div class="card-body">
<form method="post" action="{% url 'book-new' %}"> <form method="post" action="{% url 'book-new' %}" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="id_title" class="form-label">Book Title</label> <label for="id_title" class="form-label">Book Title</label>
<input type="text" name="title" id="id_title" placeholder="Book Title" class="form-control" required> <input type="text" name="title" id="id_title" placeholder="Book Title" class="form-control" required>
</div> </div>
<div class="mb-3">
<label for="id_category">Category:</label>
<select name="category" id="id_category" class="form-control" required>
{% for category in category %}
<option value="{{ category.id }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="id_author" class="form-label">Author</label> <label for="id_author" class="form-label">Author</label>
<input type="text" name="author" id="id_author" placeholder="Author" class="form-control" required> <input type="text" name="author" id="id_author" placeholder="Author" class="form-control" required>
...@@ -21,11 +29,20 @@ ...@@ -21,11 +29,20 @@
<label for="id_publisher" class="form-label">Publisher</label> <label for="id_publisher" class="form-label">Publisher</label>
<input type="text" name="publisher" id="id_publisher" placeholder="Publisher" class="form-control" required> <input type="text" name="publisher" id="id_publisher" placeholder="Publisher" class="form-control" required>
</div> </div>
<div class="mb-3">
<label for="id_date_publish">Date Publish:</label>
<input type="number" name="date_publish" id="id_date_publish" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_image">Input Image</label>
<input type="file" name="image" id="id_image" class="form-control" required>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="id_isbn" class="form-label">ISBN</label> <label for="id_isbn" class="form-label">ISBN</label>
<input type="text" name="isbn" id="id_isbn" placeholder="ISBN" class="form-control" required> <input type="text" name="isbn" id="id_isbn" placeholder="ISBN" class="form-control" required>
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Add</button> <button type="submit" class="btn btn-primary" role="button">Add</button>
<a class="btn btn-warning col-2 mx-2" href="{% url 'book-list' %}"" role="button">Back</a>
</form> </form>
</div> </div>
</div> </div>
...@@ -34,12 +51,4 @@ ...@@ -34,12 +51,4 @@
</div> </div>
<!-- <div style="text-align: center; margin-top: 50px;">
<h2>Add Book</h2>
<form method="post" action="{% url 'book_new' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div> -->
{% endblock content%} {% endblock content%}
\ No newline at end of file
...@@ -7,11 +7,19 @@ ...@@ -7,11 +7,19 @@
<div class="card"> <div class="card">
<div class="card-header bg-primary text-white">Edit Book</div> <div class="card-header bg-primary text-white">Edit Book</div>
<div class="card-body"> <div class="card-body">
<form method="post" action="{% url 'edit_book' id=book.id %}"> <form method="post" action="{% url 'book-edit' pk=book.pk %}" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="id_title" class="form-label">Book Title</label> <label for="id_title" class="form-label">Book Title</label>
<input type="text" name="title" id="id_title" value="{{ book.title }}" placeholder="Book Title" class="form-control" required> <input readonly type="text" name="title" id="id_title" value="{{ book.title }}" placeholder="Book Title" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_category">Category:</label>
<select name="category" id="id_category" class="form-control" required>
{% for category in category %}
<option value="{{ category.id }}">{{ category.name }}</option>
{% endfor %}
</select>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_author" class="form-label">Author</label> <label for="id_author" class="form-label">Author</label>
...@@ -21,11 +29,20 @@ ...@@ -21,11 +29,20 @@
<label for="id_publisher" class="form-label">Publisher</label> <label for="id_publisher" class="form-label">Publisher</label>
<input type="text" name="publisher" id="id_publisher" value="{{ book.publisher }}" placeholder="Publisher" class="form-control" required> <input type="text" name="publisher" id="id_publisher" value="{{ book.publisher }}" placeholder="Publisher" class="form-control" required>
</div> </div>
<div class="mb-3">
<label for="id_date_publish">Date Publish:</label>
<input type="number" name="date_publish" id="id_date_publish" value="{{ book.date_publish }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_image">Input Image</label>
<input type="file" name="image" id="id_image" value="{{ book.image }}"" class="form-control" required>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="id_isbn" class="form-label">ISBN</label> <label for="id_isbn" class="form-label">ISBN</label>
<input type="text" name="isbn" id="id_isbn" value="{{ book.isbn }}" placeholder="ISBN" class="form-control" required> <input type="text" name="isbn" id="id_isbn" value="{{ book.isbn }}" placeholder="ISBN" class="form-control" required>
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Save Changes</button> <button type="submit" class="btn btn-primary" role="button">Save Changes</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'book-list' %}" role="button">Back</a>
</form> </form>
</div> </div>
</div> </div>
......
...@@ -12,11 +12,13 @@ ...@@ -12,11 +12,13 @@
<thead > <thead >
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Action</th>
</tr> </tr>
</thead> </thead>
<tfoot> <tfoot>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Action</th>
</tr> </tr>
</tfoot> </tfoot>
<tbody> <tbody>
...@@ -24,19 +26,28 @@ ...@@ -24,19 +26,28 @@
<tr> <tr>
<td>{{ category.name }}</td> <td>{{ category.name }}</td>
<td> <td>
<a class="btn btn-secondary col-2 mx-2" href="{% url 'librarian_edit' pk=librarian.pk %}" role="button">Edit</a> <a class="btn btn-secondary col-1 mx-3" href="{% url 'category_edit' pk=category.pk %}" role="button">Edit</a>
<a class="btn btn-danger col-2 mx-2" href="delete/{{librarian.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{book.title}}?')">Delete</a> <a class="btn btn-danger col-1 mx-3" href="delete/{{category.id}}" role="button" onclick="return confirm('Are you sure you want to delete ?')">Delete</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<div> <div>
<a class="btn btn-primary col-2 mx-3" href="{% url 'librarian_new' %}" role="button">Add a Librarian</a> <a class="btn btn-primary col-1 mx-3" href="{% url 'category_new' %}" role="button">Add Category</a>
<a class="btn btn-primary col-2 mx-3" href="{% url 'librarian_login_history' %}" role="button">Librarian Login History</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock content%} {% endblock content%}
<!-- <td>
<a class="btn btn-secondary col-2 mx-2" href="{% url 'librarian_edit' pk=librarian.pk %}" role="button">Edit</a>
<a class="btn btn-danger col-2 mx-2" href="delete/{{librarian.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{book.title}}?')">Delete</a>
</td> -->
<!-- <div>
<a class="btn btn-primary col-2 mx-3" href="{% url 'librarian_new' %}" role="button">Add a Librarian</a>
<a class="btn btn-primary col-2 mx-3" href="{% url 'librarian_login_history' %}" role="button">Librarian Login History</a>
</div> -->
\ No newline at end of file
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Login</div>
<div class="card-body">
{% if user.is_authenticated %}
<meta http-equiv="refresh" content="0; url={% url 'dashboard' %}" />
{% else %}
<form method="post" action="{% url 'librarian_login' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_username" class="form-label">Username</label>
<input type="text" name="username" id="id_username" placeholder="Username" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_password" class="form-label">Password</label>
<input type="password" name="password" id="id_password" placeholder="Password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary" role="button">Login</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock content%}
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Member Registration</div>
<div class="card-body">
<form method="post" action="{% url 'librarian_registration' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group m-3">
<label for="">Username</label>
{{ form.username }}
</div>
<div class="form-group m-3">
<label for="">Email</label>
{{ form.email }}
</div>
<div class="form-group m-3">
<label for="">Is Librarian:</label>
{{ form.is_librarian }}
</div>
<div class="form-group m-2">
<label for="">Password</label>
{{ form.password1 }}
</div>
<div class="form-group m-2">
<label for="">Confirm Password</label>
{{ form.password2 }}
</div>
<button type="submit" class="btn btn-primary" role="button">Create</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'book-list' %}" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- <div style="text-align: center; margin-top: 50px;">
<h2>Create Account</h2>
<form method="post" action="{% url 'librarian_registration' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div> -->
{% endblock content%}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<div class="card"> <div class="card">
<div class="card-header bg-primary text-white">Edit Librarian</div> <div class="card-header bg-primary text-white">Edit Librarian</div>
<div class="card-body"> <div class="card-body">
<form method="post" action="{% url 'librarian_edit' pk=librarian.id %}"> <form method="POST" action="{% url 'librarian_edit' id=librarian.id %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="id_name">Name:</label> <label for="id_name">Name:</label>
...@@ -15,24 +15,33 @@ ...@@ -15,24 +15,33 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_username">Username:</label> <label for="id_lastname">Last Name:</label>
<input type="text" name="username" id="id_username" value="{{ librarian.user.username }}" placeholder="Username" class="form-control" required> <input type="text" name="last_name" id="id_lastname" value="{{ librarian.last_name }}" placeholder="Last Name" class="form-control" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_email">Email:</label> <label for="id_address">Address:</label>
<input type="email" name="email" id="id_email" value="{{ librarian.user.email }}" placeholder="Email" class="form-control" required> <textarea type="text" name="address" id="id_address" value="{{ librarian.address }}" placeholder="Address" class="form-control" required></textarea>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_password">New Password:</label> <label for="id_birthplace">Birth Place:</label>
<input type="password" name="password1" id="id_password" placeholder="Password" class="form-control" required> <input type="text" name="birth_place" id="id_lastname" value="{{ librarian.birth_place }}" placeholder="Birth Place" class="form-control" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_password2">Confirm Password:</label> <label for="id_datebirth">Birth date:</label>
<input type="password" name="password2" id="id_password2" placeholder="Confirm Password" class="form-control" required> <input type="date" name="date_birth" id="id_datebirth" value="{{ librarian.date_birth }}" placeholder="Birth Date" class="form-control" required>
</div> </div>
<div class="mb-3">
<!-- <label for="id_phone_number" class="form-label">Phone Number</label>
<input type="tel" name="phone_number" id="id_phone_number" value="{{ librarian.phone_number }}" placeholder="Phone Number" class="form-control" required> -->
{{form.phone_number}}
</div>
<button type="submit" class="btn btn-primary" role="button">Save Changes</button> <button type="submit" class="btn btn-primary" role="button">Save Changes</button>
</form> </form>
</div> </div>
...@@ -41,38 +50,15 @@ ...@@ -41,38 +50,15 @@
</div> </div>
</div> </div>
{% endblock content%}
<!-- <div style="text-align: center; margin-top: 50px;"> <!-- <div style="text-align: center; margin-top: 50px;">
<h2>Edit Librarian</h2> <h2>Edit</h2>
<form method="post" action="{% url 'librarian_edit' pk=librarian.id %}"> <form method="post" action="{% url 'librarian_edit' id=librarian.id %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> {{ form.as_p }}
<label for="id_name">Name:</label>
<input type="text" name="name" id="id_name" value="{{ librarian.name }}" placeholder="Input Name" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_username">Username:</label>
<input type="text" name="username" id="id_username" value="{{ librarian.user.username }}" placeholder="Username" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_email">Email:</label>
<input type="email" name="email" id="id_email" value="{{ librarian.user.email }}" placeholder="Email" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_password">Password:</label>
<input type="password" name="password1" id="id_password" placeholder="Password" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_password2">Confirm Password:</label>
<input type="password" name="password2" id="id_password2" placeholder="Confirm Password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
</form> </form>
</div> --> </div> -->
{% endblock content%}
\ No newline at end of file
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
<div class="mb-3"> <div class="mb-3">
<label for="id_password" class="form-label">Password</label> <label for="id_password" class="form-label">Password</label>
<input type="password" name="password" id="id_password" placeholder="Password" class="form-control" required> <input type="password" name="password" id="id_password" placeholder="Password" class="form-control" required>
<input type="checkbox" onclick="showPassword()"> Show Password
<br>
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Login</button> <button type="submit" class="btn btn-primary" role="button">Login</button>
</form> </form>
...@@ -29,5 +31,17 @@ ...@@ -29,5 +31,17 @@
</div> </div>
</div> </div>
<script>
function showPassword() {
var passwordInput = document.getElementById('id_password');
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
} else {
passwordInput.type = 'password';
}
}
</script>
{% endblock content%} {% endblock content%}
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<td>{{ member.phone_number }}</td> <td>{{ member.phone_number }}</td>
<td> <td>
<a class="btn btn-secondary col-3 mx-2" href="edit/{{member.id}}" role="button">Edit</a> <a class="btn btn-secondary col-3 mx-2" href="edit/{{member.id}}" role="button">Edit</a>
<a class="btn btn-danger col-3 mx-2" href="delete/{{member.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{ member.name }}')">Delete</a> <a class="btn btn-danger col-3 mx-3" href="delete/{{member.id}}" role="button" onclick="return confirm('Are you sure you want to delete {{ member.name }}')">Delete</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Login</div>
<div class="card-body">
{% if user.is_authenticated %}
<meta http-equiv="refresh" content="0; url={% url 'dashboard' %}" />
{% else %}
<form method="post" action="{% url 'member_login' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_username" class="form-label">Username</label>
<input type="text" name="username" id="id_username" placeholder="Username" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_password" class="form-label">Password</label>
<input type="password" name="password" id="id_password" placeholder="Password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary" role="button">Login</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock content%}
...@@ -19,13 +19,22 @@ ...@@ -19,13 +19,22 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_address" class="form-label">Address</label> <label for="id_address" class="form-label">Address</label>
<input type="text" name="address" id="id_address" placeholder="Input Address" class="form-control" required> <textarea type="text" name="address" id="id_address" placeholder="Input Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_birth_place" class="form-label">Birth Place</label>
<input type="text" name="birth_place" id="id_birth_place" placeholder="Input Birth Place" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_birth" class="form-label">Birth Date</label>
<input type="date" name="date_birth" id="id_date_birth" placeholder="Input datebirth" class="form-control" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_phone_number" class="form-label">Phone Number</label> <label for="id_phone_number" class="form-label">Phone Number</label>
<input type="tel" name="phone_number" id="id_phone_number" placeholder="Phone Number" class="form-control" required> {{form.phone_number}}
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Add</button> <button type="submit" class="btn btn-primary" role="button">Add</button>
<a class="btn btn-warning col-2 mx-2" href="{% url 'member_list' %}"" role="button">Back</a>
</form> </form>
</div> </div>
</div> </div>
......
{% extends 'base.html' %}
{% block content%}
<!-- <div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card p-4">
<h2>Create Account</h2>
<form method="post" action="{% url 'member_registration' %}">
{% csrf_token %}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</div>
</div>
</div> -->
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Member Registration</div>
<div class="card-body">
<form method="post" action="{% url 'member_registration' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group m-3">
<label for="">Username</label>
{{ form.username }}
</div>
<div class="form-group m-3">
<label for="">Email</label>
{{ form.email }}
</div>
<div class="form-group m-3">
<label for="">Is Member:</label>
{{ form.is_member }}
</div>
<div class="form-group m-2">
<label for="">Password</label>
{{ form.password1 }}
<!-- <input type="checkbox" onclick="showPassword()"> Show Password
<br> -->
</div>
<div class="form-group m-2">
<label for="">Confirm Password</label>
{{ form.password2 }}
<!-- <input type="checkbox" onclick="showPassword()"> Show Password
<br> -->
</div>
<button type="submit" class="btn btn-primary" role="button">Create</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'book-list' %}" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- <script>
function showPassword() {
var passwordInput = document.getElementById('id_password');
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
} else {
passwordInput.type = 'password';
}
}
</script> -->
{% endblock content%}
\ No newline at end of file
...@@ -19,13 +19,22 @@ ...@@ -19,13 +19,22 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_address" class="form-label">Address</label> <label for="id_address" class="form-label">Address</label>
<input type="text" name="address" id="id_address" value="{{ member.address }}" placeholder="Input Address" class="form-control" required> <textarea type="text" name="address" id="id_address" value="{{ member.address }}" placeholder="Input Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_birth_place" class="form-label">Birth Place</label>
<input type="text" name="birth_place" id="id_birth_place" value="{{ member.birth_place }}" placeholder="Input Birth Place" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_birth" class="form-label">Birth Date</label>
<input type="date" name="date_birth" id="id_date_birth" value="{{ member.date_birth }}" placeholder="Input datebirth" class="form-control" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_phone_number" class="form-label">Phone Number</label> <label for="id_phone_number" class="form-label">Phone Number</label>
<input type="tel" name="phone_number" id="id_phone_number" value="{{ member.phone_number }}" placeholder="Phone Number" class="form-control" required> <input type="tel" name="phone_number" id="id_phone_number" value="{{ member.phone_number }}" placeholder="Phone Number" class="form-control" required>
</div> </div>
<button type="submit" class="btn btn-primary" role="button">Save Changes</button> <button type="submit" class="btn btn-primary" role="button">Save Changes</button>
<a class="btn btn-warning col-2 mx-2" href="{% url 'member_list' %}"" role="button">Back</a>
</form> </form>
</div> </div>
</div> </div>
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
<th>Member Name</th> <th>Member Name</th>
<th>Loan Date</th> <th>Loan Date</th>
<th>Due Date</th> <th>Due Date</th>
<th>Return Date</th>
<th>Overdue Date</th> <th>Overdue Date</th>
</tr> </tr>
</thead> </thead>
...@@ -25,7 +24,6 @@ ...@@ -25,7 +24,6 @@
<th>Member Name</th> <th>Member Name</th>
<th>Loan Date</th> <th>Loan Date</th>
<th>Due Date</th> <th>Due Date</th>
<th>Return Date</th>
<th>Overdue Date</th> <th>Overdue Date</th>
</tr> </tr>
</tfoot> </tfoot>
...@@ -36,8 +34,7 @@ ...@@ -36,8 +34,7 @@
<td>{{ loan.member.name }}</td> <td>{{ loan.member.name }}</td>
<td>{{ loan.loan_date }}</td> <td>{{ loan.loan_date }}</td>
<td>{{ loan.due_date }}</td> <td>{{ loan.due_date }}</td>
<td>{{ loan.return_date }}</td> <td>{{ loan.dead}}</td>
<td>{{ loan.dead.days}} Days</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
......
...@@ -10,8 +10,12 @@ ...@@ -10,8 +10,12 @@
<form method="post" action="{% url 'register' %}"> <form method="post" action="{% url 'register' %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="id_name" class="form-label">Name</label> <label for="id_name" class="form-label">First Name</label>
<input type="text" name="name" id="id_name" placeholder="Name" class="form-control" required> <input type="text" name="name" id="id_name" placeholder="First Name" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_lname" class="form-label">Last Name</label>
<input type="text" name="lname" id="id_lname" placeholder="Last Name" class="form-control" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="id_username" class="form-label">Username</label> <label for="id_username" class="form-label">Username</label>
...@@ -21,6 +25,18 @@ ...@@ -21,6 +25,18 @@
<label for="email" class="form-label">Email</label> <label for="email" class="form-label">Email</label>
<input type="email" name="email" id="email" placeholder="Email" class="form-control" required> <input type="email" name="email" id="email" placeholder="Email" class="form-control" required>
</div> </div>
<div class="mb-3">
<label for="id_address" class="form-label">Address</label>
<textarea type="text" name="address" id="id_address" placeholder="Input Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_birth_place" class="form-label">Birth Place</label>
<input type="text" name="birth_place" id="id_birth_place" placeholder="Input Birth Place" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_birth" class="form-label">Birth Date</label>
<input type="date" name="date_birth" id="id_date_birth" placeholder="Input datebirth" class="form-control" required>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="id_password1" class="form-label">Password</label> <label for="id_password1" class="form-label">Password</label>
<input type="password" name="password1" id="id_password1" placeholder="Password" class="form-control" required> <input type="password" name="password1" id="id_password1" placeholder="Password" class="form-control" required>
...@@ -38,14 +54,13 @@ ...@@ -38,14 +54,13 @@
</div> </div>
<!-- <div style="text-align: center; margin-top: 50px;"> <div style="text-align: center; margin-top: 50px;">
<h2>Create Account</h2> <h2>Create Account</h2>
<form method="post" action="{% url 'register' %}"> <form method="post" action="{% url 'register' %}">
{% csrf_token %} {% csrf_token %}
{{ user_form.as_p }} {{ form.as_p }}
{{ librarian_form.as_p }}
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
</form> </form>
</div> --> </div>
{% endblock content%} {% endblock content%}
{% extends 'base.html' %}
{% block content%}
<div class="container-fluid px-4 pt-3">
<h2 style="text-align: center;" font-family: serif;>You dont have Permissions!</h2>
</div>
{% load static %}
<img src="{% static 'assets/perpustakaan.jpg' %}" class="img-fluid" alt="Perpustakaan">
{% endblock %}
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Change Password</div>
<div class="card-body">
<form method="post" action="{% url 'update-password' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_old_password" class="form-label">Current Password</label>
<input type="password" name="old_password" id="id_old_password" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_new_password" class="form-label">New Password</label>
<input type="password" name="new_password" id="id_new_password" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_confirm_password" class="form-label">Confirm Password</label>
<input type="password" name="confirm_password" id="id_confirm_password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary" role="button">Change Password</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'dashboard' %}"" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock content%}
\ No newline at end of file
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Edit Profile</div>
<div class="card-body">
<form method="post" action="{% url 'update-userlibrarian' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_name" class="form-label">Name</label>
<input type="text" name="name" id="id_name" value="{{ member.name }}" placeholder="Input Name" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_last_name" class="form-label">Last Name</label>
<input type="text" name="last_name" id="id_last_name" placeholder="Input Last Name" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_address" class="form-label">Address</label>
<textarea type="text" name="address" id="id_address" placeholder="Input Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_birth_place" class="form-label">Birth Place</label>
<input type="text" name="birth_place" id="id_birth_place" placeholder="Input Birth Place" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_birth" class="form-label">Birth Date</label>
<input type="date" name="date_birth" id="id_date_birth" placeholder="Input datebirth" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_phone_number" class="form-label">Phone Number</label>
<input type="tel" name="phone_number" id="id_phone_number" value="{{ librarian.phone_number }}" placeholder="Phone Number" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary" role="button">Save</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'dashboard' %}"" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock content%}
\ No newline at end of file
{% extends 'base.html' %}
{% block content%}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 mt-5">
<div class="card">
<div class="card-header bg-primary text-white">Edit Profile</div>
<div class="card-body">
<form method="post" action="{% url 'update-usermember' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_name" class="form-label">Name</label>
<input type="text" name="name" id="id_name" value="{{ member.name }}" placeholder="Input Name" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_email" class="form-label">Email</label>
<input type="email" name="email" id="id_email" placeholder="Input Email" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_address" class="form-label">Address</label>
<textarea type="text" name="address" id="id_address" placeholder="Input Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_birth_place" class="form-label">Birth Place</label>
<input type="text" name="birth_place" id="id_birth_place" placeholder="Input Birth Place" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_date_birth" class="form-label">Birth Date</label>
<input type="date" name="date_birth" id="id_date_birth" placeholder="Input datebirth" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_phone_number" class="form-label">Phone Number</label>
<input type="tel" name="phone_number" id="id_phone_number" value="{{ member.phone_number }}" placeholder="Phone Number" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary" role="button">Save</button>
<a class="btn btn-danger col-2 mx-2" href="{% url 'dashboard' %}"" role="button">Back</a>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- <div style="text-align: center; margin-top: 50px;">
<h2>Update Profile</h2>
<form method="post" action="">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div> -->
{% endblock content%}
\ No newline at end of file
{% extends 'base.html' %}
{% block content%}
<div class="container-fluid px-4 pt-3">
<h2 style="text-align: center;" font-family: serif;>Your Password Has Been Change!</h2>
</div>
{% load static %}
<img src="{% static 'assets/perpustakaan.jpg' %}" class="img-fluid" alt="Perpustakaan">
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% block content%}
<div class="container-fluid px-4 pt-3">
<h2 style="text-align: center;" font-family: serif;>Your Profile Has Been Update!</h2>
</div>
{% load static %}
<img src="{% static 'assets/perpustakaan.jpg' %}" class="img-fluid" alt="Perpustakaan">
{% endblock %}
\ No newline at end of file
from django.urls import path from django.urls import path
from django.contrib.auth.views import LogoutView from django.contrib.auth.views import LogoutView, LoginView
from .views import * from .views import *
from django.views.generic import TemplateView, ListView from django.views.generic import *
from django.conf.urls.static import static
urlpatterns = [ urlpatterns = [
path('', homepage, name='homepage'), path('', homepage, name='homepage'),
path('login/', login_view, name='login'), # path('login/', login_view, name='login'),
# path('register/', register, name='register'),
path('login/', Login, name='login'),
path('logout/', LogoutView.as_view(next_page='homepage'), name='logout'), path('logout/', LogoutView.as_view(next_page='homepage'), name='logout'),
path('register/', register_view, name='register'),
path('dashboard/', dashboard, name='dashboard'), path('dashboard/', dashboard, name='dashboard'),
path('librarian-registration/', librarian_registration, name='librarian_registration'),
path('librarians/', librarian_list, name='librarian_list'), path('librarians/', librarian_list, name='librarian_list'),
path('librarians/add/', librarian_new, name='librarian_new'), path('librarians/add/', librarian_new, name='librarian_new'),
path('librarians/edit/<int:pk>/', librarian_update, name='librarian_edit'), path('librarians/edit/<int:id>/', librarian_update, name='librarian_edit'),
path('librarians/delete/<int:pk>/', librarian_delete, name='librarian_delete'), path('librarians/delete/<int:pk>/', librarian_delete, name='librarian_delete'),
path('books/', book_list, name='book_list'), path('books/', BookList.as_view(), name='book-list'),
path('books/add/', book_new, name='book_new'), path('books/detail/<int:pk>/', BookDetail.as_view(), name='book-detail'),
path('books/edit/<int:id>/', book_update, name='edit_book'), path('books/add/', BookCreateView.as_view(), name='book-new'),
path('books/edit/<int:pk>/', BookUpdateView.as_view(), name='book-edit'),
path('books/delete/<int:id>/', book_delete, name='delete_book'), path('books/delete/<int:id>/', book_delete, name='delete_book'),
path('books/<int:pk>/delete/', BookDeleteView.as_view(), name='book-delete'),
path('book-loans/', book_loan_list, name='book_loan_list'), path('book-loans/', book_loan_list, name='book_loan_list'),
path('book-loans/add/', book_loan_new, name='book_loan_new'), path('book-loans/add/', book_loan_new, name='book_loan_new'),
...@@ -27,9 +32,13 @@ urlpatterns = [ ...@@ -27,9 +32,13 @@ urlpatterns = [
# path('book-loans/edit/<uuid:pk>/', book_loan_update, name='book_loan_edit'), # path('book-loans/edit/<uuid:pk>/', book_loan_update, name='book_loan_edit'),
path('book-loans/delete/<int:id>/', book_loan_delete, name='book_loan_delete'), path('book-loans/delete/<int:id>/', book_loan_delete, name='book_loan_delete'),
path('bookloans/', BookLoanList.as_view(), name='bookloan-list'),
path('near-outstanding-loans/', near_outstanding_loans, name='near_outstanding_loans'), path('near-outstanding-loans/', near_outstanding_loans, name='near_outstanding_loans'),
path('overdue-loans/', overdue_loans, name='overdue_loans'), path('overdue-loans/', overdue_loans, name='overdue_loans'),
path('member-registration/', member_registration, name='member_registration'),
path('member/', member_list, name='member_list'), path('member/', member_list, name='member_list'),
path('member/add/', member_new, name='member_new'), path('member/add/', member_new, name='member_new'),
path('member/edit/<int:id>/', edit_member, name='edit_member'), path('member/edit/<int:id>/', edit_member, name='edit_member'),
...@@ -37,9 +46,20 @@ urlpatterns = [ ...@@ -37,9 +46,20 @@ urlpatterns = [
path('librarian-login-history/', librarian_login_history, name='librarian_login_history'), path('librarian-login-history/', librarian_login_history, name='librarian_login_history'),
path("books2/", BookList.as_view(), name='book-list'), path('update-usermember/', update_usermember, name='update-usermember'),
path("books2/add/", BookCreateView.as_view(), name='book-new'), path('update-userlibrarian/', update_userlibrarian, name='update-userlibrarian'),
path('updateuser_success/', updateuser_success, name='updateuser_success'),
path('update-password', userchange_password, name='update-password'),
path('updatepassword_success/', updateuser_success, name='updatepassword_success'),
path('categories/', CategoryListView.as_view(), name='category_list'), path('categories/', CategoryListView.as_view(), name='category_list'),
path('category/add/', CategoryCreateView.as_view(), name='category_new'),
path('category/edit/<int:pk>/', CategoryUpdateView.as_view(), name='category_edit'),
path('unauthorized/', unauthorized, name='unauthorized'),
] ]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
\ No newline at end of file
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