feat: Add reset password (#5)
Co-authored-by: Leonardo Hakim <leohakim@gmail.com> Reviewed-on: #5 Co-authored-by: Leo Hakim <leo@noreply.git.negromate.rocks> Co-committed-by: Leo Hakim <leo@noreply.git.negromate.rocks>
This commit is contained in:
parent
9e77205fed
commit
49154ab3a5
|
@ -3,3 +3,4 @@
|
||||||
/django_gas.egg-info
|
/django_gas.egg-info
|
||||||
/.coverage
|
/.coverage
|
||||||
/htmlcov
|
/htmlcov
|
||||||
|
*.pyc
|
||||||
|
|
|
@ -8,5 +8,9 @@ urlpatterns = [
|
||||||
path('login/', views.GASLoginView.as_view(), name='login'),
|
path('login/', views.GASLoginView.as_view(), name='login'),
|
||||||
path('logout/', logout_then_login, {'login_url': 'gas:login'}, name='logout'),
|
path('logout/', logout_then_login, {'login_url': 'gas:login'}, name='logout'),
|
||||||
path('change-password/', views.GASPasswordChangeView.as_view(), name='change_password'),
|
path('change-password/', views.GASPasswordChangeView.as_view(), name='change_password'),
|
||||||
|
path('reset-password-confirm/<uidb64>/<token>/', views.GASPasswordResetConfirmView.as_view(), name='password_reset_confirm'),
|
||||||
|
path('reset-password-confirm/done/', views.GASPasswordResetCompleteView.as_view(), name='password_reset_complete'),
|
||||||
|
path('reset-password/done/', views.GASPasswordResetDoneView.as_view(), name='password_reset_done'),
|
||||||
|
path('reset-password/', views.GASPasswordResetView.as_view(), name='reset_password'),
|
||||||
path('', views.Index.as_view(), name='index'),
|
path('', views.Index.as_view(), name='index'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,45 +1,72 @@
|
||||||
from django.contrib.auth.views import LoginView, PasswordChangeView
|
from django.contrib.auth.views import (
|
||||||
|
LoginView,
|
||||||
|
PasswordChangeView,
|
||||||
|
PasswordResetConfirmView,
|
||||||
|
PasswordResetDoneView,
|
||||||
|
PasswordResetView,
|
||||||
|
)
|
||||||
from django.shortcuts import resolve_url
|
from django.shortcuts import resolve_url
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
from gas import gas_settings
|
||||||
from gas.views import GASMixin
|
from gas.views import GASMixin
|
||||||
|
|
||||||
from gas import gas_settings
|
|
||||||
|
class GASPasswordChangeView(GASMixin, PasswordChangeView):
|
||||||
|
template_name = "gas/base_form.html"
|
||||||
|
success_url = reverse_lazy("gas:index")
|
||||||
|
continue_url = reverse_lazy("gas:change_password")
|
||||||
|
title = _("Change your password")
|
||||||
|
success_message = _("Password changed.")
|
||||||
|
|
||||||
|
|
||||||
class GASLoginView(LoginView):
|
class Index(GASMixin, TemplateView):
|
||||||
|
main_menu = "index"
|
||||||
|
template_name = "gas/index.html"
|
||||||
|
roles = ("staff",)
|
||||||
|
|
||||||
|
|
||||||
|
class GASContextMixin:
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
css = gas_settings.MEDIA["css"]
|
||||||
|
javascript = gas_settings.MEDIA["js"]
|
||||||
|
if gas_settings.EXTRA_MEDIA:
|
||||||
|
css = css + gas_settings.EXTRA_MEDIA.get("css", [])
|
||||||
|
javascript = javascript + gas_settings.EXTRA_MEDIA.get("js", [])
|
||||||
|
ctx.update(
|
||||||
|
{
|
||||||
|
"logo_static_url": gas_settings.LOGO,
|
||||||
|
"css": css,
|
||||||
|
"js": javascript,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class GASLoginView(GASContextMixin, LoginView):
|
||||||
template_name = "gas/login.html"
|
template_name = "gas/login.html"
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
url = self.get_redirect_url()
|
url = self.get_redirect_url()
|
||||||
return url or resolve_url('gas:index')
|
return url or resolve_url("gas:index")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
ctx = super().get_context_data(**kwargs)
|
|
||||||
css = gas_settings.MEDIA['css']
|
|
||||||
javascript = gas_settings.MEDIA['js']
|
|
||||||
if gas_settings.EXTRA_MEDIA:
|
|
||||||
css = css + gas_settings.EXTRA_MEDIA.get('css', [])
|
|
||||||
javascript = javascript + gas_settings.EXTRA_MEDIA.get('js', [])
|
|
||||||
ctx.update({
|
|
||||||
'logo_static_url': gas_settings.LOGO,
|
|
||||||
'css': css,
|
|
||||||
'js': javascript,
|
|
||||||
})
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
|
|
||||||
class GASPasswordChangeView(GASMixin, PasswordChangeView):
|
class GASPasswordResetView(GASContextMixin, PasswordResetView):
|
||||||
template_name = 'gas/base_form.html'
|
template_name = "gas/reset.html"
|
||||||
success_url = reverse_lazy('gas:index')
|
email_template_name = "email/password_reset_email.html"
|
||||||
continue_url = reverse_lazy('gas:change_password')
|
success_url = reverse_lazy("gas:password_reset_done")
|
||||||
title = _('Change your password')
|
|
||||||
success_message = _('Password changed.')
|
|
||||||
|
|
||||||
|
|
||||||
class Index(GASMixin, TemplateView):
|
class GASPasswordResetDoneView(GASContextMixin, PasswordResetDoneView):
|
||||||
main_menu = 'index'
|
template_name = "gas/reset_done.html"
|
||||||
template_name = "gas/index.html"
|
|
||||||
roles = ('staff',)
|
|
||||||
|
class GASPasswordResetConfirmView(GASContextMixin, PasswordResetConfirmView):
|
||||||
|
template_name = "gas/reset_confirm.html"
|
||||||
|
success_url = reverse_lazy("gas:password_reset_complete")
|
||||||
|
|
||||||
|
|
||||||
|
class GASPasswordResetCompleteView(GASContextMixin, TemplateView):
|
||||||
|
template_name = "gas/reset_complete.html"
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% blocktranslate %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% translate "Please go to the following page and choose a new password:" %}
|
||||||
|
{% block reset_link %}
|
||||||
|
{{ protocol }}://{{ domain }}{% url 'gas:password_reset_confirm' uidb64=uid token=token %}
|
||||||
|
{% endblock %}
|
||||||
|
{% translate 'Your username, in case you’ve forgotten:' %} {{ user.get_username }}
|
||||||
|
|
||||||
|
{% translate "Thanks for using our site!" %}
|
||||||
|
|
||||||
|
{% blocktranslate %}The {{ site_name }} team{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% endautoescape %}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{% load i18n static form_tags %}<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>{{ gas_title }} {% trans "Login" %}</title>
|
||||||
|
{% for cssfile in css %}
|
||||||
|
<link href="{% static cssfile %}" rel="stylesheet" type="text/css" />
|
||||||
|
{% endfor %}
|
||||||
|
</head>
|
||||||
|
<body id="login">
|
||||||
|
<p>{% translate 'Forgotten your password? Enter your email address below, and we’ll email instructions for setting a new one.' %}</p>
|
||||||
|
<form action="." method="POST">{% csrf_token %}
|
||||||
|
{% form_errors form %}
|
||||||
|
{% form_field form.email %}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
<button type="submit">{% trans "Reset my password" %}</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% load i18n static form_tags %}<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>{{ gas_title }} {% trans "Login" %}</title>
|
||||||
|
{% for cssfile in css %}
|
||||||
|
<link href="{% static cssfile %}" rel="stylesheet" type="text/css" />
|
||||||
|
{% endfor %}
|
||||||
|
</head>
|
||||||
|
<body id="login">
|
||||||
|
<p>{% translate 'Your password was changed.' %}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
{% load i18n static form_tags %}<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>{{ gas_title }} {% trans "Login" %}</title>
|
||||||
|
{% for cssfile in css %}
|
||||||
|
<link href="{% static cssfile %}" rel="stylesheet" type="text/css" />
|
||||||
|
{% endfor %}
|
||||||
|
</head>
|
||||||
|
<body id="login">
|
||||||
|
{% if validlink %}
|
||||||
|
<p>{% translate "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
|
||||||
|
<form action="." method="POST">{% csrf_token %}
|
||||||
|
<input class="hidden" autocomplete="username" value="{{ form.user.get_username }}">
|
||||||
|
{% form_errors form %}
|
||||||
|
{% form_field form.new_password1 %}
|
||||||
|
{% form_field form.new_password2 %}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
<button type="submit">{% trans "Change my password" %}</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<p>{% translate "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% load i18n static form_tags %}<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>{{ gas_title }} {% trans "Login" %}</title>
|
||||||
|
{% for cssfile in css %}
|
||||||
|
<link href="{% static cssfile %}" rel="stylesheet" type="text/css" />
|
||||||
|
{% endfor %}
|
||||||
|
</head>
|
||||||
|
<body id="login">
|
||||||
|
<p>{% translate 'We’ve emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.' %}</p>
|
||||||
|
<p>{% translate 'If you don’t receive an email, please make sure you’ve entered the address you registered with, and check your spam folder.' %}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -3,28 +3,58 @@ from django.urls import reverse
|
||||||
|
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
|
|
||||||
from gas.gas.core.views import GASLoginView
|
|
||||||
|
|
||||||
|
|
||||||
class GASLoginTestCase(TestCase):
|
class GASLoginTestCase(TestCase):
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
client = Client()
|
client = Client()
|
||||||
response = client.get(reverse('gas:login'))
|
response = client.get(reverse("gas:login"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
class IndexTestCase(TestCase):
|
class IndexTestCase(TestCase):
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
admin_user = baker.make(
|
admin_user = baker.make(
|
||||||
'auth.User',
|
"auth.User",
|
||||||
username='admin',
|
username="admin",
|
||||||
is_superuser=True,
|
is_superuser=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
client = Client()
|
client = Client()
|
||||||
response = client.get(reverse('gas:index'))
|
response = client.get(reverse("gas:index"))
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
client.force_login(admin_user)
|
client.force_login(admin_user)
|
||||||
response = client.get(reverse('gas:index'))
|
response = client.get(reverse("gas:index"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class GASPasswordResetViewTestCase(TestCase):
|
||||||
|
def test_load(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get(reverse("gas:reset_password"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, "gas/reset.html")
|
||||||
|
|
||||||
|
|
||||||
|
class GASPasswordResetDoneViewTestCase(TestCase):
|
||||||
|
def test_load(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get(reverse("gas:password_reset_done"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, "gas/reset_done.html")
|
||||||
|
|
||||||
|
|
||||||
|
class GASPasswordResetConfirmViewTestCase(TestCase):
|
||||||
|
def test_load(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get(reverse("gas:password_reset_confirm", kwargs={"uidb64": "uidb64", "token": "token"}))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, "gas/reset_confirm.html")
|
||||||
|
|
||||||
|
|
||||||
|
class GASPasswordResetCompleteViewTestCase(TestCase):
|
||||||
|
def test_load(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get(reverse("gas:password_reset_complete"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, "gas/reset_complete.html")
|
||||||
|
|
Loading…
Reference in New Issue