Commit 9a5d21c0 authored by Ilham Maulana's avatar Ilham Maulana 💻

feat: librarian authentication

parent cb812483
......@@ -71,6 +71,8 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
# local
"users.middleware.AuthMiddleware",
]
ROOT_URLCONF = "config.urls"
......
......@@ -19,7 +19,15 @@ from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.auth.views import LogoutView
from dashboard.views import UpcomingLoanView, OverduedLoanView
from users.views import (
LibrarianLoginView,
LibrarianLogoutView,
LibrarianSignUpView,
LibrarianResetPassword,
)
urlpatterns = [
# local
......@@ -30,6 +38,15 @@ urlpatterns = [
path("book-loans/", include("loans.urls")),
path("upcoming-loans/", UpcomingLoanView.as_view(), name="upcoming_loans"),
path("overdued-loans/", OverduedLoanView.as_view(), name="overdued_loans"),
# auth
path("auth/login/", LibrarianLoginView.as_view(), name="librarian_login"),
path("auth/logout/", LibrarianLogoutView.as_view(), name="librarian_logout"),
path("auth/sign-up/", LibrarianSignUpView.as_view(), name="librarian_logout"),
path(
"auth/forgot-password/",
LibrarianResetPassword.as_view(),
name="reset_password",
),
# api
path("api/v1/", include("api.urls"), name="API_V1"),
# 3rd party
......
......@@ -14,7 +14,7 @@
>
<a
class="w-100 btn btn-outline-primary border-white text-white text-start"
href="/auth/logout/{{ user.id }}/"
href="/logout/"
><i class="bi bi-box-arrow-left"></i> logout</a
>
</div>
......
from django import forms
from users.models import User
from django.contrib.auth import password_validation
from django.contrib.auth.forms import (
UserCreationForm,
AuthenticationForm,
PasswordResetForm,
UsernameField,
)
class UserForm(forms.ModelForm):
......@@ -42,3 +49,84 @@ class UserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.fields["password"].required = False
class SignUpForm(UserCreationForm):
password1 = forms.CharField(
label=("Password"),
strip=False,
widget=forms.PasswordInput(
attrs={
"placeholder": "Password",
"autocomplete": "new-password",
"class": "form-control my-4",
}
),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=("Password confirmation"),
widget=forms.PasswordInput(
attrs={
"placeholder": "Password confirmation",
"autocomplete": "new-password",
"class": "form-control my-4",
}
),
strip=False,
help_text=("Enter the same password as before, for verification."),
)
class Meta:
model = User
fields = ["username", "password1", "password2"]
widgets = {
"username": forms.TextInput(
attrs={
"placeholder": "Username",
"class": "form-control my-4",
}
),
}
class LoginForm(AuthenticationForm):
username = UsernameField(
widget=forms.TextInput(
attrs={
"placeholder": "Username",
"autofocus": True,
"class": "form-control",
}
)
)
password = forms.CharField(
label=("Password"),
strip=False,
widget=forms.PasswordInput(
attrs={
"placeholder": "Password",
"autocomplete": "current-password",
"class": "form-control",
}
),
)
class Meta:
model = User
fields = ["username", "password"]
class ForgotPasswordForm(PasswordResetForm):
email = forms.EmailField(
label=("Email"),
max_length=254,
widget=forms.EmailInput(
attrs={
"placeholder": "Email",
"autocomplete": "email",
"class": "form-control",
}
),
)
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponseRedirect
class AuthMiddleware(MiddlewareMixin):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if not request.user.is_authenticated and request.path.startswith("/dashboard/"):
return HttpResponseRedirect("/auth/login")
elif request.user.is_authenticated and request.path.startswith("/auth/"):
return HttpResponseRedirect("/dashboard/")
else:
return response
{% extends "base.html" %} {% block content %}
<main
style="min-height: 100vh"
class="w-100 h-100 bg-body-secondary d-flex justify-content-center align-items-center"
>
<form
method="POST"
class="card gap-3 d-flex w-25 p-4 rounded-4 shadow"
>
<h1 class="h3 text-center mb-4">Forgot Password</h1>
{% csrf_token %}
{{ form }}
<button
type="submit"
id="submit_reset_password"
class="btn btn-primary my-2 rounded-5"
>
Reset Password
</button>
<a href="/auth/login/" class="text-center my-2">Back to Login</a>
</form>
</main>
{% endblock content %}
\ No newline at end of file
{% extends "base.html" %} {% block content %}
<main
style="min-height: 100vh"
class="w-100 h-100 bg-body-secondary d-flex justify-content-center align-items-center"
>
<form
method="POST"
class="card gap-3 d-flex w-25 p-4 rounded-4 shadow"
>
<h1 class="h3 text-center mb-4">Login</h1>
{% csrf_token %}
{{ form }}
<button
type="submit"
id="submit-login"
class="btn btn-primary my-2 rounded-5"
>
Login
</button>
<div class="d-flex flex-column align-items-center">
<p class="my-2">
Don't have an account? <a href="/auth/sign-up">Sign Up</a>
</p>
<a href="/auth/forgot-password/" class="my-2">Forgot password</a>
</div>
</form>
</main>
{% endblock content %}
\ No newline at end of file
{% extends "base.html" %} {% block content %}
<main
style="min-height: 100vh"
class="w-100 h-100 bg-body-secondary d-flex justify-content-center align-items-center"
>
<form
method="POST"
class="card gap-2 w-25 p-4 rounded-4 shadow"
>
<h1 class="h3 text-center mb-4">Sign Up</h1>
{% csrf_token %}
{{ form }}
<button
type="submit"
id="submit-sign-up"
class="btn btn-primary my-2 rounded-5"
>
Sign Up
</button>
<div class="d-flex flex-column align-items-center">
{% if error_message %}
<p class="alert alert-warning small" role="alert">
<i class="bi bi-exclamation-circle"></i> {{ error_message }}
</p>
{% endif %}
<p class="my-2">
Already have an account? <a href="/auth/login">Login</a>
</p>
</div>
</form>
</main>
{% endblock content %}
\ No newline at end of file
from django.db.models import Q
from django.views import generic
from django.contrib.auth import logout
from django.http import HttpResponseRedirect
from django.contrib.auth.views import LoginView, PasswordResetView
from users.models import Librarian, Member
from users.forms import UserForm, User
from users.forms import UserForm, User, LoginForm, SignUpForm, ForgotPasswordForm
class UserListView(generic.ListView):
......@@ -100,12 +104,12 @@ class LibrarianCreateView(UserCreateView):
class LibrarianUpdateView(UserUpdateView):
model = Librarian
success_url = "/dashboard/librarians"
success_url = "/users/librarians"
class LibrarianDeleteView(UserDeleteView):
model = Librarian
success_url = "/dashboard/librarians"
success_url = "/users/librarians"
class MemberListView(UserListView):
......@@ -116,7 +120,7 @@ class MemberListView(UserListView):
class MemberCreateView(UserCreateView):
model = User
success_url = "/dashboard/members/"
success_url = "/users/members/"
def post(self, request, *args, **kwargs):
form = self.get_form()
......@@ -131,9 +135,72 @@ class MemberCreateView(UserCreateView):
class MemberUpdateView(UserUpdateView):
model = Member
success_url = "/dashboard/members"
success_url = "/users/members"
class MemberDeleteView(UserDeleteView):
model = Member
success_url = "/dashboard/members"
success_url = "/users/members"
class LibrarianLoginView(LoginView):
form_class = LoginForm
template_name = "librarians/login.html"
redirect_authenticated_user = "/dashboard/"
def post(self, request, *args, **kwargs):
form = self.get_form()
context = self.get_context_data()
if form.is_valid():
username = form.data.get("username")
user = User.objects.get(username=username)
if not user.is_staff:
context["error_message"] = "Access Denie, account is not staff"
return self.form_invalid(form)
return self.form_valid(form)
else:
return self.form_invalid(form)
class LibrarianLogoutView(generic.TemplateView):
success_url = "/auth/login/"
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if request.user.is_authenticated:
logout(request)
return HttpResponseRedirect(self.success_url)
return self.render_to_response(context)
class LibrarianSignUpView(generic.FormView):
form_class = SignUpForm
template_name = "librarians/sign_up.html"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid:
username = form.data.get("username")
email = form.data.get("email")
password = form.data.get("password")
user = User.objects.create_user(
username=username, email=email, password=password
)
Librarian.objects.create(user=user)
return self.form_valid(form)
else:
return self.form_invalid(form)
class LibrarianResetPassword(PasswordResetView):
form_class = ForgotPasswordForm
template_name = "librarians/forgot_password.html"
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