mirror of
https://github.com/bugsink/bugsink.git
synced 2026-01-06 13:20:20 -06:00
Resend confirmation: implement (and offer as an option when re-signing up
This commit is contained in:
@@ -7,7 +7,7 @@ from django.contrib.auth import views as auth_views
|
||||
from alerts.views import debug_email as debug_alerts_email
|
||||
from users.views import debug_email as debug_users_email
|
||||
from bugsink.app_settings import get_settings
|
||||
from users.views import signup, confirm_email
|
||||
from users.views import signup, confirm_email, resend_confirmation
|
||||
|
||||
from .views import home, trigger_error, favicon
|
||||
|
||||
@@ -21,6 +21,7 @@ urlpatterns = [
|
||||
path('', home, name='home'),
|
||||
|
||||
path("accounts/signup/", signup, name="signup"),
|
||||
path("accounts/resend-confirmation/", resend_confirmation, name="resend_confirmation"),
|
||||
path("accounts/confirm-email/<str:token>/", confirm_email, name="confirm_email"),
|
||||
|
||||
path("accounts/login/", auth_views.LoginView.as_view(template_name="bugsink/login.html"), name="login"),
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="text-red-500 pt-1 px-2 text-sm">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% elif form.username.help_text %}
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.username.help_text }}</div>
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.username.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="text-red-500 pt-1 px-2 text-sm">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% elif form.password1.help_text %}
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.password1.help_text }}</div>
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.password1.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<div class="text-red-500 pt-1 px-2 text-sm">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% elif form.password2.help_text %}
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.password2.help_text }}</div>
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.password2.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import urllib.parse
|
||||
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
|
||||
from django.core.validators import EmailValidator
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.auth import password_validation
|
||||
from django.forms import ModelForm
|
||||
from django.utils.html import escape, mark_safe
|
||||
|
||||
|
||||
UserModel = get_user_model()
|
||||
@@ -30,6 +35,14 @@ class UserCreationForm(BaseUserCreationForm):
|
||||
model = UserModel
|
||||
fields = ("username",)
|
||||
|
||||
def clean_username(self):
|
||||
if UserModel.objects.filter(username=self.cleaned_data['username'], is_active=False).exists():
|
||||
raise ValidationError(mark_safe(
|
||||
'This email is already registered but not yet confirmed. Please check your email for the confirmation '
|
||||
'link or <b><a href="' + reverse("resend_confirmation") + "?email=" +
|
||||
urllib.parse.quote(escape(self.cleaned_data['username'])) + '">request it again</a></b>.'))
|
||||
return self.cleaned_data['username']
|
||||
|
||||
def _post_clean(self):
|
||||
# copy of django.contrib.auth.forms.UserCreationForm._post_clean; but with password1 instead of password2; I'd
|
||||
# say it's better UX to complain where the original error is made
|
||||
@@ -51,3 +64,7 @@ class UserCreationForm(BaseUserCreationForm):
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
class ResendConfirmationForm(forms.Form):
|
||||
email = forms.EmailField()
|
||||
|
||||
42
users/templates/users/resend_confirmation.html
Normal file
42
users/templates/users/resend_confirmation.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "barest_base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Resend confirmation · {{ site_title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="bg-cyan-100 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16" alt="Bugsink"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
<form method="post" action=".">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="text-lg mb-6 md:mb-8">
|
||||
<input name="email" type="text" class="{% if form.email.errors %}bg-red-100{% else %}bg-slate-200{% endif %} pl-4 py-2 md:py-4 focus:outline-none w-full" {% if form.email.value %}value="{{ form.email.value }}"{% endif %} placeholder="{{ form.email.label }}" />
|
||||
{% if form.email.errors %}
|
||||
{% for error in form.email.errors %}
|
||||
<div class="text-red-500 pt-1 px-2 text-sm">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% elif form.email.help_text %}
|
||||
<div class="text-gray-500 pt-1 px-2 text-sm">{{ form.email.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<button class="bg-slate-800 font-medium p-2 md:p-4 text-white uppercase w-full">Resend verification email</button>
|
||||
</form>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="{#{% url 'password_reset' TODO %}#}" class="text-slate-800">Forgot password?</a>
|
||||
<a href="{% url 'login' %}" class="float-right text-slate-800">Log in instead</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -8,7 +8,7 @@ from django.utils import timezone
|
||||
|
||||
from bugsink.app_settings import get_settings, CB_ANYBODY
|
||||
|
||||
from .forms import UserCreationForm
|
||||
from .forms import UserCreationForm, ResendConfirmationForm
|
||||
from .models import EmailVerification
|
||||
from .tasks import send_confirm_email
|
||||
|
||||
@@ -69,6 +69,24 @@ def confirm_email(request, token):
|
||||
return render(request, "users/email_confirmed.html")
|
||||
|
||||
|
||||
def resend_confirmation(request):
|
||||
if request.method == 'POST':
|
||||
form = ResendConfirmationForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
user = UserModel.objects.get(username=form.cleaned_data['email'])
|
||||
if user.is_active:
|
||||
raise Http404("This email is already confirmed.")
|
||||
|
||||
verification = EmailVerification.objects.create(user=user, email=user.username)
|
||||
send_confirm_email.delay(user.username, verification.token)
|
||||
return render(request, "users/confirm_email_sent.html", {"email": user.username})
|
||||
else:
|
||||
form = ResendConfirmationForm(data=request.GET)
|
||||
|
||||
return render(request, "users/resend_confirmation.html", {"form": form})
|
||||
|
||||
|
||||
DEBUG_CONTEXTS = {
|
||||
"confirm_email": {
|
||||
"site_title": get_settings().SITE_TITLE,
|
||||
|
||||
Reference in New Issue
Block a user