func advanceState(c appengine.Context, h *hunt.Hunt, currentState int) { err := datastore.RunInTransaction(c, func(c appengine.Context) error { h := hunt.ID(c, h.ID) if h == nil || h.State != currentState { // TODO(dneal): Return a real error. return nil } switch h.State { case hunt.StatePreLaunch: teams := team.All(c, h) nonPaperOrder := rand.Perm(len(teams)) paperOrder := rand.Perm(len(teams)) for i := range teams { puzzle.New(c, h, teams[i], nonPaperOrder[i]+1, false) puzzle.New(c, h, teams[i], len(teams)+paperOrder[i]+1, true) } case hunt.StateSurveying: tally.BuildFinalTally(c, h) } h.State++ h.Write(c) broadcast.SendRefresh(c, h) return nil }, nil) if err != nil { c.Errorf("Error: %v", err) } }
func (p *Puzzle) UpdatableProgressInfo(c appengine.Context, h *hunt.Hunt, t *team.Team) UpdatableProgressInfo { u := UpdatableProgressInfo{ AvailablePoints: p.PointValue, Solved: false, GrantedPoints: 0, SolveTimes: nil, Answerable: t != nil && !t.Key.Equal(p.Team), } if t != nil { var solves []Solve _, err := datastore.NewQuery(solveKind).Ancestor(h.Key).Filter("Puzzle =", p.Key).Filter("Team =", t.Key).Limit(1).GetAll(c, &solves) if err != nil { c.Errorf("Error: %v", err) } if len(solves) > 0 { u.Solved = true u.GrantedPoints = solves[0].Points u.Answerable = false } } var solves []Solve _, err := datastore.NewQuery(solveKind).Ancestor(h.Key).Filter("Puzzle =", p.Key).Order("Time").GetAll(c, &solves) if err != nil { c.Errorf("Error: %v", err) } for _, s := range solves { u.SolveTimes = append(u.SolveTimes, s.Time.In(h.GetTimezone(c)).Format("15:04:05")) } return u }
func Log(c appengine.Context, h *hunt.Hunt, message string) { m := &Message{message, time.Now()} k := datastore.NewIncompleteKey(c, messageKind, h.Key) k, err := datastore.Put(c, k, m) if err != nil { c.Errorf("Error: %v", err) } broadcast.SendConsoleUpdate(c, h, m.ToString(c, h.GetTimezone(c))) }
func Logs(c appengine.Context, h *hunt.Hunt) []string { var messages []*Message _, err := datastore.NewQuery(messageKind).Ancestor(h.Key).Order("-Time").Limit(1000).GetAll(c, &messages) if err != nil { c.Errorf("Error: %v", err) return nil } var result []string for _, m := range messages { result = append(result, m.ToString(c, h.GetTimezone(c))) } return result }
func AdminHandler(w http.ResponseWriter, r *http.Request) { path := strings.Split(r.URL.Path, "/") if len(path) != 4 { 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) } var t *team.Team if id := r.FormValue("team_id"); h != nil && id != "" { t = team.ID(c, id) } var p *puzzle.Puzzle if id := r.FormValue("puzzleid"); h != nil && id != "" { p = puzzle.ID(c, id) } var err error switch path[3] { case "hunts": hunts := hunt.All(c) err = enc.Encode(hunts) case "addhunt": hunt.New(c, r.FormValue("name"), r.FormValue("path")) case "deletehunt": h.Delete(c) case "updateingredients": if h != nil && h.State < hunt.StateEarlyAccess { h.Ingredients = r.FormValue("ingredients") h.Write(c) broadcast.SendIngredientsUpdate(c, h) } case "teams": if h != nil { err = enc.Encode(TeamsInfo{ Editable: true, Teams: team.All(c, h), }) } case "addteam": if h != nil && h.State < hunt.StateEarlyAccess { team.New(c, h, r.FormValue("name"), r.FormValue("password"), r.FormValue("novice") == "true") broadcast.SendTeamsUpdate(c, h) } case "deleteteam": if t != nil && h.State < hunt.StateEarlyAccess { t.Delete(c) broadcast.SendTeamsUpdate(c, h) } case "state": if h != nil { err = enc.Encode(h.State) } case "advancestate": if h != nil { currentState, err := strconv.Atoi(r.FormValue("currentstate")) if err == nil { advanceState(c, h, currentState) broadcast.SendRefresh(c, h) } } case "puzzles": if h != nil { puzzles := puzzle.All(c, h, nil) var admin []*puzzle.AdminPuzzle for _, p := range puzzles { admin = append(admin, p.Admin(c)) } err = enc.Encode(PuzzleInfo{false, admin}) } case "ingredients": err = enc.Encode(IngredientInfo{ Display: true, Editable: true, Ingredients: h.Ingredients, }) case "leaderboard": if h.State >= hunt.StateSolving { var l LeaderboardInfo fillLeaderboardInfo(c, h, nil, &l) err = enc.Encode(l) } case "leaderboardupdate": if p != nil { err = enc.Encode(p.UpdatableProgressInfo(c, h, nil)) } case "channel": if h != nil { err = enc.Encode(broadcast.GetToken(c, h, nil, true)) } case "console": if h != nil { err = enc.Encode(adminconsole.Logs(c, h)) } case "adminsurvey": if h != nil && h.State == hunt.StateSurveying { var info AdminSurveyInfo info.Display = true for _, t := range team.All(c, h) { info.Teams = append(info.Teams, TeamSurveyInfo{t.Name, t.Survey != ""}) } err = enc.Encode(info) } case "finalscores": finalScores := tally.Get(c, h, true) err = enc.Encode(finalScores) } if err != nil { c.Errorf("Error: %v", err) return } }