mirror of https://github.com/dirtbags/moth.git
Merge branch 'v3.5_devel' into abstract_state_storage_mechanisms
This commit is contained in:
commit
5986ab2601
|
@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
team by its team id (e.g., points.json?id=abc123).
|
team by its team id (e.g., points.json?id=abc123).
|
||||||
### Changed
|
### Changed
|
||||||
- Abstract state mechanisms so that it is easier to move to different backends
|
- Abstract state mechanisms so that it is easier to move to different backends
|
||||||
|
### Fixed
|
||||||
|
- Handle cases where non-legacy puzzles don't have an `author` attribute
|
||||||
|
- Handle YAML-formatted file and script lists as expected
|
||||||
|
- YAML-formatted example puzzle actually works as expected
|
||||||
|
|
||||||
|
## [3.4.3] - 2019-11-20
|
||||||
|
### Fixed
|
||||||
|
- Made top-scoring teams full-width
|
||||||
|
|
||||||
## [3.4.2] - 2019-11-18
|
## [3.4.2] - 2019-11-18
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -67,7 +67,7 @@ you can copy the example puzzles as a starting point:
|
||||||
|
|
||||||
Then launch the development server:
|
Then launch the development server:
|
||||||
|
|
||||||
$ python3 tools/devel-server.py
|
$ python3 devel/devel-server.py
|
||||||
|
|
||||||
Point a web browser at http://localhost:8080/
|
Point a web browser at http://localhost:8080/
|
||||||
and start hacking on things in your `puzzles` directory.
|
and start hacking on things in your `puzzles` directory.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import cgitb
|
import cgitb
|
||||||
import html
|
import html
|
||||||
import cgi
|
import cgi
|
||||||
|
@ -43,6 +42,13 @@ class MothRequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
super().__init__(request, client_address, server)
|
super().__init__(request, client_address, server)
|
||||||
|
|
||||||
|
# Why isn't this the default?!
|
||||||
|
def guess_type(self, path):
|
||||||
|
mtype, encoding = mimetypes.guess_type(path)
|
||||||
|
if encoding:
|
||||||
|
return "%s; encoding=%s" % (mtype, encoding)
|
||||||
|
else:
|
||||||
|
return mtype
|
||||||
|
|
||||||
# Backport from Python 3.7
|
# Backport from Python 3.7
|
||||||
def translate_path(self, path):
|
def translate_path(self, path):
|
||||||
|
@ -285,6 +291,8 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
logging.basicConfig(level=log_level)
|
logging.basicConfig(level=log_level)
|
||||||
|
|
||||||
|
mimetypes.add_type("application/javascript", ".mjs")
|
||||||
|
|
||||||
server = MothServer((addr, port), MothRequestHandler)
|
server = MothServer((addr, port), MothRequestHandler)
|
||||||
server.args["base_url"] = args.base
|
server.args["base_url"] = args.base
|
||||||
server.args["puzzles_dir"] = pathlib.Path(args.puzzles)
|
server.args["puzzles_dir"] = pathlib.Path(args.puzzles)
|
||||||
|
|
|
@ -233,11 +233,39 @@ class Puzzle:
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
self.files[name] = PuzzleFile(stream, name, not hidden)
|
self.files[name] = PuzzleFile(stream, name, not hidden)
|
||||||
|
|
||||||
|
elif key == 'files' and isinstance(val, dict):
|
||||||
|
for filename, options in val.items():
|
||||||
|
if "source" in options:
|
||||||
|
source = options["source"]
|
||||||
|
else:
|
||||||
|
source = filename
|
||||||
|
|
||||||
|
if "hidden" in options and options["hidden"]:
|
||||||
|
hidden = True
|
||||||
|
else:
|
||||||
|
hidden = False
|
||||||
|
|
||||||
|
stream = open(source, "rb")
|
||||||
|
self.files[filename] = PuzzleFile(stream, filename, not hidden)
|
||||||
|
|
||||||
|
elif key == 'files' and isinstance(val, list):
|
||||||
|
for filename in val:
|
||||||
|
stream = open(filename, "rb")
|
||||||
|
self.files[filename] = PuzzleFile(stream, filename)
|
||||||
|
|
||||||
elif key == 'script':
|
elif key == 'script':
|
||||||
stream = open(val, 'rb')
|
stream = open(val, 'rb')
|
||||||
# Make sure this shows up in the header block of the HTML output.
|
# Make sure this shows up in the header block of the HTML output.
|
||||||
self.files[val] = PuzzleFile(stream, val, visible=False)
|
self.files[val] = PuzzleFile(stream, val, visible=False)
|
||||||
self.scripts.append(val)
|
self.scripts.append(val)
|
||||||
|
|
||||||
|
elif key == "scripts" and isinstance(val, list):
|
||||||
|
for script in val:
|
||||||
|
stream = open(script, "rb")
|
||||||
|
self.files[script] = PuzzleFile(stream, script, visible=False)
|
||||||
|
self.scripts.append(script)
|
||||||
|
|
||||||
elif key == "objective":
|
elif key == "objective":
|
||||||
self.objective = val
|
self.objective = val
|
||||||
elif key == "success":
|
elif key == "success":
|
||||||
|
@ -384,7 +412,12 @@ class Puzzle:
|
||||||
self.body.write('</pre>')
|
self.body.write('</pre>')
|
||||||
|
|
||||||
def get_authors(self):
|
def get_authors(self):
|
||||||
return self.authors or [self.author]
|
if len(self.authors) > 0:
|
||||||
|
return self.authors
|
||||||
|
elif hasattr(self, "author"):
|
||||||
|
return [self.author]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
def get_body(self):
|
def get_body(self):
|
||||||
return self.body.getvalue()
|
return self.body.getvalue()
|
||||||
|
|
|
@ -28,6 +28,7 @@ If you can't use docker,
|
||||||
try this:
|
try this:
|
||||||
|
|
||||||
apt install python3
|
apt install python3
|
||||||
|
pip3 install scapy pillow PyYAML
|
||||||
git clone https://github.com/dirtbags/moth/
|
git clone https://github.com/dirtbags/moth/
|
||||||
cd moth
|
cd moth
|
||||||
python3 devel/devel-server.py --puzzles example-puzzles
|
python3 devel/devel-server.py --puzzles example-puzzles
|
||||||
|
|
|
@ -111,11 +111,15 @@ function scoreboardInit() {
|
||||||
}
|
}
|
||||||
winners.sort(teamCompare)
|
winners.sort(teamCompare)
|
||||||
winners.reverse()
|
winners.reverse()
|
||||||
|
|
||||||
|
// Let's make some better names for things we've computed
|
||||||
|
let winningScore = winners[0].overallScore
|
||||||
|
let numCategories = Object.keys(highestCategoryScore).length
|
||||||
|
|
||||||
// Clear out the element we're about to populate
|
// Clear out the element we're about to populate
|
||||||
Array.from(element.childNodes).map(e => e.remove())
|
Array.from(element.childNodes).map(e => e.remove())
|
||||||
|
|
||||||
let maxWidth = 100 / Object.keys(highestCategoryScore).length
|
let maxWidth = 100 / winningScore
|
||||||
for (let team of winners) {
|
for (let team of winners) {
|
||||||
let row = document.createElement("div")
|
let row = document.createElement("div")
|
||||||
let ncat = 0
|
let ncat = 0
|
||||||
|
@ -125,8 +129,6 @@ function scoreboardInit() {
|
||||||
let catPct = catTeam / catHigh
|
let catPct = catTeam / catHigh
|
||||||
let width = maxWidth * catPct
|
let width = maxWidth * catPct
|
||||||
|
|
||||||
console.log(catHigh, catTeam, catPct)
|
|
||||||
|
|
||||||
let bar = document.createElement("span")
|
let bar = document.createElement("span")
|
||||||
bar.classList.add("category")
|
bar.classList.add("category")
|
||||||
bar.classList.add("cat" + ncat)
|
bar.classList.add("cat" + ncat)
|
||||||
|
|
Loading…
Reference in New Issue