func HuntHandler(w http.ResponseWriter, r *http.Request) { path := strings.Split(r.URL.Path, "/") if len(path) != 3 { http.Error(w, "Not found", 404) return } c := appengine.NewContext(r) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) var h *hunt.Hunt if id := r.FormValue("hunt_id"); id != "" { h = hunt.ID(c, id) } if h == nil { return } t, badSignIn := team.SignIn(c, h, r) var p *puzzle.Puzzle if id := r.FormValue("puzzleid"); id != "" { p = puzzle.ID(c, id) } var err error switch path[2] { case "teaminfo": teams := TeamSelector{ BadSignIn: badSignIn, } if t != nil { teams.CurrentTeam = t.Name } else { for _, t := range team.All(c, h) { teams.Teams = append(teams.Teams, TeamInfo{t.Name, t.ID}) } } err = enc.Encode(teams) case "ingredients": if h.State >= hunt.StateIngredients || (t != nil && t.Novice && h.State == hunt.StateEarlyAccess) { err = enc.Encode(IngredientInfo{true, false, h.Ingredients}) } case "leaderboard": if h.State >= hunt.StateSolving { var l LeaderboardInfo fillLeaderboardInfo(c, h, t, &l) err = enc.Encode(l) } case "leaderboardupdate": if p != nil && h.State >= hunt.StateSolving { err = enc.Encode(p.UpdatableProgressInfo(c, h, t)) } case "puzzles": if t != nil && (h.State >= hunt.StateIngredients || (t.Novice && h.State == hunt.StateEarlyAccess)) && h.State < hunt.StateSolving { puzzles := puzzle.All(c, h, t) var admin []*puzzle.AdminPuzzle for _, p := range puzzles { admin = append(admin, p.Admin(c)) } // TODO(dneal): Check state. err = enc.Encode(PuzzleInfo{true, admin}) } case "updatepuzzle": if p != nil && h.State < hunt.StateSolving { p.Name = r.FormValue("name") p.Answer = r.FormValue("answer") p.Write(c) broadcast.SendPuzzlesUpdate(c, h, t) } case "survey": if t != nil && h.State == hunt.StateSurveying { info := SurveyInfo{Display: true} if t.Survey != "" { info.Done = true } else { puzzles := puzzle.All(c, h, nil) for _, p := range puzzles { if p.Team.Equal(t.Key) { continue } info.Puzzles = append(info.Puzzles, &ProgressInfo{ Number: p.Number, Name: p.Name, ID: p.ID, }) } } err = enc.Encode(info) } case "submitsurvey": if t != nil && t.Survey == "" { t.Survey = r.FormValue("result") t.Write(c) broadcast.SendSurveyUpdate(c, h, t) } case "channel": err = enc.Encode(broadcast.GetToken(c, h, t, false)) case "submitanswer": if t == nil || p == nil || h.State != hunt.StateSolving { break } var throttled, correct bool err = datastore.RunInTransaction(c, func(c appengine.Context) error { t := t.ReRead(c) p := p.ReRead(c) if t.Throttle(c) { throttled = true } else { correct = p.SubmitAnswer(c, h, t, r.FormValue("answer")) } return nil }, nil) var outcome string if err != nil { outcome = "Error, try again!" } else if throttled { outcome = "Too many answer attempts, please wait a minute and try again" adminconsole.Log(c, h, fmt.Sprintf("%s attempts to answer but is throttled", t.Name)) } else if correct { outcome = "Correct!" broadcast.SendLeaderboardUpdate(c, h, p) adminconsole.Log(c, h, fmt.Sprintf("%s correctly answers (%d) %s", t.Name, p.Number, p.Name)) } else { outcome = fmt.Sprintf("\"%s\" is an incorrect guess for %s", r.FormValue("answer"), p.Name) adminconsole.Log(c, h, fmt.Sprintf("%s incorrectly answers [%s] for (%d) %s", t.Name, r.FormValue("answer"), p.Number, p.Name)) } err = enc.Encode(outcome) case "finalscores": finalScores := tally.Get(c, h, false) err = enc.Encode(finalScores) } if err != nil { c.Errorf("Error: %v", err) } }