diff options
-rw-r--r-- | _deploy/debian_server | 160 | ||||
-rw-r--r-- | core/models/troggle.py | 10 | ||||
-rw-r--r-- | core/utils.py | 19 | ||||
-rw-r--r-- | core/views/expo.py | 20 | ||||
-rw-r--r-- | core/views/other.py | 2 | ||||
-rw-r--r-- | core/views/signup.py | 41 | ||||
-rw-r--r-- | parsers/users.py | 13 | ||||
-rw-r--r-- | templates/login/signup.html | 4 |
8 files changed, 65 insertions, 204 deletions
diff --git a/_deploy/debian_server b/_deploy/debian_server deleted file mode 100644 index 3c5293e..0000000 --- a/_deploy/debian_server +++ /dev/null @@ -1,160 +0,0 @@ -import os -import sys -import urllib.parse -from pathlib import Path - -"""Settings for a troggle installation which may vary among different -installations: for development or deployment, in a docker image or -python virtual environment (venv), on ubuntu, debian or in Windows -System for Linux (WSL), on the main server or in the potato hut, -using SQLite or mariaDB. - -It sets the directory locations for the major parts of the system so -that e.g. expofiles can be on a different filesystem. - -This file is included at the end of the main troggle/settings.py file so that -it overwrites defaults in that file. - -NOTE this file is vastly out of sync with troggle/_deploy/wsl/localsettings.py -which is the most recent version used in active maintenance. There should be -essential differences, but there and many, many non-essential differences which -should be eliminated for clarity and to use modern idioms. 8 March 2023. -""" - -print(" * importing troggle/localsettings.py") - -# DO NOT check this file into the git repo - it contains real passwords. - -EXPOFILESREMOTE = False # if True, then re-routes urls in expofiles to remote sever -#SECURE_SSL_REDIRECT = True # breaks 7 tests in test suite 301 not 200 (or 302) and runserver fails completely - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', # 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME' : 'troggle', # Or path to database file if using sqlite3. - 'USER' : 'expo', # Not used with sqlite3. - 'PASSWORD' : 'uFqP56B4XleeyIW', # Not used with sqlite3. - 'HOST' : '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT' : '', # Set to empty string for default. Not used with sqlite3. - } -} - - -EXPOUSER = 'expo' -EXPOUSERPASS = '161:gosser' -EXPOADMINUSER = 'expoadmin' -EXPOADMINUSERPASS = 'gosser:161' -EXPOUSER_EMAIL = 'wookey@wookware.org' -EXPOADMINUSER_EMAIL = 'wookey@wookware.org' - -REPOS_ROOT_PATH = '/home/expo/' -sys.path.append(REPOS_ROOT_PATH) -sys.path.append(REPOS_ROOT_PATH + 'troggle') -# Define the path to the django app (troggle in this case) -PYTHON_PATH = REPOS_ROOT_PATH + 'troggle/' - - -PHOTOS_YEAR = "2023" -# add in 358 when they don't make it crash horribly -NOTABLECAVESHREFS = [ "290", "291", "359", "264", "258", "204", "76", "107"] - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - PYTHON_PATH + "templates" - ], - 'OPTIONS': { - 'debug': 'DEBUG', - 'context_processors': [ - # django.template.context_processors.csrf, # is always enabled and cannot be removed, sets csrf_token - 'django.contrib.auth.context_processors.auth', # knowledge of logged-on user & permissions - 'core.context.troggle_context', # in core/troggle.py - 'django.template.context_processors.debug', - #'django.template.context_processors.request', # copy of current request, added in trying to make csrf work - 'django.template.context_processors.i18n', - 'django.template.context_processors.media', # includes a variable MEDIA_URL - 'django.template.context_processors.static', # includes a variable STATIC_URL - 'django.template.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - ], - 'loaders': [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', #For each app, inc admin, in INSTALLED_APPS, loader looks for /templates - # insert your own TEMPLATE_LOADERS here - ] - }, - }, -] - -PUBLIC_SITE = True - -# This should be False for normal running -DEBUG = True -CACHEDPAGES = True # experimental page cache for a handful of page types - - -# executables: -CAVERN = 'cavern' # for parsing .svx files and producing .2d files -SURVEXPORT = 'survexport' # for parsing .3d files and producing .pos files - -PV = "python" + str(sys.version_info.major) + "." + str(sys.version_info.minor) -LIBDIR = Path(REPOS_ROOT_PATH) / 'lib' / PV - -EXPOWEB = Path(REPOS_ROOT_PATH + 'expoweb/') -SURVEYS = REPOS_ROOT_PATH -SURVEY_SCANS = REPOS_ROOT_PATH + 'expofiles/surveyscans/' -FILES = REPOS_ROOT_PATH + 'expofiles' -PHOTOS_ROOT = REPOS_ROOT_PATH + 'expofiles/photos/' - -TROGGLE_PATH = Path(__file__).parent -TEMPLATE_PATH = TROGGLE_PATH / 'templates' -MEDIA_ROOT = TROGGLE_PATH / 'media' -JSLIB_ROOT = TROGGLE_PATH / 'media' / 'jslib' # used for CaveViewer JS utility - - -CAVEDESCRIPTIONS = EXPOWEB / "cave_data" -ENTRANCEDESCRIPTIONS = EXPOWEB / "entrance_data" - - -PYTHON_PATH = REPOS_ROOT_PATH + 'troggle/' - - -#URL_ROOT = 'http://expo.survex.com/' -URL_ROOT = '/' -DIR_ROOT = Path("") #this should end in / if a value is given -EXPOWEB_URL = '/' -SURVEYS_URL = '/survey_scans/' - -REPOS_ROOT_PATH = Path(REPOS_ROOT_PATH) - -SURVEX_DATA = REPOS_ROOT_PATH / "loser" -DRAWINGS_DATA = REPOS_ROOT_PATH / "drawings" - - -EXPOFILES = REPOS_ROOT_PATH / "expofiles" -SCANS_ROOT = EXPOFILES / "surveyscans" -PHOTOS_ROOT = EXPOFILES / "photos" - -#EXPOFILES = urllib.parse.urljoin(REPOS_ROOT_PATH, 'expofiles/') -PHOTOS_URL = urllib.parse.urljoin(URL_ROOT, '/photos/') - -# MEDIA_URL is used by urls.py in a regex. See urls.py & core/views_surveys.py -MEDIA_URL = '/site_media/' - - -STATIC_URL = urllib.parse.urljoin(URL_ROOT , '/static/') # used by Django admin pages. Do not delete. -JSLIB_URL = urllib.parse.urljoin(URL_ROOT , '/javascript/') # always fails, try to revive it ? -# STATIC_ROOT removed after merging content into MEDIA_ROOT. See urls.py & core/views/surveys.py - -#TINY_MCE_MEDIA_ROOT = STATIC_ROOT + '/tiny_mce/' # not needed while TinyMCE not installed -#TINY_MCE_MEDIA_URL = STATIC_URL + '/tiny_mce/' # not needed while TinyMCE not installed - -LOGFILE = '/var/log/troggle/troggle.log' -IMPORTLOGFILE = '/var/log/troggle/import.log' - -# Sanitise these to be strings as Django seems to be particularly sensitive to crashing if they aren't -STATIC_URL = str(STATIC_URL) + "/" -MEDIA_URL = str(MEDIA_URL) + "/" - -print(" + finished importing troggle/localsettings.py") diff --git a/core/models/troggle.py b/core/models/troggle.py index 6155347..62fe9c1 100644 --- a/core/models/troggle.py +++ b/core/models/troggle.py @@ -78,7 +78,12 @@ class Expedition(TroggleModel): return reverse("expedition", args=[self.year]) class Person(TroggleModel): - """single Person, can go on many years""" + """single Person, can go on expo many years + + Note that the class "User" and the class "Group + are standrd Django classes + definied in django.contrib.auth.models + """ first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) @@ -100,8 +105,7 @@ class Person(TroggleModel): def get_absolute_url(self): # we do not use URL_ROOT any more. return reverse("person", kwargs={"slug": self.slug}) - return reverse("person", kwargs={"first_name": self.first_name, "last_name": self.last_name}) - + class Meta: verbose_name_plural = "People" ordering = ("orderref",) # "Wookey" makes too complex for: ('last_name', 'first_name') diff --git a/core/utils.py b/core/utils.py index 33872b3..d88f39f 100644 --- a/core/utils.py +++ b/core/utils.py @@ -157,6 +157,25 @@ def current_expo(): else: return settings.EPOCH.year # this is 1970 +def is_identified_user(user): + if user.is_anonymous: + return False + if user.username in ["expo", "expoadmin"]: + return False + return True + +def get_git_string(user): + if not is_identified_user(user): + return None + else: + people = Person.objects.filter(user=user) + if len(people) != 1: + # someone like "fluffy-bunny" not associated with a Person + return None + person = people[0] + return f"{person.fullname} <{user.email}>" + + def parse_aliases(aliasfile): """Reads a long text string containing pairs of strings: (alias, target) diff --git a/core/views/expo.py b/core/views/expo.py index 89215a4..63f1d33 100644 --- a/core/views/expo.py +++ b/core/views/expo.py @@ -19,7 +19,9 @@ from troggle.core.utils import ( current_expo, get_cookie, git_string, + get_git_string, write_and_commit, + is_identified_user ) from troggle.core.views.editor_helpers import HTMLarea from troggle.core.views.uploads import edittxtpage @@ -455,15 +457,17 @@ def editexpopage(request, path): print("### File not found ### ", filepath) filefound = False - editor = get_cookie(request) - + current_user = request.user + if identified_login := is_identified_user(current_user): + editor = get_git_string(current_user) + else: + editor = get_cookie(request) + if request.method == "POST": # If the form has been submitted... pageform = ExpoPageForm(request.POST) # A form bound to the POST data if pageform.is_valid(): # Form valid therefore write file editor = pageform.cleaned_data["who_are_you"] editor = git_string(editor) - # print("### \n", str(pageform)[0:300]) - # print("### \n csrfmiddlewaretoken: ",request.POST['csrfmiddlewaretoken']) if filefound: headmatch = re.match(r"(.*)<title>.*</title>(.*)", head, re.DOTALL + re.IGNORECASE) if headmatch: @@ -490,7 +494,7 @@ def editexpopage(request, path): if not filefound or result != html: # Check if content changed at all edit_response = HttpResponseRedirect(reverse("expopage", args=[path])) # Redirect after POST edit_response.set_cookie('editor_id', editor, max_age=COOKIE_MAX_AGE) # cookie expires after COOKIE_MAX_AGE seconds - print(f"Cookie set: {editor} for {COOKIE_MAX_AGE/3600} hours") + print(f"Cookie set: {editor} for {COOKIE_MAX_AGE/(24*3600)} days") try: change_message = pageform.cleaned_data["change_message"] editor = pageform.cleaned_data["who_are_you"] @@ -507,9 +511,9 @@ def editexpopage(request, path): (title,) = m.groups() else: title = "" - pageform = ExpoPageForm(initial={"who_are_you":editor, "html": body, "title": title}) + pageform = ExpoPageForm(initial={"identified_login": identified_login, "who_are_you":editor, "html": body, "title": title}) else: - pageform = ExpoPageForm(initial={"who_are_you":editor}) + pageform = ExpoPageForm(initial={"identified_login": identified_login, "who_are_you":editor}) return render( @@ -540,6 +544,8 @@ class ExpoPageForm(forms.Form): "style": "vertical-align: text-top;"} ) ) + identified_login = forms.BooleanField(widget=forms.CheckboxInput(attrs={"onclick":"return false"})) # make it readonly + who_are_you = forms.CharField( widget=forms.Textarea( attrs={"cols": 90, "rows": 1, "placeholder": "You have edited this page, who are you ? e.g. 'Animal <mta@gasthof.expo>'", diff --git a/core/views/other.py b/core/views/other.py index ab2f8a7..a0a2a0c 100644 --- a/core/views/other.py +++ b/core/views/other.py @@ -163,7 +163,7 @@ def controlpanel(request): return render( request, "controlPanel.html", - {"error": ' - Needs "expoadmin" logon. \nLogout and login again.', + {"error": ' - Needs "expoadmin" or superuser logon. \nLogout and login again.', "year": current_expo()} ) diff --git a/core/views/signup.py b/core/views/signup.py index 4b7e398..e46ca49 100644 --- a/core/views/signup.py +++ b/core/views/signup.py @@ -8,21 +8,19 @@ from django.shortcuts import redirect, render from django.urls import reverse import troggle.settings as settings +from troggle.core.models.troggle import DataIssue, Person +from troggle.core.views.editor_helpers import HTMLarea from troggle.core.utils import ( COOKIE_MAX_AGE, WriteAndCommitError, + add_commit, current_expo, get_cookie, + get_git_string, git_string, + is_identified_user, 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, - write_and_commit, - current_expo -) from troggle.parsers.users import get_encryptor, ENCRYPTED_DIR, how_many_previous_expos @@ -51,27 +49,17 @@ def signupok(request): {"year": SIGNUP_YEAR, "dates": SIGNUP_DATES, "signup_user": signup_user, "signedup_people": signedup_people}, ) + def signup(request): """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. + who is being signed up. You can't signup someone else. """ signup_user = request.user - - if signup_user.is_anonymous: - personal_login = False - 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}>" + identified_login = is_identified_user(signup_user) + + if identified_login: + editor = get_git_string(signup_user) else: editor = f"troggle <signup_anon@austria.expo>" @@ -89,7 +77,7 @@ def signup(request): print(f" # Signup form INVALID\n{pageform.errors} ") return render( request, "login/signup.html", - {"form": pageform, "personal_login": personal_login, + {"form": pageform, "identified_login": identified_login, "year": SIGNUP_YEAR, "dates": SIGNUP_DATES, } ) @@ -107,16 +95,15 @@ def signup(request): "top_tent_cap": 2, "base_tent_cap": 3, } - if personal_login: + 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, "personal_login": personal_login, + {"form": pageform, "identified_login": identified_login, "year": SIGNUP_YEAR, "dates": SIGNUP_DATES, }, ) diff --git a/parsers/users.py b/parsers/users.py index 97d06a0..30b491b 100644 --- a/parsers/users.py +++ b/parsers/users.py @@ -22,11 +22,11 @@ Passwords are only ever stored as hashes using the standard Django functions. todo = """ - Not fully tested, needs experience -- Need to write to BierBook for signups - - Need to check/register with lists.wookware.org for email """ +SUPER_USERS = ["philip-sargent"] # list of userids who get the same rights as "expoadmin" i.e. the Django control panel + USERS_FILE = "users.json" ENCRYPTED_DIR = "encrypted" @@ -54,8 +54,13 @@ def register_user(u, email, password=None, pwhash=None, fullname=""): # user.set_password(None) # use Django special setting for invalid password, but then FAILS to send password reset email user.set_password("secret") # Why is the Django logic broken. Hmph. print(f" # setting INVALID password for user {u}, must be reset by password_reset") - user.is_staff = False - user.is_superuser = False + if u in SUPER_USERS: + user.is_staff = True + user.is_superuser = True + print(f"** {u} is SUPER and can access everything on the Django control panel") + else: + user.is_staff = False + user.is_superuser = False user.save() print(f" - receated and reset user '{user}'") except Exception as e: diff --git a/templates/login/signup.html b/templates/login/signup.html index 68b681d..815c2ec 100644 --- a/templates/login/signup.html +++ b/templates/login/signup.html @@ -45,7 +45,7 @@ Loser Expo {{year}} SIGN-UP Form <p>Submitting this form will subscribe you to the expo mailing list if you are not already subscribed. </p> - {% if personal_login %} + {% if identified_login %} {% else %} <button class="fancybutton" style="padding: 0.5em 25px; font-size: 100%;" onclick="window.location.href='/accounts/register/'" value = "Go to"> You need to register a personal login before you can signup to attend → @@ -166,7 +166,7 @@ Loser Expo {{year}} SIGN-UP Form <h2>All done?</h2> <!-- <p>Click the <b>Preview</b> button below to review your submission.</p> --> <div style="text-align: center"> - {% if personal_login %} + {% if identified_login %} <button class="fancybutton" style="padding: 0.5em 25px; font-size: 100%;" type = "submit" > Submit → </button> |