diff --git a/core/views/user_registration.py b/core/views/user_registration.py index 27f6046..fc2aace 100644 --- a/core/views/user_registration.py +++ b/core/views/user_registration.py @@ -13,7 +13,8 @@ from troggle.parsers.users import register_user, get_encryptor, ENCRYPTED_DIR, U from troggle.parsers.people import troggle_slugify from troggle.core.utils import ( add_commit, -) + is_identified_user + ) """ This is the new individual user login registration, instead of everyone signing in as "expo". This will be useful for the kanban expo organisation tool. @@ -27,7 +28,7 @@ todo = """ class ExpoPasswordResetForm(PasswordResetForm): """Because we are using the Django-standard django.contrib.auth mechanisms, the way Django wants us to - modify them is to subclass their stuff and insert our extras in teh subclasses. This is completely + modify them is to subclass their stuff and insert our extras in the subclasses. This is completely unlike how the rest of troggle works because we avoid Class-based views. We avoid them because they are very hard to debug for newcomer programmers who don't know Django: the logic is spread out up a tree of preceding ancestor classes. @@ -89,21 +90,61 @@ def newregister(request, username=None): save_users(request, updated_user, email) return HttpResponseRedirect("/accounts/password_reset/") else: # GET - form = newregister_form(initial={"visible": "True"}) + form = newregister_form(initial={"visible-passwords": "True"}) return render(request, "login/register.html", {"form": form, "warning": warning, "newuser": True}) -def register(request, username=None): - """To register a new user on the troggle system, similar to the "expo" user - (with cavey:beery password) but specific to an individual - """ - current_user = request.user # if not logged in, this is 'AnonymousUser' - warning = "" +def re_register_email(request): + """For a logged-on user: + - change the email address + - trigger reset password ( by email token) + and we ignore any username specified in the URL of the request. + """ + logged_in = (identified_login := is_identified_user(request.user)) + if not logged_in: + return HttpResponseRedirect("/accounts/login/") + + u = request.user + initial_values = {} + initial_values.update({"username": u.username}) + initial_values.update({"email": u.email}) + + if request.method == "POST": + form = register_email_form(request.POST) # only username and password + if form.is_valid(): + print("POST VALID") + email = form.cleaned_data["email"] + u.email = email + u.save() + save_users(request, u, email) + return render(request, "login/register_email.html", {"form": form, "confirmed": True}) + else: + print("POST INVALID") + return render(request, "login/register_email.html", {"form": form}) + else: # GET + form = register_email_form(initial=initial_values) + return render(request, "login/register_email.html", {"form": form}) + +def register(request, url_username=None): + """To register an old expoer as a new user on the troggle system, + for someone who has previously attended expo, + similar to the "expo" user + (with cavey:beery password) but specific to an individual. + + """ + warning = "" + initial_values={"visible-passwords": "True"} + + logged_in = (identified_login := is_identified_user(request.user)) + if logged_in: + return re_register_email(request) + if request.method == "POST": form = register_form(request.POST) if form.is_valid(): + print("POST VALID") un = form.cleaned_data["username"] pw= form.cleaned_data["password1"] email = form.cleaned_data["email"] @@ -112,7 +153,7 @@ def register(request, username=None): # this is a password re-set, not a new registration. So we need to check it is the same person. form_user = expoers[0] if current_user != form_user: - print(f"## UNAUTHORIZED Password reset ## {current_user} {form_user}") + print(f"## UNAUTHORIZED Password reset ## {request.user} {form_user}") # return render(request, "login/register.html", {"form": form, "unauthorized": True}) # create User in the system and refresh stored encrypted user list and git commit it: updated_user = register_user(un, email, password=pw, pwhash=None) @@ -120,19 +161,16 @@ def register(request, username=None): # to do, login automatically, and redirect to control panel ? return HttpResponseRedirect("/accounts/login/") else: # GET - if username: # if provided in URL - if not current_user.is_anonymous: - warning = f"WARNING - you are logged-in as someone else '{current_user}'. You must logout and login again as '{username}' " + if url_username: # if provided in URL + if not request.user.is_anonymous: + warning = f"WARNING - you are logged-in as someone else '{request.user}'. You must logout and login again as '{url_username}' " print(f"REGISTER: {warning}") - form = register_form(initial={"visible": "True", "username": username} ) - - elif current_user: - form = register_form(initial={"visible": "True", "username": current_user.username}) - else: - form = register_form(initial={"visible": "True"}) - - return render(request, "login/register.html", {"form": form, "warning": warning}) - + initial_values.update({"username": url_username}) + elif request.user: + initial_values.update({"username": request.user.username}) + + form = register_form(initial=initial_values) + return render(request, "login/register.html", {"form": form, "warning": warning, "logged_in": logged_in}) def save_users(request, updated_user, email="troggle@exposerver.expo"): @@ -215,8 +253,37 @@ class newregister_form(forms.Form): # not a model-form, just a form-form "If you have been on expo before, you need to use the other form at expo.survex.com/accounts/register/ ." ) +class register_email_form(forms.Form): # not a model-form, just a form-form + """The widgets are being used EVEN THOUGH we are not using form.as_p() to create the + HTML form""" + username = forms.CharField(strip=True, required=True, + label="Username", + widget=forms.TextInput( + attrs={"size": 35, "placeholder": "e.g. anathema-device", + "style": "vertical-align: text-top;", "readonly": "readonly"} # READONLY for when changing email + )) + email = forms.CharField(strip=True, required=True, + label="email", + widget=forms.TextInput( + attrs={"size": 35, "placeholder": "e.g. anathema@potatohut.expo", + "style": "vertical-align: text-top;"} + )) + + def clean(self): + cleaned_data = super().clean() + + email = cleaned_data.get("email") + users = User.objects.filter(email=email) + print(f"{len(users)=}") + if len(users) > 1: # allow 0 (change) or 1 (confirm) + print("ValidationError") + raise ValidationError( + "Duplicate email address. Another registered user is already using this email address. Email addresses must be unique as that is how we reset forgotten passwords." + ) class register_form(forms.Form): # not a model-form, just a form-form + """The widgets are being used EVEN THOUGH we are not using form.as_p() to create the + HTML form""" username = forms.CharField(strip=True, required=True, label="Username", widget=forms.TextInput( diff --git a/templates/login/register.html b/templates/login/register.html index 8f6409c..e35f793 100644 --- a/templates/login/register.html +++ b/templates/login/register.html @@ -44,7 +44,11 @@ User Registration - for a personal login to Troggle {%endif %} +
-{{ warning }} +{{ warning }} {{ form.errors }}
Use the name you are usually known by "officially": this is usually the name on your passport. -But if you habitually use your second forename, not the first forename, use that. -Yes, you can put in any 'de', 'van' or 'von' or whatever 'nobiliary particle' you have, or a hyphenated surname; but this must be your real name. -Nicknames and fun names are done later. -{% else %} -
For previous expoers, your username must be your 'troggle id' as listed on the past expoers list -{%endif %} -
Unfortunately cavers tend to use weird and playful names when signing up for things, -so we can't automatically connect the troggle names and ids with the email addresses -on the email list. And we don't believe in signing people up for things without their -direct permission anyway. -Having said that, when you register here we will sign you up automatically to -the expo email list as that is how expo manages everything and it is a condition of -coming on expo. (You can unsubscribe from the email list after expo.) +{% include 'login/register_text.html' %} -
But the automatic sign-up to the email list is not working yet, and may not be before April 2025. -So if you don't want to miss out on anything important, make sure you sign up to the -email list -right now. - -
Clicking the big blue button will send you an email which will contain a login token. -Click on the link in the email and you will be able to set your own login password. -Use this to login to troggle and go to the Expo Signup form. -{% else %} -{%endif %} - -
-The password we {% if newuser %}will be{% else %}are{%endif %} asking for is solely for logging into troggle.
-The troggle login is used to track who is editing the current and past expo data, website content, and historic survey data, as well as for accessing the expo Kanban software. It is not the same as the password you use to access your email
-with your email provider
-and it is not the same as the password you use to interact with the expo
-email list.
{{ form.non_field_errors }}
diff --git a/templates/login/register_email.html b/templates/login/register_email.html
new file mode 100644
index 0000000..49e9791
--- /dev/null
+++ b/templates/login/register_email.html
@@ -0,0 +1,83 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+
+ [For new people wanting to come to expo for the first time,
+please use the New User registration form]
+
+ This will eventually sign you up automatically to the
+expo email list.
+So type in the same email address that you use there if you have already signed up to that.
+
+
+{{ form.non_field_errors }}
+{{ form.errors }}
+
+
+ Use the name you are usually known by "officially": this is usually the name on your passport.
+But if you habitually use your second forename, not the first forename, use that.
+Yes, you can put in any 'de', 'van' or 'von' or whatever 'nobiliary particle' you have, or a hyphenated surname; but this must be your real name.
+Nicknames and fun names are done later.
+{% else %}
+ For previous expoers, your username must be your 'troggle id' as listed on the past expoers list
+{%endif %}
+ Unfortunately cavers tend to use weird and playful names when signing up for things,
+so we can't automatically connect the troggle names and ids with the email addresses
+on the email list. And we don't believe in signing people up for things without their
+direct permission anyway.
+Having said that, when you register here we will sign you up automatically to
+the expo email list as that is how expo manages everything and it is a condition of
+coming on expo. (You can unsubscribe from the email list after expo.)
+
+ But the automatic sign-up to the email list is not working yet, and may not be before April 2025.
+So if you don't want to miss out on anything important, make sure you sign up to the
+email list
+right now.
+
+ Clicking the big blue button will send you an email which will contain a login token.
+Click on the link in the email and you will be able to set your own login password.
+Use this to login to troggle and go to the Expo Signup form.
+{% else %}
+{%endif %}
+
+
+The password we {% if newuser %}will be{% else %}are{%endif %} asking for is solely for logging into troggle.
+The troggle login is used to track who is editing the current and past expo data, website content, and historic survey data, as well as for accessing the expo Kanban software. It is not the same as the password you use to access your email
+with your email provider
+and it is not the same as the password you use to interact with the expo
+email list.
\ No newline at end of file
diff --git a/urls.py b/urls.py
index 414557c..d873368 100644
--- a/urls.py
+++ b/urls.py
@@ -172,7 +172,7 @@ trogglepatterns = [
# NB setting url pattern name to 'login' instea dof 'expologin' with override Django, see https://docs.djangoproject.com/en/dev/topics/http/urls/#naming-url-patterns
path('accounts/logout/', expologout, name='expologout'), # same as in django.contrib.auth.urls
path('accounts/login/', expologin, name='expologin'), # same as in django.contrib.auth.urls
- path("accounts/register/
+Email change - for a personal login to Troggle
+
+
+Register your email address
+
+Your name
+{% if newuser %}
+Students !
+Please do not use an email address which will expire when you leave your current institution.
+This will happen much sooner than you can possibly believe. If you realise that you have done this on the email list,
+you can change it at the bottom of this page.
+
+{% if newuser %}
+What happens next
+Security note
+We never store passwords at all, we only store a cryptographic hash.
+We do store your email address but only 'in clear' inside the live database online
+where it is accessible only to the database administrators. There is no troggle report
+which publishes your email address.
+For permanent storage all email addresses are encrypted. Your real name and troggle
+username is public however, and we do not have anonymous people attending expo.
+