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 *
from rest_framework import serializers
from django.contrib.auth import authenticate, get_user_model
from datetime import date
from django.conf import settings
class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField()
......@@ -74,9 +76,11 @@ class UserProfileSerializer(serializers.ModelSerializer):
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
fields = ['name']
class BookSerializer(serializers.ModelSerializer):
category = CategorySerializer()
class Meta:
model = Book
fields = '__all__'
......@@ -94,27 +98,103 @@ class LibrarianSerializer(serializers.ModelSerializer):
model = Librarian
fields = '__all__'
from rest_framework import serializers
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:
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):
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:
model = BookLoan
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):
return (date.today() - obj.due_date).days
class NearOutstandingLoanSerializer(serializers.ModelSerializer):
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:
model = BookLoan
fields = '__all__'
def get_days_left(self, obj):
return (obj.due_date - date.today()).days
\ No newline at end of file
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 @@
from django.urls import include, path
from api import views
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 = [
# 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/<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('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('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/<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
from rest_framework.parsers import JSONParser
from library.models import *
from api.serializers import *
from rest_framework import viewsets
from datetime import date, timedelta
from rest_framework.decorators import api_view
from rest_framework.response import Response
......@@ -19,11 +20,15 @@ from rest_framework.authtoken.models import Token
from .permissions import *
from rest_framework_simplejwt.tokens import RefreshToken
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
class MyPageNumberPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
page_query_param = 'page'
#regist librarian
class LibrarianRegistrationAPIView(generics.CreateAPIView):
......@@ -140,7 +145,7 @@ class ChangeProfileView(generics.UpdateAPIView):
#Category Create dan List
class CategoryList(generics.ListCreateAPIView):
permission_classes = [LibrarianPermission]
permission_classes = [IsAuthenticated]
queryset = Category.objects.all()
serializer_class = CategorySerializer
......@@ -152,12 +157,18 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class BookListNonAuth(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
#Book Create dan List
class BookList(generics.ListCreateAPIView):
permission_classes = [MemberReadOnlyPermission|LibrarianPermission]
# permission_classes = [MemberReadOnlyPermission|LibrarianPermission]
permission_classes = [IsAuthenticated]
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = MyPageNumberPagination
#Book Update, Detail, Delete
class BookDetail(generics.RetrieveUpdateDestroyAPIView):
......@@ -196,15 +207,31 @@ class LibrarianDetail(generics.RetrieveUpdateDestroyAPIView):
#BookLoan Create dan List
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
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
class BookLoanDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [LibrarianPermission]
permission_classes = [IsAuthenticated, LibrarianPermission]
queryset = BookLoan.objects.all()
serializer_class = BookLoanSerializer
......@@ -215,8 +242,8 @@ class BookSearchView(generics.ListAPIView):
serializer_class = BookSerializer
def get_queryset(self):
book_name = self.request.query_params.get('book_name', '')
return Book.objects.filter(title__icontains=book_name)
title = self.request.query_params.get('title', '')
return Book.objects.filter(title__icontains=title)
#Book list By Year
class BookListByYear(generics.ListAPIView):
......@@ -241,7 +268,7 @@ class BookListByYearAndCategory(generics.ListAPIView):
#Book list By Category
class BookListByCategory(generics.ListAPIView):
permission_classes = [MemberReadOnlyPermission|LibrarianPermission]
permission_classes = [IsAuthenticated]
serializer_class = BookSerializer
......@@ -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)
#overdue loan list
......@@ -285,5 +312,60 @@ class OverdueLoansAPIView(APIView):
for loan in over_due:
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)
# 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
This diff is collapsed.
No preview for this file type
......@@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from datetime import timedelta
import os
from pathlib import Path
......@@ -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!
DEBUG = True
ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['10.0.2.2', '127.0.0.1']
# Application definition
......@@ -41,6 +42,11 @@ INSTALLED_APPS = [
'library',
'api',
'rest_framework',
'rest_framework.authtoken',
'phonenumber_field',
'rest_framework_simplejwt',
'rest_framework_simplejwt.token_blacklist',
'corsheaders',
]
MIDDLEWARE = [
......@@ -51,6 +57,8 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'library.middleware.UserTypeMiddleware',
'corsheaders.middleware.CorsMiddleware',
]
ROOT_URLCONF = 'djangoproj.urls'
......@@ -64,6 +72,7 @@ TEMPLATES = [
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.media',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
......@@ -120,9 +129,13 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
# STATICFILES_DIRS = [
# os.path.join(BASE_DIR, 'static')
# ]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
......@@ -134,5 +147,22 @@ LOGIN_URL='/login'
REST_FRAMEWORK = {
'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
"""
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("library.urls")),
path('api/', include('api.urls')),
path('api-auth/', include('api.urls')),
]
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(Member)
admin.site.register(BookLoan)
admin.site.register(Librarian)
admin.site.register(LoginHistory)
\ No newline at end of file
admin.site.register(LoginHistory)
admin.site.register(CustomUser)
\ No newline at end of file
......@@ -3,4 +3,4 @@ from django.apps import AppConfig
class LibraryConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'library'
name = 'library'
\ 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 django import forms
from .models import Book, Category, Member, BookLoan, Librarian
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from .models import *
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm
from django.contrib.auth.models import AbstractUser
from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.widgets import PhoneNumberPrefixWidget
class LoginForm(forms.Form):
username = forms.CharField(max_length=50)
password = forms.CharField(widget=forms.PasswordInput)
# 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
class CustomAuthenticationForm(AuthenticationForm):
class Meta:
model = CustomUser
fields = ['username', 'password']
# def clean(self):
# cleaned_data = super().clean()
# password1 = cleaned_data.get('password1')
# password2 = cleaned_data.get('password2')
class LibrarianRegistrationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = UserCreationForm.Meta.fields + ('email', 'is_librarian',)
# if password1 and password2 and password1 != password2:
# raise forms.ValidationError('Passwords do not match')
class MemberRegistrationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = UserCreationForm.Meta.fields + ('email',)
# return cleaned_data
# class UserCreationForm(UserCreationForm):
# class Meta:
# model = User
# fields = UserCreationForm.Meta.fields + 'email'
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
class userCreat(UserCreationForm):
class MemberForm(forms.ModelForm):
phone_number = PhoneNumberField(
widget=PhoneNumberPrefixWidget(attrs={'class': 'form-control'})
)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
model = Member
fields = '__all__'
class LibrarianForm(forms.ModelForm):
phone_number = PhoneNumberField(
widget=PhoneNumberPrefixWidget(attrs={'class': 'form-control'})
)
class Meta:
model = Librarian
fields = ['name']
# 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)
fields = ['name', 'last_name', 'address', 'birth_place', 'date_birth', 'phone_number']
class MemberProfileUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'email', 'name']
model = Member
fields = ['name', 'email', 'address', 'birth_place', 'date_birth', 'phone_number']
class BookForm(forms.ModelForm):
class LibrarianProfileUpdateForm(forms.ModelForm):
class Meta:
model = Book
fields = ['title', 'author', 'publisher', 'isbn']
model = Librarian
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):
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
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
......@@ -9,9 +14,36 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
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(
name='Book',
fields=[
......@@ -19,17 +51,15 @@ class Migration(migrations.Migration):
('title', models.CharField(max_length=100)),
('author', 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)),
],
),
migrations.CreateModel(
name='Librarian',
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('username', models.CharField(max_length=50, unique=True)),
('password', models.CharField(max_length=100)),
('email', models.EmailField(max_length=254, unique=True)),
('name', models.CharField(max_length=255)),
],
),
migrations.CreateModel(
......@@ -39,16 +69,30 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=100)),
('address', models.TextField()),
('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(
name='LoginHistory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('login_time', models.DateTimeField()),
('logout_time', models.DateTimeField(blank=True, null=True)),
('librarian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.librarian')),
('login_time', models.DateTimeField(default=django.utils.timezone.now)),
('librarian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
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(
......@@ -63,4 +107,9 @@ class Migration(migrations.Migration):
('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
......@@ -6,18 +6,18 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0003_remove_loginhistory_logout_time_and_more'),
('library', '0002_librarian_phone_number'),
]
operations = [
migrations.AddField(
model_name='bookloan',
name='is_late',
model_name='customuser',
name='is_librarian',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='bookloan',
name='late_fee',
field=models.IntegerField(default=0),
model_name='customuser',
name='is_member',
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
......@@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0008_book_category'),
('library', '0003_customuser_is_librarian_customuser_is_member'),
]
operations = [
migrations.AddField(
model_name='book',
name='date_publish',
field=models.DateField(null=True),
name='image',
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
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('library', '0007_category'),
('library', '0004_book_image'),
]
operations = [
migrations.AddField(
migrations.AlterField(
model_name='book',
name='category',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='library.category'),
preserve_default=False,
name='image',
field=models.ImageField(null=True, upload_to='book_images/'),
),
]
# 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.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser, Group, Permission
from django.utils import timezone
from django.contrib.auth.signals import user_logged_in
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.
class CustomUser(AbstractUser):
is_member = models.BooleanField(default=True)
is_librarian = models.BooleanField(default=False)
class Category(models.Model):
name = models.CharField(max_length=255)
......@@ -18,17 +25,39 @@ class Book(models.Model):
author = models.CharField(max_length=100)
publisher = models.CharField(max_length=100)
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)
def is_available(self):
return not self.bookloan_set.filter(is_returned=False).exists()
def __str__(self):
return self.title
class Member(models.Model):
user = models.OneToOneField(CustomUser, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
address = models.TextField()
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):
return self.name
......@@ -45,18 +74,48 @@ class BookLoan(models.Model):
return f"{self.book.title} - {self.member.name}"
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)
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):
return self.name
@receiver(user_logged_in, sender=User)
@receiver(user_logged_in, sender=CustomUser)
def create_librarian_login_history(sender, user, **kwargs):
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):
librarian = models.ForeignKey(User, on_delete=models.CASCADE)
librarian = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
login_time = models.DateTimeField(default=timezone.now)
def __str__(self):
......
......@@ -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>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<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>
</ul>
{% endif %}
......@@ -47,34 +55,49 @@
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
dashboard
</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>
Book List
</a>
<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>
Member List
</a>
<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>
Book Loan List
</a>
<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>
Librarian List
Book
</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">
<div class="sb-nav-link-icon"><i class="fas fa-book-open"></i></div>
Member
</a>
<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>
Book Loan
</a>
<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>
Librarian
</a>
<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>
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>
{% endif%}
{%else %}
<a class="nav-link" href="{% url 'login' %}" aria-expanded="false">
<div class="sb-nav-link-icon"><i class="fas fa-columns"></i></div>
Log in
</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>
register
Register Librarian
</a>
{% endif %}
</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 @@
<table id="datatablesSimple">
<thead >
<tr>
<th>Image</th>
<th>Title</th>
<th>Category</th>
<th>Author</th>
<th>Publisher</th>
<th>ISBN</th>
<th>Date Publish</th>
<th>Action</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Image</th>
<th>Title</th>
<th>Category</th>
<th>Author</th>
<th>Publisher</th>
<th>ISBN</th>
<th>Date Publish</th>
<th>Action</th>
</tr>
</tfoot>
<tbody>
{% for book in books %}
<tr>
<td>
{% if book.image %}
<img src="{{ book.image.url }}" width="100px" height="70px" alt="">
{% endif %}
</td>
<td>{{ book.title }}</td>
<td>{{ book.category.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.publisher }}</td>
<td>{{ book.isbn }}</td>
<td>{{ book.date_publish }}</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-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>
</tr>
{% endfor %}
......@@ -44,7 +52,7 @@
</table>
<div>
<a class="btn btn-primary col-1 mx-3" href="{% url 'book-new' %}" role="button">Add Book</a>
</div>
</div>
</div>
</div>
</div>
......
......@@ -50,9 +50,7 @@
</table>
<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 '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>
<a class="btn btn-primary col-2 mx-3" href="{% url 'book_loan_new' %}" role="button">Add Book Loan</a>
</div>
</div>
</div>
......
......@@ -9,17 +9,19 @@
<div class="card-body">
<form method="post" action="{% url 'book_loan_new' %}">
{% csrf_token %}
<div class="mb-3">
<div class="form-group mb-3">
<label for="id_book">Book:</label>
<select name="book" id="id_book" class="form-control" required>
<option selected>Select Book</option>
{% for book in books %}
<option value="{{ book.id }}">{{ book.title }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<div class="form-group mb-3">
<label for="id_member">Member:</label>
<select name="member" id="id_member" class="form-control" required>
<option selected>Select Member</option>
{% for member in members %}
<option value="{{ member.id }}">{{ member.name }}</option>
{% endfor %}
......@@ -30,6 +32,7 @@
<input type="date" name="due_date" id="id_due_date" class="form-control" required>
</div>
<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>
</div>
</div>
......
......@@ -42,7 +42,8 @@
<form method="post" action="{% url 'book_loan_edit' id=book_loan.id %}">
{% csrf_token %}
{{ 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>
</div>
......
......@@ -7,12 +7,20 @@
<div class="card">
<div class="card-header bg-primary text-white">Add Book</div>
<div class="card-body">
<form method="post" action="{% url 'book-new' %}">
<form method="post" action="{% url 'book-new' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="mb-3">
<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>
</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">
<label for="id_author" class="form-label">Author</label>
<input type="text" name="author" id="id_author" placeholder="Author" class="form-control" required>
......@@ -21,11 +29,20 @@
<label for="id_publisher" class="form-label">Publisher</label>
<input type="text" name="publisher" id="id_publisher" placeholder="Publisher" class="form-control" required>
</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">
<label for="id_isbn" class="form-label">ISBN</label>
<input type="text" name="isbn" id="id_isbn" placeholder="ISBN" class="form-control" required>
</div>
<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>
</div>
</div>
......@@ -34,12 +51,4 @@
</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%}
\ No newline at end of file
......@@ -7,11 +7,19 @@
<div class="card">
<div class="card-header bg-primary text-white">Edit Book</div>
<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 %}
<div class="mb-3">
<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 class="mb-3">
<label for="id_author" class="form-label">Author</label>
......@@ -21,11 +29,20 @@
<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>
</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">
<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>
</div>
<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>
</div>
</div>
......
......@@ -12,31 +12,42 @@
<thead >
<tr>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Name</th>
<th>Action</th>
</tr>
</tfoot>
<tbody>
{% for category in categories %}
<tr>
<td>{{ category.name }}</td>
<td>{{ category.name }}</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-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-secondary col-1 mx-3" href="{% url 'category_edit' pk=category.pk %}" role="button">Edit</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>
</tr>
{% endfor %}
</tbody>
</table>
<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>
<a class="btn btn-primary col-1 mx-3" href="{% url 'category_new' %}" role="button">Add Category</a>
</div>
</div>
</div>
</div>
{% 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 @@
<div class="card">
<div class="card-header bg-primary text-white">Edit Librarian</div>
<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 %}
<div class="mb-3">
<label for="id_name">Name:</label>
......@@ -15,24 +15,33 @@
</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>
<label for="id_lastname">Last Name:</label>
<input type="text" name="last_name" id="id_lastname" value="{{ librarian.last_name }}" placeholder="Last Name" 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>
<label for="id_address">Address:</label>
<textarea type="text" name="address" id="id_address" value="{{ librarian.address }}" placeholder="Address" class="form-control" required></textarea>
</div>
<div class="mb-3">
<label for="id_password">New Password:</label>
<input type="password" name="password1" id="id_password" placeholder="Password" class="form-control" required>
<label for="id_birthplace">Birth Place:</label>
<input type="text" name="birth_place" id="id_lastname" value="{{ librarian.birth_place }}" placeholder="Birth Place" 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>
<label for="id_datebirth">Birth date:</label>
<input type="date" name="date_birth" id="id_datebirth" value="{{ librarian.date_birth }}" placeholder="Birth Date" 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> -->
{{form.phone_number}}
</div>
<button type="submit" class="btn btn-primary" role="button">Save Changes</button>
</form>
</div>
......@@ -41,38 +50,15 @@
</div>
</div>
{% endblock content%}
<!-- <div style="text-align: center; margin-top: 50px;">
<h2>Edit Librarian</h2>
<form method="post" action="{% url 'librarian_edit' pk=librarian.id %}">
<h2>Edit</h2>
<form method="post" action="{% url 'librarian_edit' id=librarian.id %}">
{% csrf_token %}
<div class="mb-3">
<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>
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div> -->
\ No newline at end of file
</div> -->
{% endblock content%}
\ No newline at end of file
......@@ -19,6 +19,8 @@
<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>
<input type="checkbox" onclick="showPassword()"> Show Password
<br>
</div>
<button type="submit" class="btn btn-primary" role="button">Login</button>
</form>
......@@ -29,5 +31,17 @@
</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%}
......@@ -36,7 +36,7 @@
<td>{{ member.phone_number }}</td>
<td>
<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>
</tr>
{% 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 @@
</div>
<div class="mb-3">
<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 class="mb-3">
<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>
<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>
</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 @@
</div>
<div class="mb-3">
<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 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 Changes</button>
<a class="btn btn-warning col-2 mx-2" href="{% url 'member_list' %}"" role="button">Back</a>
</form>
</div>
</div>
......
......@@ -15,7 +15,6 @@
<th>Member Name</th>
<th>Loan Date</th>
<th>Due Date</th>
<th>Return Date</th>
<th>Overdue Date</th>
</tr>
</thead>
......@@ -25,7 +24,6 @@
<th>Member Name</th>
<th>Loan Date</th>
<th>Due Date</th>
<th>Return Date</th>
<th>Overdue Date</th>
</tr>
</tfoot>
......@@ -36,8 +34,7 @@
<td>{{ loan.member.name }}</td>
<td>{{ loan.loan_date }}</td>
<td>{{ loan.due_date }}</td>
<td>{{ loan.return_date }}</td>
<td>{{ loan.dead.days}} Days</td>
<td>{{ loan.dead}}</td>
</tr>
{% endfor %}
</tbody>
......
......@@ -10,8 +10,12 @@
<form method="post" action="{% url 'register' %}">
{% csrf_token %}
<div class="mb-3">
<label for="id_name" class="form-label">Name</label>
<input type="text" name="name" id="id_name" placeholder="Name" class="form-control" required>
<label for="id_name" class="form-label">First Name</label>
<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 class="mb-3">
<label for="id_username" class="form-label">Username</label>
......@@ -21,6 +25,18 @@
<label for="email" class="form-label">Email</label>
<input type="email" name="email" id="email" placeholder="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_password1" class="form-label">Password</label>
<input type="password" name="password1" id="id_password1" placeholder="Password" class="form-control" required>
......@@ -38,14 +54,13 @@
</div>
<!-- <div style="text-align: center; margin-top: 50px;">
<div style="text-align: center; margin-top: 50px;">
<h2>Create Account</h2>
<form method="post" action="{% url 'register' %}">
{% csrf_token %}
{{ user_form.as_p }}
{{ librarian_form.as_p }}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div> -->
</div>
{% 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.contrib.auth.views import LogoutView
from django.contrib.auth.views import LogoutView, LoginView
from .views import *
from django.views.generic import TemplateView, ListView
from django.views.generic import *
from django.conf.urls.static import static
urlpatterns = [
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('register/', register_view, name='register'),
path('dashboard/', dashboard, name='dashboard'),
path('librarian-registration/', librarian_registration, name='librarian_registration'),
path('librarians/', librarian_list, name='librarian_list'),
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('books/', book_list, name='book_list'),
path('books/add/', book_new, name='book_new'),
path('books/edit/<int:id>/', book_update, name='edit_book'),
path('books/', BookList.as_view(), name='book-list'),
path('books/detail/<int:pk>/', BookDetail.as_view(), name='book-detail'),
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/<int:pk>/delete/', BookDeleteView.as_view(), name='book-delete'),
path('book-loans/', book_loan_list, name='book_loan_list'),
path('book-loans/add/', book_loan_new, name='book_loan_new'),
......@@ -27,9 +32,13 @@ urlpatterns = [
# 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('bookloans/', BookLoanList.as_view(), name='bookloan-list'),
path('near-outstanding-loans/', near_outstanding_loans, name='near_outstanding_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/add/', member_new, name='member_new'),
path('member/edit/<int:id>/', edit_member, name='edit_member'),
......@@ -37,9 +46,20 @@ urlpatterns = [
path('librarian-login-history/', librarian_login_history, name='librarian_login_history'),
path("books2/", BookList.as_view(), name='book-list'),
path("books2/add/", BookCreateView.as_view(), name='book-new'),
path('update-usermember/', update_usermember, name='update-usermember'),
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('category/add/', CategoryCreateView.as_view(), name='category_new'),
path('category/edit/<int:pk>/', CategoryUpdateView.as_view(), name='category_edit'),
path('unauthorized/', unauthorized, name='unauthorized'),
]
]
\ No newline at end of file
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