mirror of https://github.com/dirtbags/moth.git
Fix bug that required id to get puzzle content
This commit is contained in:
parent
b39e287e41
commit
8874aad7cb
|
@ -110,7 +110,9 @@ func (h *HTTPServer) StateHandler(mh MothRequestHandler, w http.ResponseWriter,
|
||||||
// RegisterHandler handles attempts to register a team
|
// RegisterHandler handles attempts to register a team
|
||||||
func (h *HTTPServer) RegisterHandler(mh MothRequestHandler, w http.ResponseWriter, req *http.Request) {
|
func (h *HTTPServer) RegisterHandler(mh MothRequestHandler, w http.ResponseWriter, req *http.Request) {
|
||||||
teamName := req.FormValue("name")
|
teamName := req.FormValue("name")
|
||||||
if err := mh.Register(teamName); err != nil {
|
if err := mh.Register(teamName); err == ErrAlreadyRegistered {
|
||||||
|
jsend.Sendf(w, jsend.Success, "already registered", "Team ID has already been registered")
|
||||||
|
} else if err != nil {
|
||||||
jsend.Sendf(w, jsend.Fail, "not registered", err.Error())
|
jsend.Sendf(w, jsend.Fail, "not registered", err.Error())
|
||||||
} else {
|
} else {
|
||||||
jsend.Sendf(w, jsend.Success, "registered", "Team ID registered")
|
jsend.Sendf(w, jsend.Success, "registered", "Team ID registered")
|
||||||
|
|
|
@ -66,6 +66,12 @@ func TestHttpd(t *testing.T) {
|
||||||
t.Error("Register failed")
|
t.Error("Register failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thatt if r := hs.TestRequest("/register", map[string]string{"name": "GoTeam"}); r.Result().StatusCode != 200 {
|
||||||
|
t.Error(r.Result())
|
||||||
|
} else if r.Body.String() != `{"status":"success","data":{"short":"already registered","description":"Team ID has already been registered"}}` {
|
||||||
|
t.Error("Register failed", r.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
||||||
t.Error(r.Result())
|
t.Error(r.Result())
|
||||||
} else if r.Body.String() != `{"Config":{"Devel":false},"Messages":"messages.html","TeamNames":{"self":"GoTeam"},"PointsLog":[],"Puzzles":{"pategory":[1]}}` {
|
} else if r.Body.String() != `{"Config":{"Devel":false},"Messages":"messages.html","TeamNames":{"self":"GoTeam"},"PointsLog":[],"Puzzles":{"pategory":[1]}}` {
|
||||||
|
@ -108,6 +114,10 @@ func TestHttpd(t *testing.T) {
|
||||||
|
|
||||||
time.Sleep(TestMaintenanceInterval)
|
time.Sleep(TestMaintenanceInterval)
|
||||||
|
|
||||||
|
if r := hs.TestRequest("/content/pategory/2/puzzle.json", nil); r.Result().StatusCode != 200 {
|
||||||
|
t.Error(r.Result())
|
||||||
|
}
|
||||||
|
|
||||||
state := StateExport{}
|
state := StateExport{}
|
||||||
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
||||||
t.Error(r.Result())
|
t.Error(r.Result())
|
||||||
|
|
|
@ -107,7 +107,7 @@ type MothRequestHandler struct {
|
||||||
// PuzzlesOpen opens a file associated with a puzzle.
|
// PuzzlesOpen opens a file associated with a puzzle.
|
||||||
// BUG(neale): Multiple providers with the same category name are not detected or handled well.
|
// BUG(neale): Multiple providers with the same category name are not detected or handled well.
|
||||||
func (mh *MothRequestHandler) PuzzlesOpen(cat string, points int, path string) (r ReadSeekCloser, ts time.Time, err error) {
|
func (mh *MothRequestHandler) PuzzlesOpen(cat string, points int, path string) (r ReadSeekCloser, ts time.Time, err error) {
|
||||||
export := mh.ExportState()
|
export := mh.exportStateIfRegistered(true)
|
||||||
found := false
|
found := false
|
||||||
for _, p := range export.Puzzles[cat] {
|
for _, p := range export.Puzzles[cat] {
|
||||||
if p == points {
|
if p == points {
|
||||||
|
@ -115,7 +115,7 @@ func (mh *MothRequestHandler) PuzzlesOpen(cat string, points int, path string) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return nil, time.Time{}, fmt.Errorf("Category not found")
|
return nil, time.Time{}, fmt.Errorf("Puzzle does not exist or is locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try every provider until someone doesn't return an error
|
// Try every provider until someone doesn't return an error
|
||||||
|
@ -172,11 +172,15 @@ func (mh *MothRequestHandler) Register(teamName string) error {
|
||||||
// the anonymized team name for this teamID has the special value "self".
|
// the anonymized team name for this teamID has the special value "self".
|
||||||
// If not, the puzzles list is empty.
|
// If not, the puzzles list is empty.
|
||||||
func (mh *MothRequestHandler) ExportState() *StateExport {
|
func (mh *MothRequestHandler) ExportState() *StateExport {
|
||||||
|
return mh.exportStateIfRegistered(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MothRequestHandler) exportStateIfRegistered(override bool) *StateExport {
|
||||||
export := StateExport{}
|
export := StateExport{}
|
||||||
export.Config = mh.Config
|
export.Config = mh.Config
|
||||||
|
|
||||||
teamName, err := mh.State.TeamName(mh.teamID)
|
teamName, err := mh.State.TeamName(mh.teamID)
|
||||||
registered := (err == nil)
|
registered := override || (err == nil)
|
||||||
|
|
||||||
export.Messages = mh.State.Messages()
|
export.Messages = mh.State.Messages()
|
||||||
export.TeamNames = map[string]string{"self": teamName}
|
export.TeamNames = map[string]string{"self": teamName}
|
||||||
|
@ -209,7 +213,6 @@ func (mh *MothRequestHandler) ExportState() *StateExport {
|
||||||
// We used to hand this out to everyone,
|
// We used to hand this out to everyone,
|
||||||
// but then we got a bad reputation on some secretive blacklist,
|
// but then we got a bad reputation on some secretive blacklist,
|
||||||
// and now the Navy can't register for events.
|
// and now the Navy can't register for events.
|
||||||
|
|
||||||
for _, provider := range mh.PuzzleProviders {
|
for _, provider := range mh.PuzzleProviders {
|
||||||
for _, category := range provider.Inventory() {
|
for _, category := range provider.Inventory() {
|
||||||
// Append sentry (end of puzzles)
|
// Append sentry (end of puzzles)
|
||||||
|
|
|
@ -34,6 +34,7 @@ func TestServer(t *testing.T) {
|
||||||
|
|
||||||
server := NewTestServer()
|
server := NewTestServer()
|
||||||
handler := server.NewHandler(participantID, teamID)
|
handler := server.NewHandler(participantID, teamID)
|
||||||
|
anonHandler := server.NewHandler("badParticipantId", "badTeamId")
|
||||||
|
|
||||||
{
|
{
|
||||||
es := handler.ExportState()
|
es := handler.ExportState()
|
||||||
|
@ -49,6 +50,12 @@ func TestServer(t *testing.T) {
|
||||||
if err := handler.Register(teamName); err != nil {
|
if err := handler.Register(teamName); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
if err := handler.Register(teamName); err == nil {
|
||||||
|
t.Error("Registering twice should have raised an error")
|
||||||
|
} else if err != ErrAlreadyRegistered {
|
||||||
|
t.Error("Wrong error for duplicate registration:", err)
|
||||||
|
}
|
||||||
|
|
||||||
if r, _, err := handler.ThemeOpen("/index.html"); err != nil {
|
if r, _, err := handler.ThemeOpen("/index.html"); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
} else if contents, err := ioutil.ReadAll(r); err != nil {
|
} else if contents, err := ioutil.ReadAll(r); err != nil {
|
||||||
|
@ -89,12 +96,12 @@ func TestServer(t *testing.T) {
|
||||||
r.Close()
|
r.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if r, _, err := handler.PuzzlesOpen("pategory", 2, "puzzles.json"); err == nil {
|
if r, _, err := handler.PuzzlesOpen("pategory", 2, "puzzle.json"); err == nil {
|
||||||
t.Error("Opening locked puzzle shouldn't work")
|
t.Error("Opening locked puzzle shouldn't work")
|
||||||
r.Close()
|
r.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if r, _, err := handler.PuzzlesOpen("pategory", 20, "puzzles.json"); err == nil {
|
if r, _, err := handler.PuzzlesOpen("pategory", 20, "puzzle.json"); err == nil {
|
||||||
t.Error("Opening non-existent puzzle shouldn't work")
|
t.Error("Opening non-existent puzzle shouldn't work")
|
||||||
r.Close()
|
r.Close()
|
||||||
}
|
}
|
||||||
|
@ -109,6 +116,22 @@ func TestServer(t *testing.T) {
|
||||||
if len(es.PointsLog) != 1 {
|
if len(es.PointsLog) != 1 {
|
||||||
t.Error("I didn't get my points!")
|
t.Error("I didn't get my points!")
|
||||||
}
|
}
|
||||||
|
if len(es.Puzzles["pategory"]) != 2 {
|
||||||
|
t.Error("The next puzzle didn't unlock!")
|
||||||
|
} else if es.Puzzles["pategory"][1] != 2 {
|
||||||
|
t.Error("The 2-point puzzle should have unlocked!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, _, err := handler.PuzzlesOpen("pategory", 2, "puzzle.json"); err != nil {
|
||||||
|
t.Error("Opening unlocked puzzle should work")
|
||||||
|
} else {
|
||||||
|
r.Close()
|
||||||
|
}
|
||||||
|
if r, _, err := anonHandler.PuzzlesOpen("pategory", 2, "puzzle.json"); err != nil {
|
||||||
|
t.Error("Opening unlocked puzzle anonymously should work")
|
||||||
|
} else {
|
||||||
|
r.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// BUG(neale): We aren't currently testing the various ways to disable the server
|
// BUG(neale): We aren't currently testing the various ways to disable the server
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -23,6 +24,9 @@ const DistinguishableChars = "34678abcdefhikmnpqrtwxy="
|
||||||
// This is also a valid RFC3339 format.
|
// This is also a valid RFC3339 format.
|
||||||
const RFC3339Space = "2006-01-02 15:04:05Z07:00"
|
const RFC3339Space = "2006-01-02 15:04:05Z07:00"
|
||||||
|
|
||||||
|
// ErrAlreadyRegistered means a team cannot be registered because it was registered previously.
|
||||||
|
var ErrAlreadyRegistered = errors.New("Team ID has already been registered")
|
||||||
|
|
||||||
// State defines the current state of a MOTH instance.
|
// State defines the current state of a MOTH instance.
|
||||||
// We use the filesystem for synchronization between threads.
|
// We use the filesystem for synchronization between threads.
|
||||||
// The only thing State methods need to know is the path to the state directory.
|
// The only thing State methods need to know is the path to the state directory.
|
||||||
|
@ -127,7 +131,7 @@ func (s *State) TeamName(teamID string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTeamName writes out team name.
|
// SetTeamName writes out team name.
|
||||||
// This can only be done once.
|
// This can only be done once per team.
|
||||||
func (s *State) SetTeamName(teamID, teamName string) error {
|
func (s *State) SetTeamName(teamID, teamName string) error {
|
||||||
idsFile, err := s.Open("teamids.txt")
|
idsFile, err := s.Open("teamids.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -149,7 +153,7 @@ func (s *State) SetTeamName(teamID, teamName string) error {
|
||||||
teamFilename := filepath.Join("teams", teamID)
|
teamFilename := filepath.Join("teams", teamID)
|
||||||
teamFile, err := s.Fs.OpenFile(teamFilename, os.O_CREATE|os.O_EXCL, 0644)
|
teamFile, err := s.Fs.OpenFile(teamFilename, os.O_CREATE|os.O_EXCL, 0644)
|
||||||
if os.IsExist(err) {
|
if os.IsExist(err) {
|
||||||
return fmt.Errorf("Team ID is already registered")
|
return ErrAlreadyRegistered
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ function renderPuzzles(obj) {
|
||||||
pdiv.appendChild(l)
|
pdiv.appendChild(l)
|
||||||
for (let puzzle of puzzles) {
|
for (let puzzle of puzzles) {
|
||||||
let points = puzzle
|
let points = puzzle
|
||||||
let id = puzzle
|
let id = null
|
||||||
|
|
||||||
if (Array.isArray(puzzle)) {
|
if (Array.isArray(puzzle)) {
|
||||||
points = puzzle[0]
|
points = puzzle[0]
|
||||||
|
@ -80,7 +80,7 @@ function renderPuzzles(obj) {
|
||||||
let url = new URL("puzzle.html", window.location)
|
let url = new URL("puzzle.html", window.location)
|
||||||
url.searchParams.set("cat", cat)
|
url.searchParams.set("cat", cat)
|
||||||
url.searchParams.set("points", points)
|
url.searchParams.set("points", points)
|
||||||
url.searchParams.set("pid", id)
|
if (id) { url.searchParams.set("pid", id) }
|
||||||
a.href = url.toString()
|
a.href = url.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,8 +204,8 @@ function init() {
|
||||||
let points = params.get("points")
|
let points = params.get("points")
|
||||||
let puzzleId = params.get("pid")
|
let puzzleId = params.get("pid")
|
||||||
|
|
||||||
if (categoryName && points && puzzleId) {
|
if (categoryName && points) {
|
||||||
loadPuzzle(categoryName, points, puzzleId)
|
loadPuzzle(categoryName, points, puzzleId || points)
|
||||||
}
|
}
|
||||||
|
|
||||||
let teamId = sessionStorage.getItem("id")
|
let teamId = sessionStorage.getItem("id")
|
||||||
|
|
Loading…
Reference in New Issue