mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2025-12-14 21:47:12 +00:00
290 lines
12 KiB
Python
290 lines
12 KiB
Python
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
|
|
|
|
import troggle.settings as settings
|
|
from troggle.core.models.troggle import DataIssue, Person, PersonExpedition
|
|
from troggle.core.models.logbooks import Expedition
|
|
from troggle.core.views.editor_helpers import HTMLarea
|
|
from troggle.core.utils import (
|
|
WriteAndCommitError,
|
|
add_commit,
|
|
current_expo,
|
|
get_cookie,
|
|
get_git_string,
|
|
git_string,
|
|
is_identified_user,
|
|
write_and_commit,
|
|
)
|
|
from troggle.parsers.users import get_encryptor, ENCRYPTED_DIR, how_many_previous_expos
|
|
from .auth import login_required_if_public
|
|
|
|
"""The new user signup form and expo user management system in 2025.
|
|
"""
|
|
SIGNUPS_FILE = "signups.json"
|
|
SIGNEDUP = "SIGNEDUP"
|
|
BIERBOOK = "documents/bierbook"
|
|
BIERFILE = "names.txt"
|
|
|
|
SIGNUP_YEAR = "2025"
|
|
SIGNUP_DATES = "30th June - 3rd August"
|
|
|
|
def signupok(request):
|
|
signup_user = request.user
|
|
if signup_user.username in ["expo", "expoadmin"]:
|
|
signup_user = None
|
|
|
|
signedup_people = []
|
|
signups_clear = read_signups()
|
|
for su in signups_clear:
|
|
signedup_people.append(su)
|
|
|
|
return render(
|
|
request, "login/signupok.html",
|
|
{"year": SIGNUP_YEAR, "dates": SIGNUP_DATES, "signup_user": signup_user, "signedup_people": signedup_people},
|
|
)
|
|
|
|
@login_required_if_public
|
|
def signup(request):
|
|
"""Displays 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 signed up. You can't signup someone else.
|
|
"""
|
|
form_read_only = True # default
|
|
signup_user = request.user
|
|
identified_login = is_identified_user(signup_user)
|
|
|
|
if identified_login:
|
|
editor = get_git_string(signup_user)
|
|
form_read_only = False
|
|
else:
|
|
get_cookie(request) # might be blank
|
|
# No, just make the form read-only.
|
|
# return HttpResponseRedirect("/accounts/login/")
|
|
|
|
if signup_user.is_anonymous:
|
|
experience = 0
|
|
else:
|
|
people = Person.objects.filter(user=signup_user)
|
|
if len(people) == 1:
|
|
signup_person = people[0]
|
|
form_read_only = False
|
|
experience = how_many_previous_expos(signup_person)
|
|
else:
|
|
experience = 0
|
|
# No, just make the form read-only.
|
|
# return HttpResponseRedirect("/accounts/login")
|
|
|
|
|
|
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():
|
|
clean = pageform.cleaned_data
|
|
print(f" # Signup form OK {clean['name']}")
|
|
register_on_expo(signup_person)
|
|
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",
|
|
{"form": pageform, "identified_login": identified_login,
|
|
"year": SIGNUP_YEAR, "dates": SIGNUP_DATES,
|
|
}
|
|
)
|
|
else:
|
|
signups_clear = read_signups()
|
|
if signup_user.username in signups_clear:
|
|
# pre-load form with previously saved data
|
|
initial_context = signups_clear[signup_user.username]
|
|
else:
|
|
initial_context = {"allergies":"None",
|
|
"medication":"None",
|
|
"medic_info":"None",
|
|
"veggie": "mostly",
|
|
"student": "no",
|
|
"top_tent_cap": 2,
|
|
"base_tent_cap": 3,
|
|
}
|
|
if identified_login:
|
|
initial_context["name"] = signup_person.fullname
|
|
initial_context["email"] = signup_user.email
|
|
initial_context["experience"] = experience
|
|
|
|
pageform = ExpoSignupForm(initial=initial_context)
|
|
return render(
|
|
request, "login/signup.html",
|
|
{"form": pageform, "identified_login": identified_login,
|
|
"year": SIGNUP_YEAR, "dates": SIGNUP_DATES,
|
|
},
|
|
)
|
|
|
|
def register_on_expo(signup_person):
|
|
signup = PersonExpedition(person=signup_person, expedition=Expedition.objects.get(year=SIGNUP_YEAR))
|
|
signup.save()
|
|
|
|
def read_signups():
|
|
# print(f" + READ signups")
|
|
# This has a big BUG. when it works, it returns a dict with keys such as "philip-sargent"
|
|
# but the error conditions are returning a dict of dicts
|
|
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 - {su} - {clear_text}")
|
|
signups_clear[su] = json.loads(clear_text)
|
|
|
|
return signups_clear
|
|
|
|
# def is_signedup(person):
|
|
# signups_clear = read_signups()
|
|
# print(signups_clear)
|
|
# if person.slug in signups_clear:
|
|
# return True
|
|
# return False
|
|
|
|
|
|
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})
|
|
|
|
print(f"- Exporting bierbook ")
|
|
write_bierbook(signups_clear, editor)
|
|
|
|
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
|
|
|
|
def write_bierbook(signups_clear, editor):
|
|
bieryeardir = settings.EXPOWEB / BIERBOOK / current_expo()
|
|
bierfile = bieryeardir / BIERFILE
|
|
print(bierfile)
|
|
|
|
names = ""
|
|
for id in signups_clear:
|
|
names += f"{signups_clear[id]['name']}\n"
|
|
|
|
for i in range(0,3):
|
|
names += "\\ldots\\ldots\\ldots\n"
|
|
|
|
print(names)
|
|
if not bieryeardir.is_dir():
|
|
bieryeardir.mkdir(parents=True, exist_ok=True)
|
|
|
|
write_and_commit( [(bierfile, names, "utf8")], f"(re)writing bierbook names", editor)
|
|
|
|
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'}))
|
|
|
|
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 = [
|
|
('vegan', 'Vegan'),
|
|
('yes', 'Vegetarian'),
|
|
('mostly', 'Mostly Vegetarian'),
|
|
('no', 'No'),
|
|
]
|
|
|
|
STUDENT_CHOICES = [
|
|
('yes', 'Yes, I am an impecunious starvelling'),
|
|
('no', 'No, I have pots of dosh'),
|
|
]
|
|
|
|
veggie = forms.ChoiceField(choices=VEGGIE_CHOICES, widget=forms.RadioSelect(attrs={'tabindex': 10}))
|
|
student = forms.ChoiceField(choices=STUDENT_CHOICES, widget=forms.RadioSelect(attrs={'tabindex': 11}))
|
|
|
|
transport_ok = forms.ChoiceField(choices=[('yes', 'Yes, I have arranged transport and it is shown on that page'), ('no', 'No, I need to arrange or confirm transport')],
|
|
widget=forms.RadioSelect(attrs={'tabindex': 12}), initial='no')
|
|
insurance_info = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'cols': 80, 'tabindex': 13, "placeholder":"I do not have any insurance and I don't know what I need."}),
|
|
required=False)
|
|
transport_info = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'cols': 80, 'tabindex': 13, "placeholder":"I am a numpty and have no clue how I will get there (or back)."}),
|
|
required=False)
|
|
|
|
bivvy = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={'tabindex': 14, }))
|
|
tent = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={'tabindex': 15}))
|
|
top_tent_cap = forms.IntegerField(required=False, widget=forms.TextInput(attrs={'size': 1, 'tabindex': 16, "placeholder":2}))
|
|
btent = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={'tabindex': 17}))
|
|
base_tent_cap = forms.IntegerField(required=False, widget=forms.TextInput(attrs={'size': 1, 'tabindex': 18, "size":1, "placeholder":3}))
|
|
|
|
allergies = forms.CharField(widget=forms.Textarea(attrs={'rows': 2, 'cols': 80, 'tabindex': 19}), required=False)
|
|
medication = forms.CharField(widget=forms.Textarea(attrs={'rows': 2, 'cols': 80, 'tabindex': 20}), required=False)
|
|
medic_info = forms.CharField(widget=forms.Textarea(attrs={'rows': 2, 'cols': 80, 'tabindex': 21}), required=False)
|
|
|
|
extra_info = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'cols': 80, 'tabindex': 22,
|
|
'placeholder': 'Estuary english (fluent),\nCan use the potato hut bread machine (level 3 certificate)'}), required=False)
|
|
|
|
aims = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'cols': 80, 'tabindex': 23, 'placeholder': 'Strolling over the plateau, sunning myself and taking in the views.'}), required=False)
|
|
experience = forms.IntegerField(required=True, widget=forms.TextInput(attrs={'size': 1, 'tabindex': 24, 'readonly': 'readonly'}))
|
|
|
|
|