mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2026-03-31 21:44:00 +01:00
lgoing/cookie interaction betetr
This commit is contained in:
@@ -168,25 +168,6 @@ def current_expo():
|
|||||||
else:
|
else:
|
||||||
return settings.EPOCH.year # this is 1970
|
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):
|
def parse_aliases(aliasfile):
|
||||||
"""Reads a long text string containing pairs of strings:
|
"""Reads a long text string containing pairs of strings:
|
||||||
(alias, target)
|
(alias, target)
|
||||||
@@ -233,14 +214,40 @@ def parse_aliases(aliasfile):
|
|||||||
return [(None, None)], "Fail on file reading"
|
return [(None, None)], "Fail on file reading"
|
||||||
return aliases, report
|
return aliases, report
|
||||||
|
|
||||||
|
def get_editor(request):
|
||||||
|
current_user = request.user
|
||||||
|
if is_identified_user(current_user):
|
||||||
|
return get_git_string(current_user)
|
||||||
|
else:
|
||||||
|
return get_cookie(request)
|
||||||
|
|
||||||
|
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 get_cookie(request):
|
def get_cookie(request):
|
||||||
"""The initial idea of having a default turned out to be a bad idea as people just ignore the field.
|
"""The initial idea of having a default turned out to be a bad idea as people just ignore the field.
|
||||||
if the default value is blank, then the form validation code makes the user type something in,
|
if the default value is blank, then the form validation code makes the user type something in.
|
||||||
so having a blank is best.
|
So having a blank is best if the cookie is to be displayed as the first value seen on a form.
|
||||||
|
But if the cookie is to be stored, then "Unset" may be better.
|
||||||
"""
|
"""
|
||||||
# NO_COOKIE_DEFAULT = 'Unset Cookie <hohlenforscher@potatohut.expo>'
|
# NO_COOKIE_DEFAULT = 'Unset Cookie <hohlenforscher@potatohut.expo>'
|
||||||
# print(f"-- Getting cookie...")
|
# print(f"-- Getting cookie...")
|
||||||
editor_id = request.COOKIES.get('editor_id', "") # if no cookie, then default string ""
|
editor_id = request.COOKIES.get('editor_id', "")
|
||||||
editor = git_string(editor_id) # belt and braces, should have been validity checked on saving already
|
editor = git_string(editor_id) # belt and braces, should have been validity checked on saving already
|
||||||
# print(f"-- Cookie to be used: {editor=}")
|
# print(f"-- Cookie to be used: {editor=}")
|
||||||
return editor
|
return editor
|
||||||
@@ -268,7 +275,6 @@ def git_string(author_string):
|
|||||||
print(f"++ Not git-compatible author string '{author_string}', replacing as '{editor}'")
|
print(f"++ Not git-compatible author string '{author_string}', replacing as '{editor}'")
|
||||||
return editor
|
return editor
|
||||||
|
|
||||||
|
|
||||||
def git_add(filename, cwd, commands=[]):
|
def git_add(filename, cwd, commands=[]):
|
||||||
"""Add a file to the list of Staged files ready for a later git commit
|
"""Add a file to the list of Staged files ready for a later git commit
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ from PIL import Image
|
|||||||
|
|
||||||
import troggle.settings as settings
|
import troggle.settings as settings
|
||||||
from troggle.core.utils import ( COOKIE_MAX_AGE,
|
from troggle.core.utils import ( COOKIE_MAX_AGE,
|
||||||
WriteAndCommitError, get_cookie, git_string, write_binary_file,
|
WriteAndCommitError, get_editor,
|
||||||
write_and_commit, current_expo, random_slug, ensure_dir_exists
|
git_string,
|
||||||
|
write_binary_file, write_and_commit,
|
||||||
|
current_expo, random_slug, ensure_dir_exists,
|
||||||
|
is_identified_user
|
||||||
)
|
)
|
||||||
|
|
||||||
from .auth import login_required_if_public
|
from .auth import login_required_if_public
|
||||||
@@ -115,47 +118,71 @@ def dms2dd(degrees, minutes, seconds, direction):
|
|||||||
|
|
||||||
def extract_gps(dict):
|
def extract_gps(dict):
|
||||||
"""Produce a set of annotations to add to an image description
|
"""Produce a set of annotations to add to an image description
|
||||||
|
|
||||||
|
The problem is that at any time one or more of the exif data points might
|
||||||
|
be missing from a particular photo, even GPSVersionID, so we need a lot
|
||||||
|
of data existence checking or it will crash.
|
||||||
"""
|
"""
|
||||||
|
def is_present(gpsifd):
|
||||||
|
item = getattr(piexif.GPSIFD, gpsifd)
|
||||||
|
if item in dict:
|
||||||
|
print(f" {gpsifd} = {item}")
|
||||||
|
return dict[item]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def extract(gpsifd):
|
||||||
|
if item:=is_present(gpsifd): # walrus
|
||||||
|
n, d = item
|
||||||
|
return n/d
|
||||||
|
return None
|
||||||
|
|
||||||
def rational(tup):
|
def rational(tup):
|
||||||
nom, denom = tup
|
nom, denom = tup
|
||||||
return nom/denom
|
return nom/denom
|
||||||
|
|
||||||
def extract(gpsifd):
|
|
||||||
print(piexif.GPSIFD)
|
|
||||||
n, d = dict[getattr(piexif.GPSIFD, gpsifd)]
|
|
||||||
return n/d
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
compass_points = ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"]
|
compass_points = ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"]
|
||||||
bearing = extract("GPSImgDirection")
|
if bearing := extract("GPSImgDirection"):
|
||||||
compass_lookup = round(bearing / 45)
|
compass_lookup = round(bearing / 45)
|
||||||
nsew = compass_points[compass_lookup]
|
nsew = compass_points[compass_lookup]
|
||||||
if dict[piexif.GPSIFD.GPSImgDirectionRef] == b"M":
|
if item := is_present("GPSImgDirectionRef"):
|
||||||
ref = "Magnetic"
|
if item == b"M":
|
||||||
elif dict[piexif.GPSIFD.GPSImgDirectionRef] == b"T":
|
ref = "Magnetic"
|
||||||
ref = "True"
|
elif item == b"T":
|
||||||
direction = f"Direction of view: {nsew:2} ({bearing:.0f}°{ref})"
|
ref = "True"
|
||||||
|
else:
|
||||||
|
ref =""
|
||||||
|
direction = f"Direction of view: {nsew:2} ({bearing:.0f}°{ref})"
|
||||||
|
else:
|
||||||
|
direction = ""
|
||||||
|
|
||||||
|
if version := is_present("GPSVersionID"):
|
||||||
print(f"{dict[piexif.GPSIFD.GPSVersionID]=}")
|
print(f"GPS exif {version=}")
|
||||||
|
|
||||||
|
if alt := extract("GPSAltitude"):
|
||||||
|
altitude = f"{alt:.0f}m above sea-level"
|
||||||
|
else:
|
||||||
|
altitude = ""
|
||||||
|
|
||||||
|
|
||||||
alt = extract("GPSAltitude")
|
if ds := is_present("GPSDateStamp"):
|
||||||
altitude = f"{alt:.0f}m above sea-level"
|
ds = ds.decode()
|
||||||
ds = dict[piexif.GPSIFD.GPSDateStamp]
|
else:
|
||||||
hf, mf, sf = dict[piexif.GPSIFD.GPSTimeStamp]
|
ds = ""
|
||||||
h = rational(hf)
|
|
||||||
m = rational(mf)
|
if item := is_present("GPSTimeStamp"):
|
||||||
s = rational(sf)
|
hf, mf, sf = item
|
||||||
|
h = rational(hf)
|
||||||
timestamp_utc = f"{ds.decode()} {h:02.0f}:{m:02.0f}:{s:02.0f} +00:00 UTC"
|
m = rational(mf)
|
||||||
|
s = rational(sf)
|
||||||
|
timestamp_utc = f"{ds} {h:02.0f}:{m:02.0f}:{s:02.0f} +00:00 UTC"
|
||||||
|
else:
|
||||||
|
timestamp_utc = f"{ds}"
|
||||||
|
|
||||||
|
|
||||||
print(direction)
|
print(direction)
|
||||||
print(altitude)
|
print(altitude)
|
||||||
print(timestamp_utc)
|
print(timestamp_utc)
|
||||||
# location = dms2dd()
|
# location = dms2dd() # to do...
|
||||||
|
|
||||||
return f"{direction}<br />{altitude}</br />{timestamp_utc}<br />"
|
return f"{direction}<br />{altitude}</br />{timestamp_utc}<br />"
|
||||||
|
|
||||||
@@ -176,12 +203,18 @@ def new_image_form(request, path):
|
|||||||
directory = get_dir(path)
|
directory = get_dir(path)
|
||||||
# print(f"new_image_form(): {directory=} {path=}")
|
# print(f"new_image_form(): {directory=} {path=}")
|
||||||
|
|
||||||
editor = get_cookie(request)
|
identified_login = is_identified_user(request.user)
|
||||||
|
editor = get_editor(request)
|
||||||
# print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}")
|
# print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}")
|
||||||
# FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory
|
# FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
# print(f"new_image_form(): POST ")
|
# print(f"new_image_form(): POST ")
|
||||||
form = NewWebImageForm(request.POST, request.FILES, directory=directory)
|
form = NewWebImageForm(request.POST, request.FILES, directory=directory)
|
||||||
|
if identified_login:
|
||||||
|
# disable editing the git id string as we get it from the logged-on user data
|
||||||
|
form.fields["who_are_you"].widget.attrs["readonly"]="readonly"
|
||||||
|
print(form.fields["who_are_you"].widget.attrs)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
# print(f"new_image_form(): form is valid ")
|
# print(f"new_image_form(): form is valid ")
|
||||||
year = form.cleaned_data["year"]
|
year = form.cleaned_data["year"]
|
||||||
@@ -271,14 +304,15 @@ def new_image_form(request, path):
|
|||||||
# print(full_path, full_path.parent)
|
# print(full_path, full_path.parent)
|
||||||
full_path.parent.mkdir(parents=True, exist_ok=True)
|
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
try:
|
try:
|
||||||
change_message = form.cleaned_data["change_message"]
|
# change_message = form.cleaned_data["change_message"]
|
||||||
write_and_commit(
|
write_and_commit(
|
||||||
[
|
[
|
||||||
(desc_path, image_page, "utf-8"),
|
(desc_path, image_page, "utf-8"),
|
||||||
(image_path, ib.getbuffer(), False),
|
(image_path, ib.getbuffer(), False),
|
||||||
(thumb_path, tb.getbuffer(), False),
|
(thumb_path, tb.getbuffer(), False),
|
||||||
],
|
],
|
||||||
f"{change_message} - online adding of an image",
|
# f"{change_message} - online adding of an image",
|
||||||
|
f"Online adding of an image",
|
||||||
editor # this works, a new who_are_you typed on the Image form is used as the git comment
|
editor # this works, a new who_are_you typed on the Image form is used as the git comment
|
||||||
)
|
)
|
||||||
except WriteAndCommitError as e:
|
except WriteAndCommitError as e:
|
||||||
@@ -302,6 +336,11 @@ def new_image_form(request, path):
|
|||||||
"year": "", "photographer": extract_git_name(editor),
|
"year": "", "photographer": extract_git_name(editor),
|
||||||
"change_message": "Uploading photo"}
|
"change_message": "Uploading photo"}
|
||||||
form = NewWebImageForm(directory=directory, initial=initial )
|
form = NewWebImageForm(directory=directory, initial=initial )
|
||||||
|
if identified_login:
|
||||||
|
# disable editing the git id string as we get it from the logged-on user data
|
||||||
|
form.fields["who_are_you"].widget.attrs["readonly"]="readonly"
|
||||||
|
print(form.fields["who_are_you"].widget.attrs)
|
||||||
|
|
||||||
# print(f"new_image_form(): POST and not POST ")
|
# print(f"new_image_form(): POST and not POST ")
|
||||||
template = loader.get_template("new_image_form.html")
|
template = loader.get_template("new_image_form.html")
|
||||||
htmlform = template.render({"form": form, "path": path}, request)
|
htmlform = template.render({"form": form, "path": path}, request)
|
||||||
@@ -322,6 +361,8 @@ def save_original_in_expofiles(f, year, photographer):
|
|||||||
get recorded properly in original format.
|
get recorded properly in original format.
|
||||||
|
|
||||||
Django does small files <2.5 MB in memory, which is a pain.
|
Django does small files <2.5 MB in memory, which is a pain.
|
||||||
|
|
||||||
|
to do: also store a *.url file with the image file saying where it is used in the handbook.
|
||||||
"""
|
"""
|
||||||
if photographer:
|
if photographer:
|
||||||
photographer = photographer.strip().replace(" ","")
|
photographer = photographer.strip().replace(" ","")
|
||||||
@@ -376,15 +417,18 @@ class NewWebImageForm(forms.Form):
|
|||||||
year = forms.CharField(
|
year = forms.CharField(
|
||||||
widget=forms.TextInput(attrs={"size": "60", "placeholder": "Year photo was taken"}), required=False
|
widget=forms.TextInput(attrs={"size": "60", "placeholder": "Year photo was taken"}), required=False
|
||||||
)
|
)
|
||||||
change_message = forms.CharField(
|
# change_message = forms.CharField(
|
||||||
widget=forms.Textarea(attrs={"cols": 80, "rows": 3, "placeholder": "Describe the change made (for git)"}), required=False
|
# widget=forms.Textarea(attrs={"cols": 80, "rows": 3, "placeholder": "Describe the change made (for git)"}), required=False
|
||||||
)
|
# )
|
||||||
who_are_you = forms.CharField(
|
who_are_you = forms.CharField(
|
||||||
widget=forms.TextInput(
|
widget=forms.TextInput(attrs={"style": "font-size: 90%", "size": "75",
|
||||||
attrs={"size": 60, "placeholder": "You are editing this page, who are you ? e.g. 'Becka' or 'Animal <mta@gasthof.expo>'",
|
"placeholder": "Anathema Device <anathema@potatohut.expo>",
|
||||||
"style": "vertical-align: text-top;"}
|
"title":"Type in your real name, and your email between angle-brackets."
|
||||||
|
}),
|
||||||
|
# label = "Editor",
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.directory = Path(kwargs.pop("directory"))
|
self.directory = Path(kwargs.pop("directory"))
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ from troggle.core.utils import (
|
|||||||
COOKIE_MAX_AGE,
|
COOKIE_MAX_AGE,
|
||||||
WriteAndCommitError,
|
WriteAndCommitError,
|
||||||
current_expo,
|
current_expo,
|
||||||
get_cookie,
|
get_editor,
|
||||||
git_string,
|
# get_cookie,
|
||||||
get_git_string,
|
# git_string,
|
||||||
|
# get_git_string,
|
||||||
write_and_commit,
|
write_and_commit,
|
||||||
is_identified_user
|
is_identified_user
|
||||||
)
|
)
|
||||||
@@ -462,11 +463,8 @@ def editexpopage(request, path):
|
|||||||
print("### File not found ### ", filepath)
|
print("### File not found ### ", filepath)
|
||||||
filefound = False
|
filefound = False
|
||||||
|
|
||||||
current_user = request.user
|
identified_login = is_identified_user(request.user)
|
||||||
if identified_login := is_identified_user(current_user):
|
editor = get_editor(request)
|
||||||
editor = get_git_string(current_user)
|
|
||||||
else:
|
|
||||||
editor = get_cookie(request)
|
|
||||||
|
|
||||||
if request.method == "POST": # If the form has been submitted...
|
if request.method == "POST": # If the form has been submitted...
|
||||||
pageform = ExpoPageForm(request.POST) # A form bound to the POST data
|
pageform = ExpoPageForm(request.POST) # A form bound to the POST data
|
||||||
@@ -503,9 +501,9 @@ def editexpopage(request, path):
|
|||||||
print(f"Cookie set: {editor} for {COOKIE_MAX_AGE/(24*3600)} days")
|
print(f"Cookie set: {editor} for {COOKIE_MAX_AGE/(24*3600)} days")
|
||||||
try:
|
try:
|
||||||
change_message = pageform.cleaned_data["change_message"]
|
change_message = pageform.cleaned_data["change_message"]
|
||||||
if not identified_login:
|
# if not identified_login:
|
||||||
editor = pageform.cleaned_data["who_are_you"]
|
# editor = pageform.cleaned_data["who_are_you"]
|
||||||
editor = git_string(editor)
|
# editor = git_string(editor)
|
||||||
write_and_commit([(filepath, result, "utf-8")], f"{change_message} - online edit of {path}", editor)
|
write_and_commit([(filepath, result, "utf-8")], f"{change_message} - online edit of {path}", editor)
|
||||||
except WriteAndCommitError as e:
|
except WriteAndCommitError as e:
|
||||||
return render(request, "errors/generic.html", {"message": e.message})
|
return render(request, "errors/generic.html", {"message": e.message})
|
||||||
@@ -556,9 +554,10 @@ class ExpoPageForm(forms.Form):
|
|||||||
identified_login = forms.BooleanField(required=False,widget=forms.CheckboxInput(attrs={"onclick":"return false"})) # makes it readonly
|
identified_login = forms.BooleanField(required=False,widget=forms.CheckboxInput(attrs={"onclick":"return false"})) # makes it readonly
|
||||||
|
|
||||||
who_are_you = forms.CharField(
|
who_are_you = forms.CharField(
|
||||||
widget=forms.Textarea(
|
widget=forms.TextInput(attrs={"style": "font-size: 90%", "size": "75",
|
||||||
attrs={"cols": 90, "rows": 1, "placeholder": "You have edited this page, who are you ? e.g. 'Animal <mta@gasthof.expo>'",
|
"placeholder": "Anathema Device <anathema@potatohut.expo>",
|
||||||
"style": "vertical-align: text-top;"}
|
"title":"Type in your real name, and your email between angle-brackets."
|
||||||
),
|
}),
|
||||||
label = "Editor"
|
label = "Editor",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,12 +20,10 @@ Passwords are only ever stored as hashes using the standard Django functions.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
todo = """
|
todo = """
|
||||||
- Not fully tested, needs experience
|
|
||||||
|
|
||||||
- Need to check/register with lists.wookware.org for email
|
- 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
|
SUPER_USERS = ["philip-sargent", "wookey"] # list of userids who get the same rights as "expoadmin" i.e. the Django control panel
|
||||||
|
|
||||||
USERS_FILE = "users.json"
|
USERS_FILE = "users.json"
|
||||||
ENCRYPTED_DIR = "encrypted"
|
ENCRYPTED_DIR = "encrypted"
|
||||||
|
|||||||
Reference in New Issue
Block a user