feat: moved users views to web app
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
{% extends 'theme/base.html' %}
|
||||
|
||||
{% block main %}
|
||||
<section class="bg-gray-50 dark:bg-gray-900">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
|
||||
<a href="#" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||
<img class="w-8 h-8 mr-2" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/logo.svg" alt="logo">
|
||||
Shoppy
|
||||
</a>
|
||||
|
||||
<div
|
||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||
Sign in to your account
|
||||
</h1>
|
||||
<form class="space-y-4 md:space-y-6" action="{% url 'users:login' %}" method="post">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<label for="{{ field.id_for_label }}"
|
||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ field.label }}
|
||||
</label>
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
|
||||
{# <div class="flex items-center justify-between">#}
|
||||
{# <div class="flex items-start">#}
|
||||
{# <div class="flex items-center h-5">#}
|
||||
{# <input id="remember" aria-describedby="remember" type="checkbox"#}
|
||||
{# class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800">#}
|
||||
{# </div>#}
|
||||
{# <div class="ml-3 text-sm">#}
|
||||
{# <label for="remember" class="text-gray-500 dark:text-gray-300">Remember me</label>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
{# <a href="#" class="text-sm font-medium text-primary-600 hover:underline dark:text-primary-500">#}
|
||||
{# Forgot password?#}
|
||||
{# </a>#}
|
||||
{# </div>#}
|
||||
<button
|
||||
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
|
||||
Login
|
||||
</button>
|
||||
<p class="text-sm font-light text-gray-500 dark:text-gray-400">
|
||||
Don’t have an account yet?
|
||||
<a href="#" class="font-medium text-primary-600 hover:underline dark:text-primary-500">Sign up</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,45 +0,0 @@
|
||||
{% extends 'base/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<section class="bg-gray-50 dark:bg-gray-900">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a href="#" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||
<img class="w-8 h-8 mr-2" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/logo.svg" alt="logo">
|
||||
Flowbite
|
||||
</a>
|
||||
<div class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||
Create and account
|
||||
</h1>
|
||||
<form class="space-y-4 md:space-y-6" action="#">
|
||||
<div>
|
||||
<label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
|
||||
<input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
|
||||
<input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="confirm-password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Confirm password</label>
|
||||
<input type="confirm-password" name="confirm-password" id="confirm-password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center h-5">
|
||||
<input id="terms" aria-describedby="terms" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800" required="">
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="terms" class="font-light text-gray-500 dark:text-gray-300">I accept the <a class="font-medium text-primary-600 hover:underline dark:text-primary-500" href="#">Terms and Conditions</a></label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Create an account</button>
|
||||
<p class="text-sm font-light text-gray-500 dark:text-gray-400">
|
||||
Already have an account? <a href="#" class="font-medium text-primary-600 hover:underline dark:text-primary-500">Login here</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,42 +0,0 @@
|
||||
{% extends 'base/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section class="bg-gray-50 dark:bg-gray-900">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a href="#" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||
<img class="w-8 h-8 mr-2" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/logo.svg" alt="logo">
|
||||
Shoppy
|
||||
</a>
|
||||
<div class="w-full p-6 bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md dark:bg-gray-800 dark:border-gray-700 sm:p-8">
|
||||
<h2 class="mb-1 text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||
Change Password
|
||||
</h2>
|
||||
<form class="mt-4 space-y-4 lg:mt-5 md:space-y-5" action="#">
|
||||
<div>
|
||||
<label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
|
||||
<input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">New Password</label>
|
||||
<input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="confirm-password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Confirm password</label>
|
||||
<input type="confirm-password" name="confirm-password" id="confirm-password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center h-5">
|
||||
<input id="newsletter" aria-describedby="newsletter" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800" required="">
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="newsletter" class="font-light text-gray-500 dark:text-gray-300">I accept the <a class="font-medium text-primary-600 hover:underline dark:text-primary-500" href="#">Terms and Conditions</a></label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Reset passwod</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,98 +0,0 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class TestLogin(APITestCase):
|
||||
def setUp(self) -> None:
|
||||
self.password = "theonering"
|
||||
self.user = User.objects.create(
|
||||
username="sauron",
|
||||
email="sauron@mordor.middleearth",
|
||||
)
|
||||
|
||||
self.user.set_password(self.password)
|
||||
self.user.save()
|
||||
|
||||
def test_login(self):
|
||||
response = self.client.post(
|
||||
reverse("users:login"),
|
||||
{
|
||||
"username": self.user.username,
|
||||
"password": self.password,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
def test_login_get(self):
|
||||
response = self.client.get(reverse("users:login"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
def test_login_already_logged_in(self):
|
||||
response = self.client.post(
|
||||
reverse("users:login"),
|
||||
{
|
||||
"username": self.user.username,
|
||||
"password": self.password,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
response = self.client.get(reverse("users:login"))
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
def test_login_failed(self):
|
||||
response = self.client.post(
|
||||
reverse("users:login"),
|
||||
{
|
||||
"username": self.user.username,
|
||||
"password": "wrongpassword",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_login_then_logout(self):
|
||||
response = self.client.post(
|
||||
reverse("users:login"),
|
||||
{
|
||||
"username": self.user.username,
|
||||
"password": self.password,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
response = self.client.post(reverse("users:logout"))
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
def test_logout_already_logged_out(self):
|
||||
response = self.client.post(reverse("users:logout"))
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
def test_login_then_get_logout(self):
|
||||
response = self.client.post(
|
||||
reverse("users:login"),
|
||||
{
|
||||
"username": self.user.username,
|
||||
"password": self.password,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
|
||||
response = self.client.get(reverse("users:logout"))
|
||||
assert response.status_code == status.HTTP_302_FOUND
|
||||
assert response.url == reverse("web:index")
|
||||
+1
-8
@@ -1,13 +1,6 @@
|
||||
from django.urls import path
|
||||
|
||||
from users.views import login, logout, register, reset_password
|
||||
|
||||
app_name = "users"
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("login/", login, name="login"),
|
||||
path("logout/", logout, name="logout"),
|
||||
path("register/", register, name="register"),
|
||||
path("reset-password/", reset_password, name="reset-password"),
|
||||
]
|
||||
urlpatterns = []
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
from django.contrib.auth import login as login_user
|
||||
from django.contrib.auth import logout as logout_user
|
||||
from django.shortcuts import redirect, render, reverse
|
||||
from django.views.generic import TemplateView, View
|
||||
|
||||
from users.forms import LoginForm
|
||||
|
||||
|
||||
class RedirectionMixin:
|
||||
redirect_to = ""
|
||||
|
||||
def get_redirection(self):
|
||||
return reverse(self.redirect_to)
|
||||
|
||||
|
||||
class LoginView(View, RedirectionMixin):
|
||||
template_name = "users/login.html"
|
||||
redirect_to = "web:index"
|
||||
login_form_class = LoginForm
|
||||
|
||||
def get_login_form(self, request):
|
||||
return self.login_form_class(data=request.POST)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.user.is_authenticated:
|
||||
return redirect(self.get_redirection())
|
||||
|
||||
login_form = self.login_form_class()
|
||||
return render(request, self.template_name, {"form": login_form})
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
login_form = self.get_login_form(request)
|
||||
|
||||
if login_form.is_valid():
|
||||
login_user(request, login_form.get_user())
|
||||
|
||||
if not login_form.cleaned_data.get('remember_me'):
|
||||
request.session.set_expiry(0)
|
||||
|
||||
return redirect(self.get_redirection())
|
||||
|
||||
return render(request, self.template_name, {"form": login_form}, status=400)
|
||||
|
||||
|
||||
class LogoutView(View, RedirectionMixin):
|
||||
redirect_to = "web:index"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
logout_user(request)
|
||||
return redirect(self.get_redirection())
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
logout_user(request)
|
||||
return redirect(self.get_redirection())
|
||||
|
||||
|
||||
class RegisterView(TemplateView):
|
||||
template_name = "users/register.html"
|
||||
|
||||
|
||||
class ResetPasswordView(TemplateView):
|
||||
template_name = "users/reset-password.html"
|
||||
|
||||
|
||||
login = LoginView.as_view()
|
||||
logout = LogoutView.as_view()
|
||||
register = RegisterView.as_view()
|
||||
reset_password = ResetPasswordView.as_view()
|
||||
|
||||
Reference in New Issue
Block a user