Now you can hit enter to sign in

This commit is contained in:
Neale Pickett 2019-02-22 19:09:38 -07:00
parent 02ed2162c2
commit 8e67abe0c0
9 changed files with 80 additions and 43 deletions

View File

@ -28,6 +28,16 @@ def get_seed(request):
else:
return int(seedstr)
def get_puzzle(request):
seed = get_seed(request)
category = request.match_info.get("category")
points = int(request.match_info.get("points"))
filename = request.match_info.get("filename")
cat = moth.Category(request.app["puzzles_dir"].joinpath(category), seed)
puzzle = cat.puzzle(points)
return puzzle
async def handle_puzzlelist(request):
seed = get_seed(request)
@ -87,6 +97,16 @@ async def handle_puzzlefile(request):
content_type=content_type,
)
async def handle_answer(request):
seed = get_seed(request)
category = request.match_info.get("category")
points = int(request.match_info.get("points"))
filename = request.match_info.get("filename")
cat = moth.Category(request.app["puzzles_dir"].joinpath(category), seed)
puzzle = cat.puzzle(points)
async def handle_mothballer(request):
seed = get_seed(request)
@ -113,19 +133,37 @@ async def handle_index(request):
seed = random.getrandbits(32)
body = """<!DOCTYPE html>
<html>
<head><title>Dev Server</title></head>
<head>
<title>Dev Server</title>
<script>
// Skip trying to log in
sessionStorage.setItem("id", "Hello from the development server")
</script>
</head>
<body>
<h1>Dev Server</h1>
<p>
You need to provide the contest seed in the URL.
If you don't have a contest seed in mind,
why not try <a href="{seed}/">{seed}</a>?
Pick a seed:
</p>
<ul>
<li><a href="{seed}/">{seed}</a>: a special seed I made just for you!</li>
<li><a href="random/">random</a>: will use a different seed every time you load a page (could be useful for debugging)</li>
<li>You can also hack your own seed into the URL, if you want to.</li>
</ul>
<p>
If you are chaotic,
you could even take your chances with a
<a href="random/">random seed</a> for every HTTP request.
This means generated files will get a different seed than the puzzle itself!
Puzzles can be generated from Python code: these puzzles can use a random number generator if they want.
The seed is used to create these random numbers.
</p>
<p>
We like to make a new seed for every contest,
and re-use that seed whenever we regenerate a category during an event
(say to fix a bug).
By using the same seed,
we make sure that all the dynamically-generated puzzles have the same values
in any new packages we build.
</p>
</body>
</html>
@ -140,12 +178,8 @@ async def handle_static(request):
themes = request.app["theme_dir"]
fn = request.match_info.get("filename")
if not fn:
for fn in ("puzzle-list.html", "index.html"):
path = themes.joinpath(fn)
if path.exists():
break
else:
path = themes.joinpath(fn)
fn = "index.html"
path = themes.joinpath(fn)
return web.FileResponse(path)
@ -182,7 +216,7 @@ if __name__ == '__main__':
app["puzzles_dir"] = pathlib.Path(args.puzzles)
app["theme_dir"] = pathlib.Path(args.theme)
app.router.add_route("GET", "/", handle_index)
app.router.add_route("GET", "/{seed}/puzzles.json", handle_puzzlelist)
app.router.add_route("*", "/{seed}/puzzles.json", handle_puzzlelist)
app.router.add_route("GET", "/{seed}/content/{category}/{points}/puzzle.json", handle_puzzle)
app.router.add_route("GET", "/{seed}/content/{category}/{points}/{filename}", handle_puzzlefile)
app.router.add_route("GET", "/{seed}/mothballer/{category}", handle_mothballer)

View File

@ -175,6 +175,12 @@ func (ctx *Instance) answerHandler(w http.ResponseWriter, req *http.Request) {
}
func (ctx *Instance) puzzlesHandler(w http.ResponseWriter, req *http.Request) {
teamid := req.FormValue("id")
if _, err := ctx.TeamName(teamid); err != nil {
http.Error(w, "Unauthorized: must provide team ID", http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(ctx.jPuzzleList)
@ -273,13 +279,7 @@ func (ctx *Instance) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) {
w: wOrig,
statusCode: new(int),
}
w.Header().Set("WWW-Authenticate", "Basic")
_, password, _ := r.BasicAuth()
if password != ctx.Password {
http.Error(w, "Authentication Required", 401)
} else {
ctx.mux.ServeHTTP(w, r)
}
ctx.mux.ServeHTTP(w, r)
log.Printf(
"%s %s %s %d\n",
r.RemoteAddr,

View File

@ -19,7 +19,6 @@ type Instance struct {
MothballDir string
StateDir string
ResourcesDir string
Password string
Categories map[string]*Mothball
update chan bool
jPuzzleList []byte
@ -27,13 +26,12 @@ type Instance struct {
mux *http.ServeMux
}
func NewInstance(base, mothballDir, stateDir, resourcesDir, password string) (*Instance, error) {
func NewInstance(base, mothballDir, stateDir, resourcesDir string) (*Instance, error) {
ctx := &Instance{
Base: strings.TrimRight(base, "/"),
MothballDir: mothballDir,
StateDir: stateDir,
ResourcesDir: resourcesDir,
Password: password,
Categories: map[string]*Mothball{},
update: make(chan bool, 10),
mux: http.NewServeMux(),

View File

@ -37,11 +37,6 @@ func main() {
"/theme",
"Path to static theme resources (HTML, images, css, ...)",
)
password := flag.String(
"password",
"sesame",
"Pass Word (in the 1920s sense) to view the site. Not a secure passphrase.",
)
maintenanceInterval := flag.Duration(
"maint",
20*time.Second,
@ -58,7 +53,7 @@ func main() {
log.Fatal(err)
}
ctx, err := NewInstance(*base, *mothballDir, *stateDir, *themeDir, *password)
ctx, err := NewInstance(*base, *mothballDir, *stateDir, *themeDir)
if err != nil {
log.Fatal(err)
}

View File

@ -2,6 +2,7 @@
<html>
<head>
<title>MOTH</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="basic.css">
<script src="moth.js"></script>
@ -11,11 +12,11 @@
<section>
<div id="messages"></div>
<div id="login">
<form id="login">
Team name: <input name="name">
Team ID: <input name="id"> <br>
<button id="submit">Sign In</button>
</div>
<input type="submit" value="Sign In">
</form>
<div id="puzzles"></div>
@ -23,6 +24,7 @@
<nav>
<ul>
<li><a href="scoreboard.html">Scoreboard</a></li>
<li><a href="logout.html">Sign Out</a></li>
</ul>
</nav>
</body>

View File

@ -15,7 +15,7 @@ sessionStorage.removeItem("id")
</section>
<nav>
<ul>
<li><a href="index.html">login</a></li>
<li><a href="index.html">Sign In</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>

View File

@ -64,6 +64,7 @@ function renderPuzzles(obj) {
i.appendChild(a)
a.textContent = points
a.href = "puzzle.html?cat=" + cat + "&points=" + points + "&pid=" + id
a.target = "_blank"
}
}
@ -76,13 +77,10 @@ function renderPuzzles(obj) {
container.firstChild.remove()
}
container.appendChild(puzzlesElement)
container.style.display = "none"
document.getElementById("login").style.display = "block"
}
function heartbeat(teamId) {
rpc("puzzles.json", {teamid: teamId})
rpc("puzzles.json", {id: teamId})
.then(resp => {
if (resp.ok) {
resp.json()
@ -103,16 +101,20 @@ function showPuzzles(teamId) {
let spinner = document.createElement("span")
spinner.classList.add("spinner")
sessionStorage.setItem("id", teamId)
document.getElementById("login").style.display = "none"
document.getElementById("puzzles").appendChild(spinner)
heartbeat(teamId)
setInterval(e => { heartbeat(teamId) }, 40000)
}
function login() {
function login(e) {
let name = document.querySelector("[name=name]").value
let id = document.querySelector("[name=id]").value
e.preventDefault()
rpc("register", {
name: name,
id: id,
@ -158,7 +160,13 @@ function toast(message, timeout=5000) {
}
function init() {
document.getElementById("submit").addEventListener("click", login)
// Already signed in?
let id = sessionStorage.getItem("id")
if (id) {
showPuzzles(id)
}
document.getElementById("login").addEventListener("submit", login)
}
if (document.readyState === "loading") {

View File

@ -94,7 +94,7 @@ if (document.readyState === "loading") {
<div id="devel"></div>
<nav>
<ul>
<li><a href="puzzle-list.html">Puzzles</a></li>
<li><a href="index.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>

View File

@ -128,7 +128,7 @@ if (document.readyState === "loading") {
</section>
<nav>
<ul>
<li><a href="puzzle-list.html">Puzzles</a></li>
<li><a href="index.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>