summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/TESTS/test_imports.py1
-rw-r--r--core/models/caves.py2
-rw-r--r--core/views/caves.py9
-rw-r--r--core/views/expo.py9
-rw-r--r--core/views/logbook_edit.py451
-rw-r--r--core/views/logbooks.py2
-rw-r--r--core/views/survex.py2
-rw-r--r--core/views/uploads.py426
-rw-r--r--core/views/wallets_edit.py14
9 files changed, 494 insertions, 422 deletions
diff --git a/core/TESTS/test_imports.py b/core/TESTS/test_imports.py
index e81054b..9a40041 100644
--- a/core/TESTS/test_imports.py
+++ b/core/TESTS/test_imports.py
@@ -54,6 +54,7 @@ class SimpleTest(SimpleTestCase):
from troggle.parsers.people import GetPersonExpeditionNameLookup
def test_import_views_uploads(self):
+ from troggle.core.views.logbook_edit import logbookedit
from troggle.core.views.uploads import dwgupload
def test_import_views_walletedit(self):
diff --git a/core/models/caves.py b/core/models/caves.py
index 0a910ef..a0ec04b 100644
--- a/core/models/caves.py
+++ b/core/models/caves.py
@@ -11,7 +11,7 @@ import settings
from troggle.core.models.logbooks import QM
from troggle.core.models.survex import SurvexStation, utmToLatLng
from troggle.core.models.troggle import DataIssue, TroggleModel
-from troggle.core.utils import TROG, parse_aliases
+from troggle.core.utils import TROG, parse_aliases
# Use the TROG global object to cache the cave lookup list. No good for multi-user.., or even multi-page. Pointless in fact.
Gcavelookup = TROG["caves"]["gcavelookup"]
diff --git a/core/views/caves.py b/core/views/caves.py
index a40b314..84f0569 100644
--- a/core/views/caves.py
+++ b/core/views/caves.py
@@ -20,7 +20,14 @@ from troggle.core.forms import CaveForm, EntranceForm, EntranceLetterForm # Cav
from troggle.core.models.caves import Cave, CaveAndEntrance, Entrance, GetCaveLookup, get_cave_leniently
from troggle.core.models.logbooks import QM
from troggle.core.models.wallets import Wallet
-from troggle.core.utils import COOKIE_MAX_AGE, WriteAndCommitError, current_expo, get_cookie, git_string, write_and_commit
+from troggle.core.utils import (
+ COOKIE_MAX_AGE,
+ WriteAndCommitError,
+ current_expo,
+ get_cookie,
+ git_string,
+ write_and_commit,
+)
from troggle.core.views import expo
from troggle.parsers.caves import read_cave, read_entrance
from troggle.settings import CAVEDESCRIPTIONS, ENTRANCEDESCRIPTIONS
diff --git a/core/views/expo.py b/core/views/expo.py
index d3d649b..019df18 100644
--- a/core/views/expo.py
+++ b/core/views/expo.py
@@ -14,7 +14,14 @@ from django.views.decorators.csrf import ensure_csrf_cookie
import troggle.core.views.caves
import troggle.settings as settings
from troggle.core.models.caves import Cave
-from troggle.core.utils import COOKIE_MAX_AGE, WriteAndCommitError, current_expo, get_cookie, git_string, write_and_commit
+from troggle.core.utils import (
+ COOKIE_MAX_AGE,
+ WriteAndCommitError,
+ current_expo,
+ get_cookie,
+ git_string,
+ write_and_commit,
+)
from troggle.core.views.editor_helpers import HTMLarea
from troggle.core.views.uploads import edittxtpage
diff --git a/core/views/logbook_edit.py b/core/views/logbook_edit.py
new file mode 100644
index 0000000..7411149
--- /dev/null
+++ b/core/views/logbook_edit.py
@@ -0,0 +1,451 @@
+import subprocess
+from datetime import datetime, timedelta, timezone
+from pathlib import Path
+
+from django import forms
+from django.core.files.storage import FileSystemStorage
+from django.http import HttpResponseRedirect
+from django.shortcuts import redirect, render
+
+import settings
+from troggle.core.models.caves import GetCaveLookup
+from troggle.core.models.logbooks import LogbookEntry, PersonLogEntry, writelogbook
+from troggle.core.models.survex import DrawingFile
+from troggle.core.models.troggle import DataIssue, Expedition, PersonExpedition
+from troggle.core.utils import (
+ COOKIE_MAX_AGE,
+ alphabet_suffix,
+ current_expo,
+ get_cookie,
+ git_string,
+ sanitize_name,
+ unique_slug,
+ write_and_commit,
+)
+from troggle.parsers.people import GetPersonExpeditionNameLookup, known_foreigner
+
+# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
+from .auth import login_required_if_public
+
+"""Logbook edit 'view'
+Note that there are other file upload forms in views/wallet_edit.py views/uploads.py
+and that core/forms.py contains Django class-based forms for caves and entrances.
+"""
+
+todo = """ - refactor git to use utils.py functions
+"""
+
+def create_new_lbe_slug(date):
+ onthisdate = LogbookEntry.objects.filter(date=date)
+ n = len(onthisdate)
+ print(f" Already entries on this date: {n}\n {onthisdate}")
+
+ suffix = alphabet_suffix(n+1)
+
+ tid = f"{date}{suffix}"
+ if len(tid) <=4 :
+ print(f"BAD ERROR {tid=}")
+ tid = f"{date}_{LogbookEntry.objects.count()}_{n}" # fudged number
+ print(f"{tid=}")
+ return tid
+
+def store_edited_entry_into_database(date, place, title, text, others, author, tu, slug):
+ """saves a single logbook entry and related personlogentry items
+
+ need to select out *guest and foreign friends from others
+
+ Rather similar to similarly named function in parsers/logbooks but circular reference prevents us using it directly,
+ and they need refactoring anyway.
+ """
+
+ year = slug[0:4]
+ expedition = Expedition.objects.get(year=year)
+ cave = GetCaveLookup().get(place.lower())
+ # print(f"store_edited_entry_into_database(): {place=} {cave=}")
+
+ if LogbookEntry.objects.filter(slug=slug).exists():
+ # oops.
+ message = f" ! - DUPLICATE SLUG for logbook entry {date} - {slug}"
+ DataIssue.objects.create(parser="logbooks", message=message)
+ slug = slug + "_" + unique_slug(text,2)
+
+ otherAttribs = {
+ "place": place,
+ "text": text,
+ "expedition": expedition,
+ "time_underground": tu,
+ "cave": cave,
+ "title": f"{place} - {title}",
+ # "other_people": others
+ }
+ coUniqueAttribs = {"slug": slug, "date": date }
+
+ lbo = LogbookEntry.objects.create(**otherAttribs, **coUniqueAttribs)
+
+ pt_list = []
+ # These entities have to be PersonExpedition objects
+ team = others.split(",")
+ team.append(author)
+
+ odds = []
+ for name in team:
+ name = name.strip()
+ if len(name) > 0:
+ if name[0] == "*": # a name prefix of "*" is special, just a string.
+ odds.append(name)
+ print(f" - adding * special name '{name}'")
+ else:
+ try:
+ personyear = GetPersonExpeditionNameLookup(expedition).get(name.lower())
+ if not personyear:
+ odds.append(name)
+ print(f" - adding unrecognised expoer '{name}'")
+ if known_foreigner(name):
+ message = f" ! - Known foreigner: '{name}' in entry {slug=}"
+ print(message)
+ else:
+ message = f" ! - No name match for: '{name}' in entry {slug=}"
+ print(message)
+ DataIssue.objects.create(parser="logbooks", message=message)
+ else:
+ coUniqueAttribs = {"personexpedition": personyear, "nickname_used": name, "logbook_entry": lbo} # lbo is primary key
+ otherAttribs = {"time_underground": tu, "is_logbook_entry_author": (name==author)}
+ pt_list.append(PersonLogEntry(**otherAttribs, **coUniqueAttribs))
+
+ except:
+ # This should not happen. We do not raise exceptions in that function
+ message = f" ! - EXCEPTION: '{name}' in entry {slug=}"
+ print(message)
+ DataIssue.objects.create(parser="logbooks", message=message)
+ raise
+
+ PersonLogEntry.objects.bulk_create(pt_list)
+
+ lbo.other_people = ", ".join(odds)
+ print(f" - Saving other_people '{lbo.other_people}'")
+ lbo.save()
+
+
+@login_required_if_public
+def logbookedit(request, year=None, slug=None):
+ """Edit a logbook entry
+
+ This 'validates' the author as being on expo in the current year, but only indicates this by
+ putting the text of the form prompt in red (same as for an invalid date, which is arguably more important).
+ No check is done on the other people on the trip as this is picked up anyway by parsing on import
+ and we don't really care at this point.
+ """
+ def yesterday():
+ yesterday = datetime.now() - timedelta(1)
+ return yesterday.strftime('%Y-%m-%d')
+
+ def validate_year(year):
+ try:
+ expo = Expedition.objects.get(year=year)
+ except:
+ year = current_expo() # creates new Expedition object if needed
+ return year
+
+ def new_entry_form():
+ # set the date to be "yesterday" as this will, hopefully, usually be the case
+
+ return render(
+ request,
+ "logbookform.html",
+ {
+ "form": form,
+ "year": year,
+ "yesterday": yesterday(),
+
+ },
+ )
+ def clean_tu(tu):
+ if tu =="":
+ return 0
+ try:
+ tu = float(tu)/1 # check numeric
+ except:
+ return 0
+ return tu
+
+ if not year:
+ if not slug: # not in the URL, we have not read teh POST response yet.. wich might have a slug in it
+ year = current_expo()
+ else:
+ year = slug[0:4]
+ try:
+ year = str(int(year)) # but maybe slug was hand-edited to be a future year..
+ year = validate_year(year) # so fix that
+ except:
+ year = current_expo()
+
+ author = ""
+
+ if request.method == "POST":
+ prev_slug = "" # None value pending overwrite from submitted form
+ form = LogbookEditForm(request.POST)
+ if not form.is_valid():
+ message = f'Invalid form response for logbook entry creating "{request.POST}"'
+ print(message)
+ return render(request, "errors/generic.html", {"message": message})
+ else:
+ # if there is no slug then this is probably a completely new lbe and we need to enter it into the db
+ # otherwise it is an update
+ # validation all to be done yet..
+ date = request.POST["date"].strip()
+ author = request.POST["author"].strip() # TODO check against personexpedition on submit
+ others = request.POST["others"].strip() # TODO check each against personexpedition on submit
+ place = request.POST["place"].strip().replace(' - ',' = ') # no hyphens !
+ title = request.POST["title"].strip()
+ entry = request.POST["text"].strip()
+ if "prev_slug" in request.POST:
+ prev_slug = request.POST["prev_slug"].strip() # if we are re-editing the same entry again
+ entry = entry.replace('\r','') # remove HTML-standard CR inserted from form.
+ entry = entry.replace('\n\n','\n<p>\n') # replace 2 \n with <p>
+ tu = request.POST["tu"].strip()
+ tu = clean_tu(tu)
+
+ try:
+ odate = datetime.strptime(date.replace(".", "-"), "%Y-%m-%d").date()
+ print(f"{odate.year=}")
+ if str(odate.year) == year:
+ dateflag = False
+ else:
+ print(f"Trying to change the year ! No!! {odate.year=}")
+ odate = datetime.strptime(f"{year}-01-01", "%Y-%m-%d").date()
+ dateflag = True
+ except:
+ odate = datetime.strptime(f"{year}-01-01", "%Y-%m-%d").date()
+ print(f"! Invalid date string {date}, setting to {odate}")
+ dateflag = True
+ date = odate.isoformat()
+
+ year = validate_year(year)
+ expo = Expedition.objects.get(year=year)
+ personyear = GetPersonExpeditionNameLookup(expo).get(author.lower())
+ if personyear:
+ authorflag = False
+ else:
+ authorflag = True
+ print(f"! Unrecognised author: {author}")
+
+ # if somehow we get a slug set to just '2024', not eg '2020-08-10b'
+ # because the URL of the page is /logbookedit/2022 for a new entry
+ # This is a hack, why can we not reproduce this bug on the dev system?
+ if slug not in locals():
+ slug = ""
+ if len(slug) < 11:
+ slug = ""
+ if len(prev_slug) < 11:
+ prev_slug = ""
+
+ if not prev_slug and not slug:
+ # Creating a new logbook entry with all the gubbins
+ slug = create_new_lbe_slug(date)
+
+ if prev_slug and not slug:
+ # if this was a previous post, then prev_slug will have been set on the form
+ # we are editing a previous thing, so we don't create a new lbe
+ slug = prev_slug
+
+ # OK we could patch the object in place, but if the people on the trip have changed this
+ # would get very messy. So we delete it, and thus all the dependent objects,
+ # and recreate it and all its links. It might not exist though.
+ print(f"- Deleting the LogBookEntry {slug}")
+ LogbookEntry.objects.filter(slug=slug).delete() # works even if it does not exist
+
+ print(f"- Creating the LogBookEntry {slug}")
+ year = slug[0:4]
+ try:
+ expedition = Expedition.objects.get(year=year)
+ except Expedition.DoesNotExist:
+ message = f'''! - This expo "{year}" not created yet
+ It needs to be created before you can save a logbook entry.
+ See /handbook/computing/newyear.html
+
+ WHAT TO DO NOW:
+ 1. Press the Back button on your proswer to return to the screen where you typed up the entry,
+ 2. Copy the text of what you wrote into a new text file,
+ 3. Direct a nerd to fix this. It should take only a couple of minutes.'''
+ print(message)
+ return render(request, "errors/generic.html", {"message": message})
+ store_edited_entry_into_database(date, place, title, entry, others, author, tu, slug)
+
+
+ print(f"- Rewriting the entire {year} logbook to disc ")
+ filename= "logbook.html"
+ try:
+ print(f" - Logbook for {year} to be exported and written out.")
+ writelogbook(year, filename) # uses a template, not the code fragment below which is just a visible hint to logged on user
+ except:
+ message = f'! - Logbook saving failed - \n!! Permissions failure ?! on attempting to save file "logbook.html"'
+ print(message)
+ return render(request, "errors/generic.html", {"message": message})
+
+ # Code fragment illustration - not actually what gets saved to database
+ output = f'''
+
+<div class="tripdate" id="{slug}">{date}</div>
+<div class="trippeople"><u>{author}</u>, {others}</div>
+<div class="triptitle">{place} - {title}</div>
+
+{entry}
+
+<div class="timeug">T/U {tu} hrs</div>
+<hr />
+
+'''
+ # Successful POST
+ # So save to database and then write out whole new logbook.html file
+
+ # We do author validation on the form as displayed by GET, not at the moment of POST.
+ # If we had JS validation then we could be more timely.
+ git = settings.GIT
+ dirpath = Path(settings.EXPOWEB) / "years" / str(year)
+ lbe_add = subprocess.run(
+ [git, "add", filename], cwd=dirpath, capture_output=True, text=True
+ )
+ msgdata = (
+ lbe_add.stderr
+ + "\n"
+ + lbe_add.stdout
+ + "\nreturn code: "
+ + str(lbe_add.returncode)
+ )
+ message = f'! - FORM Logbook Edit {slug} - Success: git ADD on server for this file {filename}.' + msgdata
+ print(message)
+ if lbe_add.returncode != 0:
+ msgdata = (
+ "Ask a nerd to fix this.\n\n"
+ + lbe_add.stderr
+ + "\n\n"
+ + lbe_add.stdout
+ + "\n\nreturn code: "
+ + str(lbe_add.returncode)
+ )
+ message = (
+ f"! - FORM Logbook Edit - CANNOT git ADD on server for this file {filename}. {slug} edits saved but not added to git.\n"
+ + msgdata
+ )
+ print(message)
+ return render(request, "errors/generic.html", {"message": message})
+
+ lbe_commit = subprocess.run(
+ [git, "commit", "-m", f"Logbook edited {slug}"],
+ cwd=dirpath,
+ capture_output=True,
+ text=True,
+ )
+ message = f'! - FORM Logbook Edit - {filename}. {slug} edits saved, added to git, and COMMITTED.\n' + msgdata
+ print(message)
+ #This produces return code = 1 if it commits OK
+ if lbe_commit.returncode != 0:
+ msgdata = (
+ "Ask a nerd to fix this.\n\n"
+ + lbe_commit.stderr
+ + "\n"
+ + lbe_commit.stdout
+ + "\nreturn code: "
+ + str(lbe_commit.returncode)
+ )
+ message = (
+ f"! - FORM Logbook Edit - Error code '{lbe_commit.returncode}' with git on server for {filename}. {slug} edits saved, added to git, but NOT committed.\n"
+ + msgdata
+ )
+ print(message)
+ if not (lbe_commit.returncode ==1 and settings.DEVSERVER):
+ # rc=1 is OK on the development server
+ return render(request, "errors/generic.html", {"message": message})
+
+ # This does not change the URL in the browser, so despite a new slug being created,
+ # the next time this code is run it thinks a new slug needs to be created. So we should
+ # actually redirect to a new URL (an edit not a create) not simply return a render object.
+ # logbookedit/2022-08-21a
+
+ # HOWEVER by doing a redirect rather than returning a rendered page, we lose all the
+ # error settings e.g dateflag and authroflag so the user gets no feedback about bad data entered.
+ # so we need to pass the flags explicitly int he url and then extract them from the request in the GET bit. sigh.
+ return HttpResponseRedirect(f"/logbookedit/{slug}?dateflag={dateflag}&authorflag={authorflag}")
+
+ # return render(
+ # request,
+ # "logbookform.html",
+ # {
+ # "form": form,
+ # "year": year,
+ # "date": date, "dateflag": dateflag,
+ # "author": author, "authorflag": authorflag,
+ # "others": others,
+ # "place": place,
+ # "title": title,
+ # "tu": tu,
+ # "entry": entry,
+ # "output": output,
+ # "slug": slug,
+ # },
+ # )
+ # GET here
+ else:
+ form = LogbookEditForm()
+ year = validate_year(year)
+
+ if request.GET.get('dateflag', 'False') == "True":
+ dateflag = True
+ else:
+ dateflag = False
+
+ if request.GET.get('authorflag', 'False') == "True":
+ authorflag = True
+ else:
+ authorflag = False
+
+ if not slug: # no slug or bad slug for an lbe which does not exist
+ return new_entry_form()
+ else:
+ lbes = LogbookEntry.objects.filter(slug=slug)
+ if not lbes:
+ return new_entry_form()
+ else:
+ if len(lbes) > 1:
+ return render(request, "object_list.html", {"object_list": lbes}) # ie a bug
+ else:
+ lbe = lbes[0]
+ print(f"{lbe}")
+ tu = clean_tu(lbe.time_underground)
+
+ people = []
+ for p in lbe.personlogentry_set.filter(logbook_entry=lbe): # p is a PersonLogEntry object
+ if p.is_logbook_entry_author:
+ # author = p.personexpedition.person.fullname
+ author = p.nickname_used
+ else:
+ # people.append(p.personexpedition.person.fullname)
+ people.append(p.nickname_used)
+ others =', '.join(people)
+ if lbe.other_people:
+ others = others + ", " + lbe.other_people
+ lenothers = min(70,max(20, len(others)))
+
+ text = lbe.text
+ rows = max(5,len(text)/50)
+ return render(
+ request,
+ "logbookform.html",
+ {
+ "form": form,
+ "year": year,
+ "date": lbe.date.isoformat(), "dateflag": dateflag,
+ "author": author, "authorflag": authorflag,
+ "others": others,
+ "lenothers": lenothers,
+ "place": lbe.place,
+ "title": lbe.title.replace(f"{lbe.place} - ",""),
+ "tu": tu,
+ "entry": text,
+ "textrows": rows,
+ "slug": slug,
+ },
+ )
+
+class LogbookEditForm(forms.Form): # not a model-form, just a form-form
+ author = forms.CharField(strip=True, required=False)
diff --git a/core/views/logbooks.py b/core/views/logbooks.py
index c71bab0..003b67f 100644
--- a/core/views/logbooks.py
+++ b/core/views/logbooks.py
@@ -1,9 +1,9 @@
import re
+from django.core.exceptions import ValidationError
from django.db.models import Q
from django.shortcuts import redirect, render
from django.views.generic.list import ListView
-from django.core.exceptions import ValidationError
import troggle.settings as settings
from troggle.core.models.logbooks import QM, LogbookEntry, PersonLogEntry, writelogbook
diff --git a/core/views/survex.py b/core/views/survex.py
index 4a258d4..f1877af 100644
--- a/core/views/survex.py
+++ b/core/views/survex.py
@@ -18,7 +18,7 @@ from troggle.core.models.caves import Cave, GetCaveLookup
from troggle.core.models.logbooks import LogbookEntry
from troggle.core.models.survex import SurvexBlock, SurvexFile #, SurvexDirectory
from troggle.core.models.wallets import Wallet
-from troggle.core.utils import COOKIE_MAX_AGE, current_expo, get_cookie, git_string, add_commit
+from troggle.core.utils import COOKIE_MAX_AGE, add_commit, current_expo, get_cookie, git_string
from troggle.parsers.survex import parse_one_file
"""Everything that views survexfiles
diff --git a/core/views/uploads.py b/core/views/uploads.py
index f4e2278..98e2c43 100644
--- a/core/views/uploads.py
+++ b/core/views/uploads.py
@@ -9,10 +9,18 @@ from django.shortcuts import redirect, render
import settings
from troggle.core.models.caves import GetCaveLookup
-from troggle.core.models.logbooks import LogbookEntry, PersonLogEntry, writelogbook
from troggle.core.models.survex import DrawingFile
from troggle.core.models.troggle import DataIssue, Expedition, PersonExpedition
-from troggle.core.utils import COOKIE_MAX_AGE, alphabet_suffix, current_expo, get_cookie, git_string, sanitize_name, unique_slug, write_and_commit
+from troggle.core.utils import (
+ COOKIE_MAX_AGE,
+ alphabet_suffix,
+ current_expo,
+ get_cookie,
+ git_string,
+ sanitize_name,
+ unique_slug,
+ write_and_commit,
+)
from troggle.parsers.people import GetPersonExpeditionNameLookup, known_foreigner
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
@@ -20,7 +28,7 @@ from .auth import login_required_if_public
"""File upload 'views'
Note that there are other file upload forms in views/wallet_edit.py
-and that core/forms.py contains Django class-based forms for caves and entrances.
+and views/logbook_edit.py and that core/forms.py contains Django class-based forms for caves and entrances.
"""
todo = """
@@ -42,95 +50,6 @@ todo = """
- Make file rename utility less ugly.
"""
-def create_new_lbe_slug(date):
- onthisdate = LogbookEntry.objects.filter(date=date)
- n = len(onthisdate)
- print(f" Already entries on this date: {n}\n {onthisdate}")
-
- suffix = alphabet_suffix(n+1)
-
- tid = f"{date}{suffix}"
- if len(tid) <=4 :
- print(f"BAD ERROR {tid=}")
- tid = f"{date}_{LogbookEntry.objects.count()}_{n}" # fudged number
- print(f"{tid=}")
- return tid
-
-def store_edited_entry_into_database(date, place, title, text, others, author, tu, slug):
- """saves a single logbook entry and related personlogentry items
-
- need to select out *guest and foreign friends from others
-
- Rather similar to similarly named function in parsers/logbooks but circular reference prevents us using it directly,
- and they need refactoring anyway.
- """
-
- year = slug[0:4]
- expedition = Expedition.objects.get(year=year)
- cave = GetCaveLookup().get(place.lower())
- # print(f"store_edited_entry_into_database(): {place=} {cave=}")
-
- if LogbookEntry.objects.filter(slug=slug).exists():
- # oops.
- message = f" ! - DUPLICATE SLUG for logbook entry {date} - {slug}"
- DataIssue.objects.create(parser="logbooks", message=message)
- slug = slug + "_" + unique_slug(text,2)
-
- otherAttribs = {
- "place": place,
- "text": text,
- "expedition": expedition,
- "time_underground": tu,
- "cave": cave,
- "title": f"{place} - {title}",
- # "other_people": others
- }
- coUniqueAttribs = {"slug": slug, "date": date }
-
- lbo = LogbookEntry.objects.create(**otherAttribs, **coUniqueAttribs)
-
- pt_list = []
- # These entities have to be PersonExpedition objects
- team = others.split(",")
- team.append(author)
-
- odds = []
- for name in team:
- name = name.strip()
- if len(name) > 0:
- if name[0] == "*": # a name prefix of "*" is special, just a string.
- odds.append(name)
- print(f" - adding * special name '{name}'")
- else:
- try:
- personyear = GetPersonExpeditionNameLookup(expedition).get(name.lower())
- if not personyear:
- odds.append(name)
- print(f" - adding unrecognised expoer '{name}'")
- if known_foreigner(name):
- message = f" ! - Known foreigner: '{name}' in entry {slug=}"
- print(message)
- else:
- message = f" ! - No name match for: '{name}' in entry {slug=}"
- print(message)
- DataIssue.objects.create(parser="logbooks", message=message)
- else:
- coUniqueAttribs = {"personexpedition": personyear, "nickname_used": name, "logbook_entry": lbo} # lbo is primary key
- otherAttribs = {"time_underground": tu, "is_logbook_entry_author": (name==author)}
- pt_list.append(PersonLogEntry(**otherAttribs, **coUniqueAttribs))
-
- except:
- # This should not happen. We do not raise exceptions in that function
- message = f" ! - EXCEPTION: '{name}' in entry {slug=}"
- print(message)
- DataIssue.objects.create(parser="logbooks", message=message)
- raise
-
- PersonLogEntry.objects.bulk_create(pt_list)
-
- lbo.other_people = ", ".join(odds)
- print(f" - Saving other_people '{lbo.other_people}'")
- lbo.save()
class FilesForm(forms.Form): # not a model-form, just a form-form
uploadfiles = forms.FileField()
@@ -157,8 +76,6 @@ class ExpotextfileForm(forms.Form): # not a model-form, just a form-form
)
)
-class LogbookEditForm(forms.Form): # not a model-form, just a form-form
- author = forms.CharField(strip=True, required=False)
@login_required_if_public
def edittxtpage(request, path, filepath):
@@ -255,327 +172,6 @@ def edittxtpage(request, path, filepath):
@login_required_if_public
-def logbookedit(request, year=None, slug=None):
- """Edit a logbook entry
-
- This 'validates' the author as being on expo in the current year, but only indicates this by
- putting the text of the form prompt in red (same as for an invalid date, which is arguably more important).
- No check is done on the other people on the trip as this is picked up anyway by parsing on import
- and we don't really care at this point.
- """
- def yesterday():
- yesterday = datetime.now() - timedelta(1)
- return yesterday.strftime('%Y-%m-%d')
-
- def validate_year(year):
- try:
- expo = Expedition.objects.get(year=year)
- except:
- year = current_expo() # creates new Expedition object if needed
- return year
-
- def new_entry_form():
- # set the date to be "yesterday" as this will, hopefully, usually be the case
-
- return render(
- request,
- "logbookform.html",
- {
- "form": form,
- "year": year,
- "yesterday": yesterday(),
-
- },
- )
- def clean_tu(tu):
- if tu =="":
- return 0
- try:
- tu = float(tu)/1 # check numeric
- except:
- return 0
- return tu
-
- if not year:
- if not slug: # not in the URL, we have not read teh POST response yet.. wich might have a slug in it
- year = current_expo()
- else:
- year = slug[0:4]
- try:
- year = str(int(year)) # but maybe slug was hand-edited to be a future year..
- year = validate_year(year) # so fix that
- except:
- year = current_expo()
-
- author = ""
-
- if request.method == "POST":
- prev_slug = "" # None value pending overwrite from submitted form
- form = LogbookEditForm(request.POST)
- if not form.is_valid():
- message = f'Invalid form response for logbook entry creating "{request.POST}"'
- print(message)
- return render(request, "errors/generic.html", {"message": message})
- else:
- # if there is no slug then this is probably a completely new lbe and we need to enter it into the db
- # otherwise it is an update
- # validation all to be done yet..
- date = request.POST["date"].strip()
- author = request.POST["author"].strip() # TODO check against personexpedition on submit
- others = request.POST["others"].strip() # TODO check each against personexpedition on submit
- place = request.POST["place"].strip().replace(' - ',' = ') # no hyphens !
- title = request.POST["title"].strip()
- entry = request.POST["text"].strip()
- if "prev_slug" in request.POST:
- prev_slug = request.POST["prev_slug"].strip() # if we are re-editing the same entry again
- entry = entry.replace('\r','') # remove HTML-standard CR inserted from form.
- entry = entry.replace('\n\n','\n<p>\n') # replace 2 \n with <p>
- tu = request.POST["tu"].strip()
- tu = clean_tu(tu)
-
- try:
- odate = datetime.strptime(date.replace(".", "-"), "%Y-%m-%d").date()
- print(f"{odate.year=}")
- if str(odate.year) == year:
- dateflag = False
- else:
- print(f"Trying to change the year ! No!! {odate.year=}")
- odate = datetime.strptime(f"{year}-01-01", "%Y-%m-%d").date()
- dateflag = True
- except:
- odate = datetime.strptime(f"{year}-01-01", "%Y-%m-%d").date()
- print(f"! Invalid date string {date}, setting to {odate}")
- dateflag = True
- date = odate.isoformat()
-
- year = validate_year(year)
- expo = Expedition.objects.get(year=year)
- personyear = GetPersonExpeditionNameLookup(expo).get(author.lower())
- if personyear:
- authorflag = False
- else:
- authorflag = True
- print(f"! Unrecognised author: {author}")
-
- # if somehow we get a slug set to just '2024', not eg '2020-08-10b'
- # because the URL of the page is /logbookedit/2022 for a new entry
- # This is a hack, why can we not reproduce this bug on the dev system?
- if slug not in locals():
- slug = ""
- if len(slug) < 11:
- slug = ""
- if len(prev_slug) < 11:
- prev_slug = ""
-
- if not prev_slug and not slug:
- # Creating a new logbook entry with all the gubbins
- slug = create_new_lbe_slug(date)
-
- if prev_slug and not slug:
- # if this was a previous post, then prev_slug will have been set on the form
- # we are editing a previous thing, so we don't create a new lbe
- slug = prev_slug
-
- # OK we could patch the object in place, but if the people on the trip have changed this
- # would get very messy. So we delete it, and thus all the dependent objects,
- # and recreate it and all its links. It might not exist though.
- print(f"- Deleting the LogBookEntry {slug}")
- LogbookEntry.objects.filter(slug=slug).delete() # works even if it does not exist
-
- print(f"- Creating the LogBookEntry {slug}")
- year = slug[0:4]
- try:
- expedition = Expedition.objects.get(year=year)
- except Expedition.DoesNotExist:
- message = f'''! - This expo "{year}" not created yet
- It needs to be created before you can save a logbook entry.
- See /handbook/computing/newyear.html
-
- WHAT TO DO NOW:
- 1. Press the Back button on your proswer to return to the screen where you typed up the entry,
- 2. Copy the text of what you wrote into a new text file,
- 3. Direct a nerd to fix this. It should take only a couple of minutes.'''
- print(message)
- return render(request, "errors/generic.html", {"message": message})
- store_edited_entry_into_database(date, place, title, entry, others, author, tu, slug)
-
-
- print(f"- Rewriting the entire {year} logbook to disc ")
- filename= "logbook.html"
- try:
- print(f" - Logbook for {year} to be exported and written out.")
- writelogbook(year, filename) # uses a template, not the code fragment below which is just a visible hint to logged on user
- except:
- message = f'! - Logbook saving failed - \n!! Permissions failure ?! on attempting to save file "logbook.html"'
- print(message)
- return render(request, "errors/generic.html", {"message": message})
-
- # Code fragment illustration - not actually what gets saved to database
- output = f'''
-
-<div class="tripdate" id="{slug}">{date}</div>
-<div class="trippeople"><u>{author}</u>, {others}</div>
-<div class="triptitle">{place} - {title}</div>
-
-{entry}
-
-<div class="timeug">T/U {tu} hrs</div>
-<hr />
-
-'''
- # Successful POST
- # So save to database and then write out whole new logbook.html file
-
- # We do author validation on the form as displayed by GET, not at the moment of POST.
- # If we had JS validation then we could be more timely.
- git = settings.GIT
- dirpath = Path(settings.EXPOWEB) / "years" / str(year)
- lbe_add = subprocess.run(
- [git, "add", filename], cwd=dirpath, capture_output=True, text=True
- )
- msgdata = (
- lbe_add.stderr
- + "\n"
- + lbe_add.stdout
- + "\nreturn code: "
- + str(lbe_add.returncode)
- )
- message = f'! - FORM Logbook Edit {slug} - Success: git ADD on server for this file {filename}.' + msgdata
- print(message)
- if lbe_add.returncode != 0:
- msgdata = (
- "Ask a nerd to fix this.\n\n"
- + lbe_add.stderr
- + "\n\n"
- + lbe_add.stdout
- + "\n\nreturn code: "
- + str(lbe_add.returncode)
- )
- message = (
- f"! - FORM Logbook Edit - CANNOT git ADD on server for this file {filename}. {slug} edits saved but not added to git.\n"
- + msgdata
- )
- print(message)
- return render(request, "errors/generic.html", {"message": message})
-
- lbe_commit = subprocess.run(
- [git, "commit", "-m", f"Logbook edited {slug}"],
- cwd=dirpath,
- capture_output=True,
- text=True,
- )
- message = f'! - FORM Logbook Edit - {filename}. {slug} edits saved, added to git, and COMMITTED.\n' + msgdata
- print(message)
- #This produces return code = 1 if it commits OK
- if lbe_commit.returncode != 0:
- msgdata = (
- "Ask a nerd to fix this.\n\n"
- + lbe_commit.stderr
- + "\n"
- + lbe_commit.stdout
- + "\nreturn code: "
- + str(lbe_commit.returncode)
- )
- message = (
- f"! - FORM Logbook Edit - Error code '{lbe_commit.returncode}' with git on server for {filename}. {slug} edits saved, added to git, but NOT committed.\n"
- + msgdata
- )
- print(message)
- if not (lbe_commit.returncode ==1 and settings.DEVSERVER):
- # rc=1 is OK on the development server
- return render(request, "errors/generic.html", {"message": message})
-
- # This does not change the URL in the browser, so despite a new slug being created,
- # the next time this code is run it thinks a new slug needs to be created. So we should
- # actually redirect to a new URL (an edit not a create) not simply return a render object.
- # logbookedit/2022-08-21a
-
- # HOWEVER by doing a redirect rather than returning a rendered page, we lose all the
- # error settings e.g dateflag and authroflag so the user gets no feedback about bad data entered.
- # so we need to pass the flags explicitly int he url and then extract them from the request in the GET bit. sigh.
- return HttpResponseRedirect(f"/logbookedit/{slug}?dateflag={dateflag}&authorflag={authorflag}")
-
- # return render(
- # request,
- # "logbookform.html",
- # {
- # "form": form,
- # "year": year,
- # "date": date, "dateflag": dateflag,
- # "author": author, "authorflag": authorflag,
- # "others": others,
- # "place": place,
- # "title": title,
- # "tu": tu,
- # "entry": entry,
- # "output": output,
- # "slug": slug,
- # },
- # )
- # GET here
- else:
- form = LogbookEditForm()
- year = validate_year(year)
-
- if request.GET.get('dateflag', 'False') == "True":
- dateflag = True
- else:
- dateflag = False
-
- if request.GET.get('authorflag', 'False') == "True":
- authorflag = True
- else:
- authorflag = False
-
- if not slug: # no slug or bad slug for an lbe which does not exist
- return new_entry_form()
- else:
- lbes = LogbookEntry.objects.filter(slug=slug)
- if not lbes:
- return new_entry_form()
- else:
- if len(lbes) > 1:
- return render(request, "object_list.html", {"object_list": lbes}) # ie a bug
- else:
- lbe = lbes[0]
- print(f"{lbe}")
- tu = clean_tu(lbe.time_underground)
-
- people = []
- for p in lbe.personlogentry_set.filter(logbook_entry=lbe): # p is a PersonLogEntry object
- if p.is_logbook_entry_author:
- # author = p.personexpedition.person.fullname
- author = p.nickname_used
- else:
- # people.append(p.personexpedition.person.fullname)
- people.append(p.nickname_used)
- others =', '.join(people)
- if lbe.other_people:
- others = others + ", " + lbe.other_people
- lenothers = min(70,max(20, len(others)))
-
- text = lbe.text
- rows = max(5,len(text)/50)
- return render(
- request,
- "logbookform.html",
- {
- "form": form,
- "year": year,
- "date": lbe.date.isoformat(), "dateflag": dateflag,
- "author": author, "authorflag": authorflag,
- "others": others,
- "lenothers": lenothers,
- "place": lbe.place,
- "title": lbe.title.replace(f"{lbe.place} - ",""),
- "tu": tu,
- "entry": text,
- "textrows": rows,
- "slug": slug,
- },
- )
-
-@login_required_if_public
def expofilerename(request, filepath):
"""Rename any single file in /expofiles/ - eventually.
Currently this just does files within wallets i.e. in /surveyscans/
diff --git a/core/views/wallets_edit.py b/core/views/wallets_edit.py
index 2c8ffe3..e36e7e4 100644
--- a/core/views/wallets_edit.py
+++ b/core/views/wallets_edit.py
@@ -19,8 +19,18 @@ from troggle.core.models.logbooks import LogbookEntry # , PersonLogEntry
from troggle.core.models.survex import SurvexBlock, SurvexFile, SurvexPersonRole
from troggle.core.models.troggle import DataIssue, Expedition
from troggle.core.models.wallets import YEAR_RANGE, Wallet, make_valid_date
-from troggle.core.utils import COOKIE_MAX_AGE, WriteAndCommitError, add_commit, current_expo, get_cookie, git_add, \
- git_commit, git_string, sanitize_name, write_and_commit
+from troggle.core.utils import (
+ COOKIE_MAX_AGE,
+ WriteAndCommitError,
+ add_commit,
+ current_expo,
+ get_cookie,
+ git_add,
+ git_commit,
+ git_string,
+ sanitize_name,
+ write_and_commit,
+)
from troggle.core.views.auth import login_required_if_public
from troggle.core.views.caves import get_cave_leniently, getCave
from troggle.core.views.scans import caveifywallet, oldwallet