From 0fd2396bd72b1a5eb12893a2a01896d8926a84a9 Mon Sep 17 00:00:00 2001 From: Walter Lorenzetti Date: Mon, 6 Nov 2023 10:41:33 +0100 Subject: [PATCH] Username recovery (#641) * Add case "graduatedSymbol" to getlegendgraphic filter. * Start integration of django_registration. * Add registration settings. Add sign up link to login page. * Refactoring login/rest_password template structure. * Add django_registration templates required. * Base registration two-step workflow. * Add django-registration to requirements. * Add is_active management. * Ads reCAPTCHA, close #597. * Add reCAPTCHA to reset password form. * Add reCAPTCHA to registration form. * Add 'other_info' field to userdata model. * Add 'first_name', 'last_name' and 'other_info' to registration form. * Add 'registration_intro' to GeneralSuiteData model. * Add 'registration_intro' to general suite data info form. * Add 'registration_intro' context to registration form page. * Make translatable 'registration_intro'. * Registration intro management. * Add save of 'other_info' userdata property. * Send email to administrator if REGISTRATION_ACTIVE_BY_ADMIN is True. * Introduce 'registered' and 'activated_by_admin' userdata model properties. * Send email to user after activation by administrator. * Refine * Check for testing. * Fix send email on activation by administrator for only registered users. * :globe_with_meridians: Add _it_ translation. * Change position of registration information message inside the registration form page. * Change version for development state. * Add check for anonymous user inside the registration_allowed method. * Adding test for registration workflow. * Add test for registration view. * Change override_settings parameters for tests. * Change override_settings parameters for tests. * Change override_settings parameters for tests. * Recaptcha form element styling. * Start create form for recovery username. * Add workflow for username recovery. * Fix send email to administrators. --------- Co-authored-by: wlorenzetti --- g3w-admin/base/urls.py | 19 +++++++++- g3w-admin/templates/login.html | 12 ++++++ .../registration/password_reset_form.html | 5 +++ .../registration/username_recovery_done.html | 12 ++++++ .../registration/username_recovery_email.html | 10 +++++ .../registration/username_recovery_form.html | 37 +++++++++++++++++++ .../username_recovery_subject.txt | 3 ++ g3w-admin/usersmanage/forms.py | 3 +- g3w-admin/usersmanage/views.py | 26 ++++++++++++- 9 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 g3w-admin/templates/registration/username_recovery_done.html create mode 100644 g3w-admin/templates/registration/username_recovery_email.html create mode 100644 g3w-admin/templates/registration/username_recovery_form.html create mode 100644 g3w-admin/templates/registration/username_recovery_subject.txt diff --git a/g3w-admin/base/urls.py b/g3w-admin/base/urls.py index e7615a6e4..4f6ff7614 100644 --- a/g3w-admin/base/urls.py +++ b/g3w-admin/base/urls.py @@ -21,7 +21,11 @@ G3WResetPasswordForm, G3WRegistrationForm ) -from usersmanage.views import UserRegistrationView +from usersmanage.views import ( + UserRegistrationView, + UsernameRecoveryView, + UsernameRecoveryDoneView +) from ajax_select import urls as ajax_select_urls from sitetree.sitetreeapp import register_i18n_trees @@ -164,6 +168,7 @@ ############################################################# # PASSWORD RESET (user password reset by email) +# USERNAME RECOVERY (username recovery by email) ############################################################# if settings.RESET_USER_PASSWORD: urlpatterns += [ @@ -200,6 +205,18 @@ auth.views.PasswordResetCompleteView.as_view(extra_context=extra_context_login_page), name='password_reset_complete' ), + path( + 'username_recovery/', + UsernameRecoveryView.as_view( + extra_context=extra_context_login_page + ), + name='username_recovery' + ), + path( + 'username_recovery/done/', + UsernameRecoveryDoneView.as_view(extra_context=extra_context_login_page), + name='username_recovery_done' + ), ] ############################################################# diff --git a/g3w-admin/templates/login.html b/g3w-admin/templates/login.html index 47c817c89..e4c2b1839 100644 --- a/g3w-admin/templates/login.html +++ b/g3w-admin/templates/login.html @@ -44,6 +44,18 @@

{% trans 'LOGIN ERROR' %}!

{% trans 'Forgot your password?' %} + + {% endif %} + {% if SETTINGS.REGISTRATION_OPEN %} + {% endif %} {% if SETTINGS.REGISTRATION_OPEN %}
diff --git a/g3w-admin/templates/registration/password_reset_form.html b/g3w-admin/templates/registration/password_reset_form.html index 77abfcc02..5f81d18fc 100644 --- a/g3w-admin/templates/registration/password_reset_form.html +++ b/g3w-admin/templates/registration/password_reset_form.html @@ -8,7 +8,12 @@

{% trans 'LOGIN ERROR' %}!

+ {% if form.errors.email %} {% trans 'Email no present into database' %} + {% endif %} + {% if form.errors.captcha %} + {% trans 'Checking the CAPTCHA is required' %} + {% endif %}
{% endif %}
diff --git a/g3w-admin/templates/registration/username_recovery_done.html b/g3w-admin/templates/registration/username_recovery_done.html new file mode 100644 index 000000000..bd10acdce --- /dev/null +++ b/g3w-admin/templates/registration/username_recovery_done.html @@ -0,0 +1,12 @@ +{% extends "base_login.html" %} +{% load static %} +{% load i18n %} + +{% block login_page_box_body %} + +{% endblock %} \ No newline at end of file diff --git a/g3w-admin/templates/registration/username_recovery_email.html b/g3w-admin/templates/registration/username_recovery_email.html new file mode 100644 index 000000000..60167c146 --- /dev/null +++ b/g3w-admin/templates/registration/username_recovery_email.html @@ -0,0 +1,10 @@ +{% load i18n %}{% autoescape off %} +{% blocktranslate %}You're receiving this email because you requested a username recovery for your user account at {{ site_name }}.{% endblocktranslate %} + +{% translate "Your username is:" %} + +{{ user.get_username }} + +{{ SETTINGS.REGISTRATION_EMAIL_BODY_SIGN }} + +{% endautoescape %} diff --git a/g3w-admin/templates/registration/username_recovery_form.html b/g3w-admin/templates/registration/username_recovery_form.html new file mode 100644 index 000000000..711f48611 --- /dev/null +++ b/g3w-admin/templates/registration/username_recovery_form.html @@ -0,0 +1,37 @@ +{% extends "base_login.html" %} +{% load static %} +{% load i18n %} + +{% block login_page_box_body %} +
+{% endblock %} \ No newline at end of file diff --git a/g3w-admin/templates/registration/username_recovery_subject.txt b/g3w-admin/templates/registration/username_recovery_subject.txt new file mode 100644 index 000000000..f7a634a47 --- /dev/null +++ b/g3w-admin/templates/registration/username_recovery_subject.txt @@ -0,0 +1,3 @@ +{% load i18n %}{% autoescape off %} +{{ SETTINGS.REGISTRATION_EMAIL_SUBJECT_PREFIX}} {% blocktranslate %}Username recovery on {{ site_name }}{% endblocktranslate %} +{% endautoescape %} \ No newline at end of file diff --git a/g3w-admin/usersmanage/forms.py b/g3w-admin/usersmanage/forms.py index f0850fbe8..b341f517b 100644 --- a/g3w-admin/usersmanage/forms.py +++ b/g3w-admin/usersmanage/forms.py @@ -851,7 +851,8 @@ def clean_email(self): - +class G3WUsernameRecoveryForm(G3WreCaptchaFormMixin, PasswordResetForm): + pass diff --git a/g3w-admin/usersmanage/views.py b/g3w-admin/usersmanage/views.py index 56ffefdca..d767994e8 100644 --- a/g3w-admin/usersmanage/views.py +++ b/g3w-admin/usersmanage/views.py @@ -15,6 +15,8 @@ from django.contrib.auth.models import Group from django.contrib.sites.shortcuts import get_current_site from django.template.loader import render_to_string +from django.contrib.auth.views import PasswordResetView, PasswordResetDoneView +from django.urls import reverse_lazy from guardian.shortcuts import assign_perm, get_objects_for_user from guardian.decorators import permission_required_or_403 from django_registration.backends.activation import views as registration_views @@ -335,11 +337,33 @@ def send_admin_activation_email(self, user): request=self.request, ) + # Get email of every admin users (Admin Level 1 and Admin Level 2) + admins = User.objects.filter(is_superuser=True) + send_mail( subject, message, settings.DEFAULT_FROM_EMAIL, - ["to@example.com"], + [a.email for a in admins], fail_silently=False, ) + +class UsernameRecoveryView(PasswordResetView): + """ + A view to recovery username by email, follow the same logic of Password reset. + """ + + email_template_name = 'registration/username_recovery_email.html' + form_class = G3WUsernameRecoveryForm + subject_template_name = 'registration/username_recovery_subject.txt' + success_url = reverse_lazy('username_recovery_done') + template_name = 'registration/username_recovery_form.html' + title = _('Username recovery') + +class UsernameRecoveryDoneView(PasswordResetDoneView): + """ + View for show message to the end user of emailing username. + """ + template_name = 'registration/username_recovery_done.html' + title = _('Username sent')