From 7345e3a3286ebf2771a7c7800c83632cc9930fa1 Mon Sep 17 00:00:00 2001
From: Philip Sargent
Date: Fri, 17 Mar 2023 20:01:52 +0000
Subject: [PATCH] Much QM re-engineering
---
core/admin.py | 22 ++---
core/models/caves.py | 18 +++-
core/models/logbooks.py | 35 ++------
core/views/caves.py | 14 +--
md5bash.sh | 79 ++++++++++++++++
parsers/QMs.py | 53 ++++++-----
parsers/survex.py | 9 +-
templates/cave_qms.html | 43 ++++-----
templates/core/QMs_json_list.html | 12 ---
templates/qm.html | 145 +++++++++++++++---------------
10 files changed, 252 insertions(+), 178 deletions(-)
create mode 100644 md5bash.sh
diff --git a/core/admin.py b/core/admin.py
index bfbd727..b7c0d2b 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -47,11 +47,11 @@ class SurvexBlockAdmin(TroggleModelAdmin):
inlines = (RoleInline,)
-class QMsFoundInline(admin.TabularInline):
- model = QM
- fk_name = "found_by"
- fields = ("number", "grade", "location_description", "comment") # need to add foreignkey to cave part
- extra = 1
+# class QMsFoundInline(admin.TabularInline):
+ # model = QM
+ # fk_name = "found_by"
+ # fields = ("number", "grade", "location_description", "comment") # need to add foreignkey to cave part
+ # extra = 1
class PersonLogEntryInline(admin.TabularInline):
@@ -64,7 +64,7 @@ class LogbookEntryAdmin(TroggleModelAdmin):
prepopulated_fields = {"slug": ("title",)}
search_fields = ("title", "expedition__year")
date_heirarchy = "date"
- inlines = (PersonLogEntryInline, QMsFoundInline)
+ # inlines = (PersonLogEntryInline, QMsFoundInline)
class Media:
css = {"all": ("css/troggleadmin.css",)} # this does not exist
@@ -91,12 +91,12 @@ class PersonAdmin(TroggleModelAdmin):
class QMAdmin(TroggleModelAdmin):
- search_fields = ("found_by__cave__kataster_number", "number", "found_by__date")
- list_display = ("__str__", "grade", "found_by", "ticked_off_by")
+ search_fields = ("number", "expoyear")
+ list_display = ("__str__", "grade")
list_display_links = ("__str__",)
- list_editable = ("found_by", "ticked_off_by", "grade")
- list_per_page = 20
- raw_id_fields = ("found_by", "ticked_off_by")
+ # list_editable = ("comment", "page_ref", "grade")
+ # list_per_page = 20
+ # raw_id_fields = ("found_by", "ticked_off_by")
class PersonExpeditionAdmin(TroggleModelAdmin):
diff --git a/core/models/caves.py b/core/models/caves.py
index 6492698..8b23ceb 100644
--- a/core/models/caves.py
+++ b/core/models/caves.py
@@ -1,4 +1,5 @@
import os
+import os
import re
from collections import defaultdict
from datetime import datetime, timezone
@@ -161,14 +162,27 @@ class Cave(TroggleModel):
def __str__(self, sep=": "):
return str(self.slug())
- def get_QMs(self):
+ def get_open_QMs(self):
"""Searches for all QMs that reference this cave."""
# qms = self.qm_set.all().order_by('expoyear', 'block__date')
qms = QM.objects.filter(cave=self).order_by(
"expoyear", "block__date"
) # a QuerySet, see https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
- return qms # a QuerySet
+ qmsopen = qms.filter(ticked=False)
+ return qmsopen # a QuerySet
+ def get_ticked_QMs(self):
+ """Searches for all QMs that reference this cave."""
+ qms = QM.objects.filter(cave=self).order_by(
+ "expoyear", "block__date"
+ )
+ qmticked = qms.filter(ticked=True)
+ return qmticked # a QuerySet
+
+ def get_QMs(self):
+ qms = self.get_open_QMs() | self.get_ticked_QMs() # set union operation
+ return qms # a QuerySet
+
def kat_area(self):
for a in self.area.all():
if a.kat_area():
diff --git a/core/models/logbooks.py b/core/models/logbooks.py
index 226f8e5..b594945 100644
--- a/core/models/logbooks.py
+++ b/core/models/logbooks.py
@@ -144,38 +144,19 @@ class QM(TroggleModel):
number = models.IntegerField(
help_text="this is the sequential number in the year, only unique for CSV imports",
)
+ grade = models.CharField(max_length=1, blank=True, null=True, help_text="A/B/C/D/X")
cave = models.ForeignKey("Cave", related_name="QMs", blank=True, null=True, on_delete=models.SET_NULL)
block = models.ForeignKey("SurvexBlock", null=True, on_delete=models.SET_NULL) # only for QMs from survex files
blockname = models.TextField(blank=True, null=True) # NB truncated copy of survexblock name with last char added
- expoyear = models.CharField(
- max_length=4, blank=True, null=True
- ) # could change to datetime if logbooks similarly chnaged
- found_by = models.ForeignKey(
- LogbookEntry, related_name="QMs_found", blank=True, null=True, on_delete=models.SET_NULL
- )
- ticked = models.BooleanField(
- default=False
- ) # for ticked QMs not attached to a logbook entry, should imply completion_description has text
- ticked_off_by = models.ForeignKey(
- LogbookEntry, related_name="QMs_ticked_off", blank=True, null=True, on_delete=models.SET_NULL
- ) # unused, ever?!
-
- GRADE_CHOICES = (
- ("A", "A: Large obvious lead"),
- ("B", "B: Average lead"),
- ("C", "C: Tight unpromising lead"),
- ("D", "D: Dig"),
- ("X", "X: Unclimbable or horrid"),
- ("V", "V: Vertical"),
- ) # also seen "?" in imported data - see urls.py
- grade = models.CharField(max_length=1, choices=GRADE_CHOICES)
+ expoyear = models.CharField(max_length=4, blank=True, null=True)
+ ticked = models.BooleanField(default=False)
location_description = models.TextField(blank=True)
- nearest_station_description = models.CharField(max_length=400, blank=True, null=True)
+ completion_description = models.TextField(blank=True)
+ completion_date = models.DateField(blank=True, null=True)
nearest_station_name = models.CharField(max_length=200, blank=True, null=True)
resolution_station_name = models.CharField(max_length=200, blank=True, null=True)
- nearest_station = models.ForeignKey("SurvexStation", blank=True, null=True, on_delete=models.SET_NULL)
area = models.CharField(max_length=100, blank=True, null=True)
- completion_description = models.TextField(blank=True, null=True)
+ page_ref = models.TextField(blank=True, null=True)
comment = models.TextField(blank=True, null=True)
def __str__(self):
@@ -228,8 +209,8 @@ class QM(TroggleModel):
),
)
- def get_next_by_id(self):
+ def get_next_by_id(self): # called in template
return QM.objects.get(id=self.id + 1)
- def get_previous_by_id(self):
+ def get_previous_by_id(self): # called in template
return QM.objects.get(id=self.id - 1)
diff --git a/core/views/caves.py b/core/views/caves.py
index fa5e7ef..c866718 100644
--- a/core/views/caves.py
+++ b/core/views/caves.py
@@ -536,9 +536,11 @@ def caveQMs(request, slug):
def qm(request, cave_id, qm_id, year, grade=None, blockname=None):
"""Reports on one specific QM
Fixed and working July 2022, for both CSV imported QMs
- needs refactoring though.
+
+ Needs refactoring though! Uses extremely baroque way of getting the QMs instead of querying for QM objects
+ directly, presumably as a result of a baroque history.
- 290 has several QMS with the same number, grade, year (2108) and first 8 chars of the survexblock. This crashes things.
+ Many caves have several QMS with the same number, grade, year (2018) and first 8 chars of the survexblock. This crashes things, so the terminal char of the survexblock name was added
"""
year = int(year)
@@ -547,7 +549,7 @@ def qm(request, cave_id, qm_id, year, grade=None, blockname=None):
# CSV import QMs, use old technique
try:
c = getCave(cave_id)
- manyqms = c.get_QMs()
+ manyqms = c.get_open_QMs() | c.get_ticked_QMs() # set union operation
qm = manyqms.get(number=qm_id, expoyear=year)
return render(request, "qm.html", {"qm": qm})
except QM.DoesNotExist:
@@ -565,12 +567,12 @@ def qm(request, cave_id, qm_id, year, grade=None, blockname=None):
qmslug = f"{cave_id}-{year}-{blockname=}{qm_id}{grade}"
print(f"{qmslug=}")
c = getCave(cave_id)
- manyqms = c.get_QMs()
+ manyqms = c.get_open_QMs() | c.get_ticked_QMs() # set union operation
qmqs = manyqms.filter(expoyear=year, blockname=blockname, number=qm_id, grade=grade)
if len(qmqs) > 1:
for q in qmqs:
print(qmqs)
- message = f"Multiple QMs with the same cave, year, number, grade AND first 8 chars of the survexblock name. (Could be caused by incomplete databasereset). Fix this in the survex file(s). {cave_id=} {year=} {qm_id=} {blockname=}"
+ message = f"Multiple QMs with the same cave, year, number, grade AND first-several+terminal chars of the survexblock name. (Could be caused by incomplete databasereset). Fix this in the survex file(s). {cave_id=} {year=} {qm_id=} {blockname=}"
return render(request, "errors/generic.html", {"message": message})
else:
qm = qmqs.get(expoyear=year, blockname=blockname, number=qm_id, grade=grade)
@@ -588,7 +590,7 @@ def qm(request, cave_id, qm_id, year, grade=None, blockname=None):
{"badslug": f"Failed get {cave_id=} {year=} {qm_id=} {grade=} {blockname=}"},
)
except MultipleObjectsReturned:
- message = f"Multiple QMs with the same cave, year, number, grade AND first 8 chars of the survexblock name. (Could be caused by incomplete databasereset). Fix this in the survex file(s). {cave_id=} {year=} {qm_id=} {blockname=}"
+ message = f"Multiple QMs with the same cave, year, number, grade AND first-several+terminal chars of the survexblock name. (Could be caused by incomplete databasereset). Fix this in the survex file(s). {cave_id=} {year=} {qm_id=} {blockname=}"
return render(request, "errors/generic.html", {"message": message})
except QM.DoesNotExist:
# raise
diff --git a/md5bash.sh b/md5bash.sh
new file mode 100644
index 0000000..9a2ed8f
--- /dev/null
+++ b/md5bash.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+# read in the input string from command line arguments
+input=$1
+
+# pad the input string with a single "1" bit
+padded_input="$input"$(echo -ne '\x80')
+
+# pad the input string to a multiple of 512 bits (64 bytes)
+while (( $(echo -n "$padded_input" | wc -c) % 64 != 56 ))
+do
+ padded_input="$padded_input"$(echo -ne '\x00')
+done
+
+# append the length of the input string (in bits) as a 64-bit little-endian integer
+length=$(echo -n "$input" | wc -c)
+length=$(echo "obase=16; $length * 8" | bc | xxd -p -c 16 | tac | tr -d '\n')
+while (( $(echo -n "$length" | wc -c) < 16 ))
+do
+ length="$length"0
+done
+padded_input="$padded_input"$(echo -ne "$length" | xxd -r -p)
+
+# initialize the buffer (A, B, C, D)
+A="67452301"
+B="efcdab89"
+C="98badcfe"
+D="10325476"
+
+# process the input in 512-bit (64-byte) chunks
+for (( i=0; i<$(echo -n "$padded_input" | wc -c)/64; i++ ))
+do
+ chunk=$(echo -n "$padded_input" | dd bs=64 skip=$i count=1 2>/dev/null | xxd -p -c 64)
+
+ # initialize the message schedule (M)
+ M=()
+ for (( j=0; j<16; j++ ))
+ do
+ word=$(echo -ne "${chunk:$j*8:8}" | xxd -r -p | od -An -tu4 -v)
+ M+=($word)
+ done
+ for (( j=16; j<64; j++ ))
+ do
+ word1=${M[j-15]}
+ s0=$(( (word1>>7 | word1<<25) ^ (word1>>18 | word1<<14) ^ (word1>>3) ))
+
+ word2=${M[j-2]}
+ s1=$(( (word2>>17 | word2<<15) ^ (word2>>19 | word2<<13) ^ (word2>>10) ))
+
+ M+=($((M[j-16] + s0 + M[j-7] + s1)))
+ done
+
+ # initialize the working variables
+ AA=$A
+ BB=$B
+ CC=$C
+ DD=$D
+
+ # round 1
+ for (( j=0; j<16; j++ ))
+ do
+ F=$(( (B & C) | (~B & D) ))
+ g=$j
+ dTemp=$((D))
+ D=$((C))
+ C=$((B))
+ B=$((B + ((A + F + M[g] + 0xd76aa478) & 0xffffffff)))
+ A=$((dTemp))
+ done
+
+ # round 2
+ for (( j=16; j<32; j++ ))
+ do
+ F=$(( (D & B) | (~D & C) ))
+ g=$(( (5*j + 1) % 16 ))
+ dTemp=$((D))
+ D=$((C))
+ C=$((B))
+
diff --git a/parsers/QMs.py b/parsers/QMs.py
index 7a553be..f3044ff 100644
--- a/parsers/QMs.py
+++ b/parsers/QMs.py
@@ -65,7 +65,6 @@ def parseCaveQMs(cave, inputFile, ticked=False):
nqms = parse_KH_QMs(kh, inputFile=inputFile, ticked=ticked)
return nqms
- # qmPath = settings.EXPOWEB+inputFile
qmPath = Path(settings.EXPOWEB, inputFile)
with open(qmPath, "r") as qmCSVContents:
@@ -76,15 +75,17 @@ def parseCaveQMs(cave, inputFile, ticked=False):
n = 0
nqms = 0
for line in qmReader:
+ #"Number","Grade","Area","Description","Page reference","Nearest survey station","Completion description","Comment"
try:
n += 1
year = int(line[0][1:5])
f"PH_{int(year)}_{int(n):02d}"
QMnum = re.match(r".*?-\d*?-X?(?P\d*)", line[0]).group("numb")
- newQM = QM()
+ newQM = QM() # creates python object, does not touch db yet
# newQM.found_by=placeholder
newQM.number = QMnum
newQM.cave = caveid
+ newQM.expoyear = year
newQM.blockname = ""
if line[1] == "Dig":
newQM.grade = "D"
@@ -92,32 +93,28 @@ def parseCaveQMs(cave, inputFile, ticked=False):
newQM.grade = line[1]
newQM.area = line[2]
newQM.location_description = line[3]
-
+ newQM.page_ref = line[4]
# In the table, completion is indicated by the presence of a completion discription.
- newQM.completion_description = line[4]
- newQM.nearest_station_description = line[5]
+ newQM.nearest_station_name = line[5]
+ newQM.completion_description = line[6]
if newQM.completion_description:
newQM.ticked = True
else:
newQM.ticked = False
- newQM.comment = line[6]
+ newQM.comment = line[7]
try:
# year and number are unique for a cave in CSV imports
preexistingQM = QM.objects.get(
- number=QMnum, found_by__date__year=year
- ) # if we don't have this one in the DB, save it
- if (
- preexistingQM.new_since_parsing is False
- ): # if the pre-existing QM has not been modified, overwrite it - VERY OLD THING
+ number=QMnum, expoyear=year, cave=caveid,
+ )
+ if preexistingQM:
+ message = f" ! - {qmPath} PRE-EXISTING QM - should not exist ! {str(line)} "
+ print(message)
+ DataIssue.objects.create(parser="QMs", message=message)
preexistingQM.delete()
- newQM.expoyear = year
- newQM.save()
- else: # otherwise, print that it was ignored
- print((" - preserving " + str(preexistingQM) + ", which was edited in admin \r"))
-
+ newQM.save()
except QM.DoesNotExist: # if there is no pre-existing QM, save the new one
- newQM.expoyear = year
newQM.save()
nqms += 1
except KeyError: # check on this one
@@ -130,6 +127,12 @@ def parseCaveQMs(cave, inputFile, ticked=False):
print(message)
DataIssue.objects.create(parser="QMs", message=message)
continue
+ except:
+ message = f" ! - {qmPath} UNKNOWN error {str(line)} "
+ print(message)
+ DataIssue.objects.create(parser="QMs", message=message)
+ raise
+ continue
return nqms
@@ -139,8 +142,9 @@ def parse_KH_QMs(kh, inputFile, ticked):
khQMs = khQMfile.readlines()
nqms = 0
for line in khQMs:
+ # C1997-161-27 ASib: pitch at end of Fuzzy Logic [Paradox Rift - continues] [sep.fuzzy.13]
res = re.search(
- r"name=\"[CB](?P\d*)-(?P\d*)-(?P\d*).* (?P[ABDCV])(?P.*)\[(?P.*)\]",
+ r"name=\"[CB](?P\d*)-(?P\d*)-(?P\d*).* (?P[ABCDX])(?P.*)\[(?P.*)\]",
line,
)
if res:
@@ -157,8 +161,10 @@ def parse_KH_QMs(kh, inputFile, ticked):
}
nonLookupAttribs = {
"ticked": ticked,
- "nearest_station_name": res["nearest_station"],
- "location_description": res["description"],
+ "page_ref": "",
+ "completion_description": "",
+ "nearest_station_name": res["nearest_station_name"],
+ "location_description": res["location_description"],
}
# Create new. We know it doesn't exist as we deleted evrything when we started.
instance = QM.objects.create(**nonLookupAttribs, **lookupAttribs)
@@ -169,8 +175,11 @@ def parse_KH_QMs(kh, inputFile, ticked):
def Load_QMs():
deleteQMs()
- n204 = parseCaveQMs(cave="204-steinBH", inputFile=r"1623/204/qm.csv")
- n234 = parseCaveQMs(cave="234-Hauch", inputFile=r"1623/234/qm.csv")
+ #Number Grade Area Description Page reference Nearest station Completion description Comment
+ n204 = parseCaveQMs(cave="204-steinBH", inputFile=r"1623/204/qm-204.csv") # TAB separated values
+
+ #"Number","Grade","Area","Description","Page reference","Nearest survey station","Completion description","Comment"
+ n234 = parseCaveQMs(cave="234-Hauch", inputFile=r"1623/234/qm-234.csv") # COMMA separated values, with quotes.
n161 = parseCaveQMs(cave="161-KH", inputFile="1623/161/qmtodo.htm", ticked=False)
t161 = parseCaveQMs(cave="161-KH", inputFile="1623/161/qmdone.htm", ticked=True)
# parseCaveQMs(cave='balkonhoehle',inputFile=r"1623/264/qm.csv")
diff --git a/parsers/survex.py b/parsers/survex.py
index d8eda23..79e90d1 100644
--- a/parsers/survex.py
+++ b/parsers/survex.py
@@ -1309,7 +1309,10 @@ class LoadingSurvex:
insp = self.insp
# create a short, hopefully-unique name for this block to be used in the QM id
- blockname = survexblock.name[:6] + survexblock.name[-1:]
+ if len(survexblock.name) < 7:
+ blockname = survexblock.name
+ else:
+ blockname = survexblock.name[:6] + survexblock.name[-1:]
# logslug = f'D{int(qmyear)}_{blockname}_{int(qm_no):03d}'
qm_ticked = False # default
@@ -1319,7 +1322,7 @@ class LoadingSurvex:
self.TickSurvexQM(survexblock, qmline)
return
- if qm_grade not in ["A", "B", "C", "D", "X", "V", "?"]:
+ if qm_grade not in ["A", "B", "C", "D", "X"]: # "V", "?" not allowed in survex file QMs
message = f" ! QM{qm_no} INVALID code '{qm_grade}' [{blockname}] '{survexblock.survexfile.path}'"
print(insp + message)
stash_data_issue(
@@ -1336,7 +1339,7 @@ class LoadingSurvex:
pass
else:
qm_ticked = True
- print(f"{survexblock.survexfile.cave} {survexblock}:{qm_no}{qm_grade} {qmline.group(4)}", file=sys.stderr)
+ # print(f"{survexblock.survexfile.cave} {survexblock}:{qm_no}{qm_grade} {qmline.group(4)}", file=sys.stderr)
if resolution_station_name:
qm_ticked = True
# if qmline.group(6) and qmline.group(6) != "-":
diff --git a/templates/cave_qms.html b/templates/cave_qms.html
index 8b042d3..f55ce9b 100644
--- a/templates/cave_qms.html
+++ b/templates/cave_qms.html
@@ -20,39 +20,42 @@
1626-359 QMs Homecoming
+ For how to set up your own QMs, see Adding QMs .
For full explanation of the current status of the QM system(s), see scriptsqms page.
{% endblock %}
{% block content %}
-
Extant
- {% if cave.get_QMs %}
-
- {% for QM in cave.get_QMs %}
- {% if QM.ticked %}
- {% else %}
+ Open leads
+ {% for QM in cave.get_open_QMs %}
- {{QM}}
- {% if QM.nearest_station_description %}⋮{{QM.nearest_station_description}}⋮{% endif %} {{QM.location_description}} {{QM.grade}}
+ {% if QM.nearest_station_name %}§{{QM.nearest_station_name}}§{% endif %}
+{{QM.location_description}} {{QM.grade}}
{% if QM.block %} {{QM.block}}.svx {{QM.block.date}} {% endif %}
- {% endif %}
+ {% empty %}
+ - No open leads.
{% endfor %}
+
+§ QM.nearest_station_name
+☆ QM.resolution_station_name
Ticked off
-
- {% for QM in cave.get_QMs %}
- {% if QM.ticked %}
+ {% for QM in cave.get_ticked_QMs %}
- {{QM}}
- {% if QM.nearest_station %}⋮{{QM.nearest_station}}⋮{% endif %}
- {% if QM.nearest_station_name %}⋮{{QM.nearest_station_name}}⋮{% endif %}
- {% if QM.nearest_station_description %}⋮{{QM.nearest_station_description}}⋮{% endif %} {{QM.location_description}} {{QM.grade}}
+ {% if QM.nearest_station_name %}§{{QM.nearest_station_name}}§{% endif %}
+ {% if QM.resolution_station_name %}☆{{QM.resolution_station_name}}☆{% endif %}
+ {{QM.location_description}} {{QM.grade}}
{% if QM.block %} {{QM.block}}.svx {{QM.block.date}} {% endif %}
{% if QM.completion_description %}
Completion page: {{QM.completion_description}}
- {% endif %}
- {% endif %}
-
-
-
+ {% endif %}
+ {% if QM.comment %}
+ Comment: {{QM.comment}}
+ {% endif %}
+ {% empty %}
+
- No ticked leads.
{% endfor %}
-{% endif %}
+
+§ QM.nearest_station_name
+☆ QM.resolution_station_name
{% endblock %}
\ No newline at end of file
diff --git a/templates/core/QMs_json_list.html b/templates/core/QMs_json_list.html
index 70ed97b..6a52105 100644
--- a/templates/core/QMs_json_list.html
+++ b/templates/core/QMs_json_list.html
@@ -18,16 +18,4 @@ Hacked up list of caves with grade "?"
{% endfor %} }
------------------------------------------------------
-Hacked up list of caves with grade "V"
-
-
-{% for qm in object_list %}
-{% if qm.grade == "V" %}
-"{{qm.id}}": ["{{qm.expoyear}}","{{qm.cave}}",{% if qm.ticked %}"TICKed",{% else %}"OPEN",{% endif %}
-"{{qm.blockname}}","QM{{qm.number}}","{{qm.grade}}","{{qm.nearest_station_name}}","{{qm.resolution_station_name}}",
-"{{qm.get_absolute_url}}"
-]{% if not forloop.last %},{% endif %}
-{% endif %}
-{% endfor %} }
-{% endblock %}
diff --git a/templates/qm.html b/templates/qm.html
index 69ada72..1afaa15 100644
--- a/templates/qm.html
+++ b/templates/qm.html
@@ -2,6 +2,75 @@
{% load link %}
{% block title %} QM: {{qm|safe}} {% endblock %}
{% block contentheader %}
+
+
+
+{% endblock %}
+
+{% block related %}
+{% endblock %}
+
+{% block content %}
+
+
+Previous QM |
+QM {{qm|safe}} |
+Next QM |
+
+
+
+{% if qm.ticked %}
+This QM is TICKED
+
+
+{% if qm.resolution_station_name %}
+The survey station which record the continuation of the cave past this QM is {{qm.resolution_station_name}}.
+{%endif %}
+Tick off comment: '{{qm.comment}}'
+Tick off completion description: '{{qm.completion_description}}'
+Tick off url: {{qm.get_completion_url}} WRONG
+Tick off date: '{{qm.completion_date}}' [For survex file ticks. not implemented yet]
+{% endif %}
+
+{% if qm.cave %}
+Cave: {{qm.cave|safe }}
+All QMs on this cave {{ qm.cave|safe }}
+ Cave description {{ qm.cave|safe }}
+{% else %}
+This QM is OPEN
+Comment: '{{qm.comment}}'
+{% endif %}
+
+QM page_ref: '{{qm.page_ref}}'
+
+QM Number: {{qm.number}} Grade: {{qm.grade}}
+
+Explanation of Grade letters: Handbook - QM grades
+
+{% if qm.block %}
+
Survexfile
+{{qm.block.date}} {{qm.block}}.svx
+{% endif %}
+
+
+
+
+
+QM original closest survey station
+{% if qm.block %}
+Survex block: {{qm.blockname}}
+
+{% endif %}
+Nearest station: '{{qm.nearest_station_name}}' {{nearest_station_description}}
+QM original description
+{{qm.location_description}}
+
+{% if qm.found_by %}
+Creation
+Found by {{qm.found_by}} on {{qm.found_by.date}}.
+{% endif %}
+
+
QMs available for these caves from CSV import
For full explanation of the current status of the QM system(s), see scriptsqms page.
-
-
-
-Previous QM |
-QM {{qm|safe}} |
-Next QM |
-
-
-{% endblock %}
-
-{% block related %}
-{% endblock %}
-
-{% block content %}
-Cave
-{% if qm.cave %}
-{{ qm.cave|safe }} QMs
-{% else %}
- {% if qm.cave %}
- {{ qm.cave|safe }} QMs
- {% endif %}
-{% endif %}
-{{ qm.cave|safe }} cave description
-
-QM Number
-{{qm.number}}
-
-Grade
-{{qm.grade}}
-Explanation of Grade letters: Handbook - QM grades
-
-{% if qm.block %}
-
Survexfile
-{{qm.block.date}} {{qm.block}}.svx
-{% endif %}
-
-{% if qm.ticked %}
-Ticked
-This QM is TICKED
-{% endif %}
-
-{% if qm.resolution_station_name %}
-resolution_station_name
-{{qm.resolution_station_name}}
-
-{% endif %}
-
-Location
-{% if qm.block %}
-Survex block: {{qm.blockname}}
-
-{% endif %}
-Nearest station: '{{qm.nearest_station_name}}' {{nearest_station_description}}
-QM Description
-{{qm.location_description}}
-
-{% if qm.found_by %}
-Creation
-Found by {{qm.found_by}} on {{qm.found_by.date}}.
-{% endif %}
-
-Completion
-{% if qm.ticked %}
-Ticked off log entry: {{qm.ticked_off_by}}
-Ticked off date: {{qm.get_completion_url}} WRONG
-Tick off date: [For survex file ticks. not implemented yet, needs model change]
-Tick off completion description: {{qm.completion_description}}
-{% else %}
-No completion description yet- STILL EXTANT.
-
-{% endif %}
-
-Comment
-{{qm.comment}}
-
+
{% endblock %}