diff options
-rw-r--r-- | core/utils.py | 1 | ||||
-rw-r--r-- | core/views/auth.py | 15 | ||||
-rw-r--r-- | core/views/signup.py | 162 | ||||
-rw-r--r-- | parsers/people.py | 1 | ||||
-rw-r--r-- | templates/login/signup.html | 12 | ||||
-rw-r--r-- | templates/login/signupok.html | 40 | ||||
-rw-r--r-- | urls.py | 3 |
7 files changed, 190 insertions, 44 deletions
diff --git a/core/utils.py b/core/utils.py index b6ec7af..33872b3 100644 --- a/core/utils.py +++ b/core/utils.py @@ -135,7 +135,6 @@ def make_new_expo_dir(year): if not p.is_file(): write_and_commit( [(p, content, "utf8")], f"Auto new year {ff} file creation", "Auto New Year <make_new_expo_dir@troggle.expo>") - def current_expo(): """Returns the current expo year, but also checks if the most recent expo year is the same as this year. If it is not, then it creates an empty Expedition and fixes some files and diff --git a/core/views/auth.py b/core/views/auth.py index db17ae3..689e645 100644 --- a/core/views/auth.py +++ b/core/views/auth.py @@ -23,19 +23,10 @@ class login_required_if_public(object): def __call__(self, *args, **kwargs): return self.f(*args, **kwargs) - -# This is copied from CUYC.cuy.website.view.auth -# If we want to do the whole online-email thing, we would also need to copy across the code in these -# imported files and delete what is superfluous. -# Or we could just load the latest version of django-registration app. -# from cuy.club.models import Member, Message -# from ..forms import WebsiteLoginForm, WebsiteRegisterForm -# from ...common import mail_site_error -# from .generic import user_is_active - """The login and logout functions. -This is also where we would manage registration: for people wanting to create and validate their individual -logon accounts/forgottenpassword""" + +TO DO : check that we don't have another set of these active somewhere +""" ############################ # Authentication Functions # diff --git a/core/views/signup.py b/core/views/signup.py index 686c92d..bc10b7a 100644 --- a/core/views/signup.py +++ b/core/views/signup.py @@ -1,8 +1,8 @@ -import os -import re +import json from pathlib import Path import django.forms as forms +from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import redirect, render from django.urls import reverse @@ -16,62 +16,174 @@ from troggle.core.utils import ( git_string, write_and_commit, ) +from troggle.core.models.troggle import DataIssue, Person from troggle.core.views.editor_helpers import HTMLarea - +from troggle.core.utils import ( + add_commit, +) +from troggle.parsers.users import get_encryptor, ENCRYPTED_DIR """The new user signup form and expo user management system in 2025. """ +SIGNUPS_FILE = "signups.json" +SIGNEDUP = "SIGNEDUP" +SIGNUP_YEAR = "2025" +SIGNUP_DATES = "30th June - 3rd August" + +def signupok(request): + signup_user = request.user + + return render( + request, "login/signupok.html", + {"year": SIGNUP_YEAR, "dates": SIGNUP_DATES, "signup_user": signup_user }, + ) def signup(request): - current_user = request.user + """Display and processes the applicant signup form for the forthcoming expo + The user must be logged-on as a personal login and that is + who is being sighned up. You can't signup someone else. + """ + signup_user = request.user - personal_login = True - if current_user.is_anonymous: + if signup_user.is_anonymous: personal_login = False - elif current_user.username in ["expo", "expoadmin"]: + elif signup_user.username in ["expo", "expoadmin"]: personal_login = False - + else: + personal_login = True + + if personal_login: + people = Person.objects.filter(user=signup_user) + if len(people) != 1: + # someone like "fluffy-bunny" not associated with a Person + return HttpResponseRedirect("/accounts/login/?next=/signup") + signup_person = people[0] + editor = f"{signup_person.fullname} <{signup_user.email}>" + if request.method == "POST": # If the form has been submitted... pageform = ExpoSignupForm(request.POST) # A form bound to the POST data if pageform.is_valid(): - print(f"form OK") - who = pageform.cleaned_data["name"] - who = git_string(name) - print(f"{who=}") + clean = pageform.cleaned_data + print(f" # Signup form OK {clean['name']}") + save_signups(editor, signup_person.slug, clean) + return HttpResponseRedirect("/signupok") + + else: + print(f" # Signup form INVALID\n{pageform.errors} ") return render( - request, - "login/signup.html", + request, "login/signup.html", {"form": pageform, "personal_login": personal_login, - "year": "2025", "dates": "30th June - 3rd August", + "year": SIGNUP_YEAR, "dates": SIGNUP_DATES, } ) else: - pageform = ExpoSignupForm(initial={"allergies":"None", + initial_context = {"allergies":"None", "medication":"None", "medic_info":"None", "veggie": "mostly", "student": "no", "top_tent_cap": 2, "base_tent_cap": 3, - }) + } + if personal_login: + initial_context["name"] = signup_person.fullname + initial_context["email"] = signup_user.email + pageform = ExpoSignupForm(initial=initial_context) return render( - request, - "login/signup.html", - {"form": pageform, - "year": "2025", "dates": "30th June - 3rd August", + request, "login/signup.html", + {"form": pageform, "personal_login": personal_login, + "year": SIGNUP_YEAR, "dates": SIGNUP_DATES, }, ) + +def read_signups(): + print(f" + READ signups") + f = get_encryptor() + signups_dir = settings.EXPOWEB / ENCRYPTED_DIR / current_expo() + if not signups_dir.is_dir(): + signups_dir.mkdir(parents=True, exist_ok=True) + + signupsfile = signups_dir / SIGNUPS_FILE + if not signupsfile.is_file(): + return { SIGNEDUP: {} } # dict where e.g. {"philip-sargent": encrypted_form_data, more users etc.} + + with open(signupsfile, 'r', encoding='utf-8') as json_f: + message = "" + try: + signups_single_dict = json.load(json_f) + except FileNotFoundError: + message = f"File {signupsfile} not found!" + except json.JSONDecodeError: + message = f"Invalid JSON format! - JSONDecodeError for {signupsfile}" + except Exception as e: + message = f"! Troggle USERs. Failed to load {signupsfile} JSON file. Exception <{e}>" + if message: + print(message) + DataIssue.objects.update_or_create(parser="_signups", message=message, url="") ########################### + return { SIGNEDUP: {} } + signups_dict = signups_single_dict[SIGNEDUP] + # print("ALL:",signups_dict) + signups_clear ={} + for su, content in signups_dict.items(): + clear_text = f.decrypt(content).decode() + print(f"\n - C signups_dict {su} - {clear_text}") + signups_clear[su] = clear_text + + return signups_clear + + +def save_signups(editor, person_slug, clean): + # print(f" + SAVE: Saving all signups") + f = get_encryptor() + signups_clear = read_signups() + # print(f" SAVE: {len(signups_clear)} signups read") + + signups_clear[person_slug] = clean + signups_crypt = {} + for su in signups_clear: + # re-encrypt everything + signups_crypt[su] = f.encrypt(json.dumps(signups_clear[su]).encode("utf8")).decode() + + print(f" SAVE after adding: {len(signups_crypt)} signups") + encryptedfile = settings.EXPOWEB / ENCRYPTED_DIR / current_expo() / SIGNUPS_FILE + try: + print(f"- Rewriting the entire encrypted set of signups to disc ") + write_signups(signups_crypt, encryptedfile, editor) + except: + message = f'! - Users encrypted data saving failed - \n!! Permissions failure ?! on attempting to save file "{encryptedfile}"' + print(message) + raise + return render(request, "errors/generic.html", {"message": message}) + +def write_signups(signups, encryptedfile, editor): + jsondict = { SIGNEDUP: signups } + try: + with open(encryptedfile, 'w', encoding='utf-8') as json_f: + json.dump(jsondict, json_f, indent=1) + except Exception as e: + print(f" ! Exception dumping json <{e}>") + raise + + commit_msg = f"Online signup to next expo" + try: + add_commit(encryptedfile, commit_msg, editor) + except Exception as e: + print(f" ! Exception doing git add/commit <{e}>") + raise + return True + + class ExpoSignupForm(forms.Form): name = forms.CharField(label='Full name', max_length=100, widget=forms.TextInput(attrs={'tabindex': 1, 'placeholder': 'Anathema Device'})) address = forms.CharField(widget=forms.Textarea(attrs={'rows': 7, 'cols': 20, 'tabindex': 2, 'placeholder': 'The Airfield,\nTadfield'})) phone = forms.CharField(max_length=15, widget=forms.TextInput(attrs={'tabindex': 3, 'placeholder': '+44.1234567890'})) email = forms.EmailField(widget=forms.TextInput(attrs={'tabindex': 4, 'placeholder': 'a.device@potatohut.expo'})) - kinname = forms.CharField(label='Next of Kin name', max_length=100, widget=forms.TextInput(attrs={'tabindex': 5, 'placeholder': 'Newton Pulsifer'})) - kinaddress = forms.CharField(widget=forms.Textarea(attrs={'rows': 7, 'cols': 20, 'tabindex': 6, 'placeholder': 'c/o The Old Ship Inn,\nLower Tadfield'})) - kinphone = forms.CharField(max_length=15, widget=forms.TextInput(attrs={'tabindex': 7, 'placeholder': '+44.0987654321'})) - kinemail = forms.EmailField(widget=forms.TextInput(attrs={'tabindex': 8, 'placeholder': 'n.pulsifer@basecamp.expo'})) + kin_name = forms.CharField(label='Next of Kin name', max_length=100, widget=forms.TextInput(attrs={'tabindex': 5, 'placeholder': 'Newton Pulsifer'})) + kin_address = forms.CharField(widget=forms.Textarea(attrs={'rows': 7, 'cols': 20, 'tabindex': 6, 'placeholder': 'c/o The Old Ship Inn,\nLower Tadfield'})) + kin_phone = forms.CharField(max_length=15, widget=forms.TextInput(attrs={'tabindex': 7, 'placeholder': '+44.0987654321'})) + kin_email = forms.EmailField(widget=forms.TextInput(attrs={'tabindex': 8, 'placeholder': 'n.pulsifer@basecamp.expo'})) relation = forms.CharField(label='Relation to you', max_length=100, widget=forms.TextInput(attrs={'tabindex': 9, 'placeholder': 'Beau'})) VEGGIE_CHOICES = [ diff --git a/parsers/people.py b/parsers/people.py index f18caee..04b5e2f 100644 --- a/parsers/people.py +++ b/parsers/people.py @@ -177,7 +177,6 @@ def load_people_expos(): print("", flush=True) ensure_users_are_persons() - def ensure_users_are_persons(): # Just ensure this is up to date. print(f"# ensure_users_are_persons()") diff --git a/templates/login/signup.html b/templates/login/signup.html index ac8e601..1101361 100644 --- a/templates/login/signup.html +++ b/templates/login/signup.html @@ -75,6 +75,10 @@ Loser Expo 2025 SIGN-UP Form </button> {% endif %} <hr> +<span style="color:red; font-family: monospace; font-weight: bold;"> +{{ form.errors }} <br /> <!-- why are the field errors not being reported against the field as a red outline?? --> +{{ form.non_field_errors }} <!-- form validation errors appear here, and also at the top of the form--> +</span> <form action="{% url 'signup' %}" method="post"> {% csrf_token %} @@ -89,25 +93,25 @@ Loser Expo 2025 SIGN-UP Form <td align="right"><i>Full</i> name:</td> <td>{{ form.name }}</td> <td align="right">Name:</td> - <td>{{ form.kinname }}</td> + <td>{{ form.kin_name }}</td> </tr> <tr> <td align="right">Address:</td> <td>{{ form.address }}</td> <td align="right">Address:</td> - <td>{{ form.kinaddress }}</td> + <td>{{ form.kin_address }}</td> </tr> <tr> <td align="right">Phone:</td> <td>{{ form.phone }}</td> <td align="right">Phone:</td> - <td>{{ form.kinphone }}</td> + <td>{{ form.kin_phone }}</td> </tr> <tr> <td align="right">Email:</td> <td>{{ form.email }}</td> <td align="right">Email:</td> - <td>{{ form.kinemail }}</td> + <td>{{ form.kin_email }}</td> </tr> <tr> <td colspan="2"></td> diff --git a/templates/login/signupok.html b/templates/login/signupok.html new file mode 100644 index 0000000..548a890 --- /dev/null +++ b/templates/login/signupok.html @@ -0,0 +1,40 @@ +<!-- frontpage.html - this text visible because this template has been included --> +{% extends "base.html" %} + + +{% block title %}Cambridge Expeditions to Austria{% endblock %} + +{% block content %} + <title>Loser Expo {{year}} Sign-up Form Completed</title> + + <h1>Expo {{year}} {{dates}}</h1> + + +<div id="col1"> +<h3>You have signed up to attend the next Expo</h3> +<p class="indent"> +You have signed up as {{signup_user.username}} - {{signup_user.email}} +<p class="indent"> +Your signup has been registered. Please now register your email on the email announcements list if +you have not already done so: +<ul> +<li><a href="https://lists.wookware.org/cgi-bin/mailman/listinfo/expo">lists.wookware.org : expo</a> +</ul> +</p> +<p class="indent"> +This is the beginning of becoming part of the team for Expo {{year}}. There are training events and +organisation to do, kit-lists to organise, and your dates on expo need to be agreed with Expo. We +particularly need adequate manpower to de-rig the caves and pack up at the end of Expo. +<p class="indent"> +You next jobs to do: see the <a href="/kanboard/board/2">Expo Kanboard</a>. +<br /> +<!-- <img src="/expofiles/photos/2007/selected/eishoehle5nial.jpg">--> +<figure align=center> +<img src="/expofiles/photos/2007/selected/eishoehle4nial.jpg" width="250px"> +<figcaption>Nial in <a href="/expofiles/photos/2007/selected/">Eishohle in 2007</a>.</figcaption> +</figure> +{% endblock content %} + +{% block margins %} + +{% endblock margins %}
\ No newline at end of file @@ -57,7 +57,7 @@ from troggle.core.views.other import controlpanel, exportlogbook, frontpage, tod from troggle.core.views.prospect import prospecting from troggle.core.views.user_registration import register, newregister, reset_done, ExpoPasswordResetForm from troggle.core.views.scans import allscans, cavewallets, scansingle, walletslistperson, walletslistyear -from troggle.core.views.signup import signup +from troggle.core.views.signup import signup, signupok from troggle.core.views.uploads import dwgupload, expofilerename, gpxupload, photoupload from troggle.core.views.wallets_edit import walletedit @@ -144,6 +144,7 @@ trogglepatterns = [ path('logbookedit/', logbookedit, name='logbookedit'), path('logbookedit/<slug:slug>', logbookedit, name='logbookedit'), path('signup', signup, name='signup'), + path('signupok', signupok, name='signupok'), # Renaming an uploaded file path('expofilerename/<path:filepath>', expofilerename, name='expofilerename'), |