def get(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return puzzle = MaybeGetPuzzle(game, self.request) if not puzzle: return self.error(404) feedback = model.Feedback.get_or_insert(str(team.key()), parent=puzzle) props = { "error": self.request.get_all("error"), "game": model.GetProperties(game), "team": model.GetProperties(team), "puzzle": model.GetProperties(puzzle), "feedback": model.GetProperties(feedback), "guesses": [], "solve_teams": set(), } for guess in model.Guess.all().ancestor(puzzle).order("-timestamp"): if guess.answer in puzzle.answers: props["solve_teams"].add(guess.team.key()) if guess.team.key() == team.key(): props["guesses"].append(model.GetProperties(guess)) if guess.answer in puzzle.answers: props["guesses"][-1]["is_correct"] = True props.setdefault("solve_time", guess.timestamp) self.response.out.write(template.render("guess.dj.html", props))
def post(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return puzzle = MaybeGetPuzzle(game, self.request) if not puzzle: return self.error(404) self.redirect("/guess?t=%d&p=%s" % (team.key().id(), self.request.get("p"))) if self.request.get("comment", None) is not None: feedback = model.Feedback(parent=puzzle, key_name=str(team.key())) feedback.comment = self.request.get("comment") if game.solving_enabled or game.voting_enabled: for s in range(len(feedback.scores)): feedback.scores[s] = NormalizeScore( self.request.get("score.%d" % s)) feedback.put() self.redirect("/team?t=%d" % team.key().id()) answer = NormalizeAnswer(self.request.get("answer", "")) if answer and game.solving_enabled: start_time = datetime.datetime.now() - datetime.timedelta( 0, SPAM_SECONDS) guesses = model.Guess.all().ancestor(puzzle).filter( "team", team.key()) recent = guesses.filter("timestamp >=", start_time).fetch(SPAM_GUESSES) if answer in [g.answer for g in recent]: self.response.headers["location"] += "&error=dup" elif len(recent) >= SPAM_GUESSES: self.response.headers["location"] += "&error=spam" else: model.Guess(parent=puzzle, answer=answer, team=team).put()
def get(self): game = model.GetGame() puzzle = MaybeGetPuzzle(game, self.request) if not puzzle: return self.error(404) # Access control: # (Solving enabled AND type is "p") OR # Voting enabled OR Results enabled OR # Team is puzzle author OR Team solved puzzle file = self.request.get("f") if not (game.voting_enabled or game.results_enabled or (game.solving_enabled and file == "p")): team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return if puzzle.parent_key() != team.key(): guesses = model.Guess.all().ancestor(puzzle).filter( "team", team.key()) if not [g for g in guesses if g in puzzle.answers]: return self.error(403) blobinfo = { "p": puzzle.puzzle_blob, "s": puzzle.solution_blob }.get(file) if not blobinfo: return self.error(404) self.send_blob( blobinfo, save_as="%s%s-%s" % (file, self.request.get("p"), blobinfo.filename or "file"))
def post(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return if game.voting_enabled: sr = range(len(model.Feedback().scores)) puzzles = model.Puzzle.all().ancestor(game) feedback_keys = [ db.Key.from_path("Feedback", str(team.key()), parent=p.key()) for p in puzzles ] feedback = {} for p, f in zip(puzzles, model.Feedback.get(feedback_keys)): if p.key().parent() == team.key(): continue # No self voting n = p.number score = [self.request.get("score.%s.%d" % (n, s)) for s in sr] score_orig = [ self.request.get("score.%s.%d.orig" % (n, s)) for s in sr ] if (score != score_orig) or not f: if not f: f = model.Feedback(parent=p, key_name=str(team.key())) for s in sr: f.scores[s] = puzzle.NormalizeScore(score[s]) if not self.request.get("normalize"): f.put() feedback.setdefault(p.key().name(), []).append(f) if self.request.get("normalize"): for flist in feedback.values(): for i in range(len(flist[0].scores)): vector = [f.scores[i] for f in flist] NormalizeVector(vector, 0, 5, 3) for f, s in zip(flist, vector): f.scores[i] = round(s * 10) / 10.0 for f in flist: f.put() self.redirect("/team?t=%d" % team.key().id()) team.name = self.request.get("name") or team.name team.email = self.request.get("email") set_pw = self.request.get("set_password") confirm_pw = self.request.get("confirm_password") if set_pw or confirm_pw: if set_pw != confirm_pw: self.response.headers["location"] += "&error=set_password" else: team.password = set_pw team.put()
def post(self): game = model.GetGame() team = GetTeamOrRedirect(game, self.request, self.response) if not team: return target = self.request.get("u") or ("/team?t=%d" % team.key().id()) password = self.request.get("pw") if password == team.password: self.redirect(target) self.response.headers.add_header( "Set-Cookie", "password=%s; Max-Age=%d; Path=/" % (urllib.quote(password), 7 * 24 * 60 * 60)) else: self.redirect("/login?t=%d&u=%s&error=password" % (team.key().id(), urllib.quote(target)))
def get(self): game = model.GetGame() team = GetTeamOrRedirect(game, self.request, self.response) if not team: return props = { "error": self.request.get_all("error"), "game": model.GetProperties(game), "team": model.GetProperties(team), "target": self.request.get("u"), } self.response.headers.add_header("Set-Cookie", "password=; Max-Age=0; Path=/") self.response.out.write(template.render("login.dj.html", props))
def post(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return puzzle = MaybeGetPuzzle(game, self.request) if not puzzle: return self.error(404) if puzzle.parent_key() != team.key(): return self.error(403) self.redirect("/team?t=%d" % team.key().id()) updates = {} for arg in self.request.arguments(): if arg.endswith(".orig"): continue orig_value = urllib.unquote(self.request.get(arg + ".orig", "")) new_value = self.request.get(arg).replace("\r\n", "\n") if new_value != orig_value: updates[arg] = new_value.strip() for blobinfo in self.get_uploads(field_name="puzzle_file"): if puzzle.puzzle_blob: blobstore.delete(puzzle.puzzle_blob.key()) puzzle.puzzle_blob = blobinfo for blobinfo in self.get_uploads(field_name="solution_file"): if puzzle.solution_blob: blobstore.delete(puzzle.solution_blob.key()) puzzle.solution_blob = blobinfo if "title" in updates: puzzle.title = updates.get("title") if "answers" in updates: puzzle.answers = [] for answer in updates.get("answers").split("\n"): answer = NormalizeAnswer(answer) if answer: puzzle.answers.append(answer) if "errata" in updates: puzzle.errata_timestamp = datetime.datetime.now() puzzle.errata = updates.get("errata") if "solution" in updates: puzzle.solution = updates.get("solution") puzzle.put()
def get(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return puzzle = MaybeGetPuzzle(team, self.request) if not puzzle: return self.error(404) if puzzle.parent_key() != team.key(): return self.error(403) props = { "form_url": blobstore.create_upload_url("/puzzle"), "game": model.GetProperties(game), "team": model.GetProperties(team), "puzzle": model.GetProperties(puzzle), "comments": [], "votes": [], "solves": [], } no_scores = model.Feedback().scores for feedback in model.Feedback.all().ancestor(puzzle): comment = (feedback.comment or "").strip() if comment: props["comments"].append(comment) props["votes"].append(feedback.scores) props["puzzle"]["answers"] = "\n".join(props["puzzle"].get( "answers", [])) props["comments"].sort(key=unicode.lower) props["votes"].sort(reverse=True) solvers = {} for guess in model.Guess.all().ancestor(puzzle).order("timestamp"): if guess.answer in puzzle.answers and not solvers.get( guess.team.key()): solvers[guess.team.key()] = 1 props["solves"].append(guess) self.response.out.write(template.render("puzzle.dj.html", props))
def get(self): game = model.GetGame() props = { "admin_email": admin.GetAdminEmail(game), "admin_logout_url": users.create_logout_url(dest_url="/"), "game": model.GetProperties(game), "puzzles": [], "teams": [], } team_by_key = {} for team in model.Team.all().ancestor(game): team_props = team_by_key[team.key()] = model.GetProperties(team) team_props.update({ "generosity": {}, "score": team_props.get("bonus") or 0.0, "solve_count": 0, "solve_score": 0, "solve_time": 0, "works": [], "wrote": {}, "wrote_score": 0, }) cookie = login.CookiePassword(team, self.request) if cookie: props["cookie_team"] = team_props props["cookie_password"] = cookie props["teams"].append(team_props) puzzle_by_key = {} for p in sorted(model.Puzzle.all().ancestor(game), key=puzzle.SortKey): puzzle_props = puzzle_by_key[p.key()] = model.GetProperties(p) author_props = team_by_key.get(p.key().parent(), {}) puzzle_props.update({ "author": author_props.get("name"), "author_id": author_props.get("key_id"), "score": 0, "solve_count": 0, "votes": [], }) author_props["wrote"][p.key().name()] = puzzle_props props["puzzles"].append(puzzle_props) for feedback in model.Feedback.all().ancestor(game): puzzle_props = puzzle_by_key[feedback.key().parent()] puzzle_props["votes"].append(feedback.scores) puzzle_type = puzzle_props["key_name"] team_props = team_by_key[db.Key(feedback.key().name())] generosity = team_props["generosity"].setdefault( puzzle_props["key_name"], [0] * len(feedback.scores)) generosity[:] = [ a + b for a, b in zip(generosity, feedback.scores) ] work_by_keys = {} for team_props in props["teams"]: for puzzle_props in props["puzzles"]: work_props = work_by_keys[(team_props["key"], puzzle_props["key"])] = { "puzzle": puzzle_props, "guess_count": 0, } team_props["works"].append(work_props) for guess in model.Guess.all().ancestor(game).order("timestamp"): work_props = work_by_keys[(guess.team.key(), guess.key().parent())] if guess.answer in work_props["puzzle"]["answers"]: if not work_props.get("solve_time"): team_props = team_by_key[guess.team.key()] work_props["solve_time"] = team_props[ "solve_time"] = guess.timestamp work_props["puzzle"]["solve_count"] += 1 team_props["solve_count"] += 1 # # Compute scores # no_scores = model.Feedback().scores for team_props in props["teams"]: for puzzle_props in team_props["wrote"].values(): wrote_scores = puzzle_props["scores"] = [0 for s in no_scores] for scores in puzzle_props["votes"]: for i in range(len(wrote_scores)): if i < len(scores): wrote_scores[i] += scores[i] unvoted = len(team_by_key) - len(puzzle_props["votes"]) - 1 if unvoted > 0: for i in range(len(wrote_scores)): wrote_scores[i] += no_scores[i] * unvoted points = 2 * wrote_scores[0] + sum(wrote_scores[1:]) puzzle_props["score"] = points team_props["score"] += points team_props["wrote_score"] += points for work_props in team_props["works"]: if work_props.get("solve_time"): points = 9 + len( props["teams"]) - work_props["puzzle"]["solve_count"] work_props["score"] = points team_props["solve_score"] += points team_props["score"] += points props["teams"].sort( key=lambda tp: (-tp["solve_count"], tp["solve_time"], tp["name"])) self.response.out.write(template.render("main.dj.html", props))
def get(self): game = model.GetGame() team = login.GetTeamOrRedirect(game, self.request, self.response) if not team: return props = { "error": self.request.get_all("error"), "game": model.GetProperties(game), "team": model.GetProperties(team), "team_puzzles": [], "other_puzzles": [], "errata_puzzles": [], } puzzle_props = {} for p in sorted(model.Puzzle.all().ancestor(game), key=puzzle.SortKey): pp = puzzle_props[p.key()] = model.GetProperties(p) pp.update({ "guess_count": 0, "solve_teams": set(), "comment_count": 0, "vote_count": 0, }) if pp.get("errata"): props["errata_puzzles"].append(pp) if p.parent_key() == team.key(): props["team_puzzles"].append(pp) else: props["other_puzzles"].append(pp) feedback_keys = [ db.Key.from_path("Feedback", str(team.key()), parent=pp["key"]) for pp in props["other_puzzles"] ] for key, feedback in zip(feedback_keys, model.Feedback.get(feedback_keys)): pp = puzzle_props.get(key.parent()) if pp: pp["feedback"] = model.GetProperties( feedback or model.Feedback(key=key)) no_scores = model.Feedback().scores for review in model.Feedback.all().ancestor(team): pp = puzzle_props.get(review.key().parent()) if pp: if review.comment and review.comment.strip(): pp["comment_count"] += 1 pp["vote_count"] += 1 for guess in model.Guess.all().ancestor(game): pp = puzzle_props.get(guess.parent_key()) if not pp: continue if guess.answer in pp["answers"]: pp["solve_teams"].add(guess.team.key()) if guess.team.key() == team.key(): if guess.answer in pp["answers"]: pp["solve_time"] = guess.timestamp pp["guess_count"] += 1 self.response.out.write(template.render("team.dj.html", props))
def post(self): game = model.GetGame() if not GetAdminEmail(game): return self.error(403) ingredients = [self.request.get("ingredient%d" % i) for i in range(3)] admin_users = re.split(r'[,\s]+', self.request.get("admin_users")) game.location = self.request.get("location") game.ingredients = [i for i in ingredients if i] game.ingredients_visible = bool( self.request.get("ingredients_visible")) game.admin_users = [u for u in admin_users if u] game.login_enabled = bool(self.request.get("login_enabled")) game.solving_enabled = bool(self.request.get("solving_enabled")) game.voting_enabled = bool(self.request.get("voting_enabled")) game.results_enabled = bool(self.request.get("results_enabled")) game.put() for team in model.Team.all().ancestor(game): try: bonus = float(self.request.get("bonus.%d" % team.key().id())) except: bonus = 0.0 if bonus != team.bonus: team.bonus = bonus team.put() n = self.request.get("delete_team") if n: for tk in model.Team.all(keys_only=True).ancestor(game).filter( "name", n): db.delete( model.Guess.all(keys_only=True).ancestor(game).filter( "team", tk)) db.delete([ db.Key.from_path("Feedback", str(tk), parent=p.key()) for p in model.Puzzle.all().ancestor(game) ]) db.delete(db.Query(keys_only=True).ancestor(tk)) if self.request.get("new_team"): # before assign_numbers is handled team = model.Team(parent=game) team.name = self.request.get("new_team") team.password = self.request.get("new_password") team.put() for pt in PUZZLE_TYPES: model.Puzzle(parent=team, key_name=pt).put() nonum = model.Puzzle().number puzzles = list(model.Puzzle.all().ancestor(game)) for puzzle in puzzles: k = puzzle.key() num = self.request.get("number.%d.%s" % (k.parent().id(), k.name())) orig = self.request.get("number.%d.%s.orig" % (k.parent().id(), k.name())) if num != orig: puzzle.number = num or nonum puzzle.put() if self.request.get("assign_numbers"): try: n = int(self.request.get("assign_start")) except: n = 1 taken = {} # numbers already used type_puzzles = {} # group puzzles by type before scrambling order for p in puzzles: if p.number == nonum or not p.number: type_puzzles.setdefault(p.key().name(), []).append(p) else: taken[p.number] = 1 for ptype, plist in sorted(type_puzzles.iteritems()): random.shuffle(plist) for p in plist: while taken.has_key(str(n)): n += 1 p.number = str(n) p.put() n += 1 self.redirect("/admin")
def get(self): game = model.GetGame() admin_email = GetAdminEmail(game) if not admin_email: # TODO(egnor): Without multilogin, this creates redirect loops. return self.redirect(users.create_login_url(dest_url="/admin")) props = { "game": model.GetProperties(game), "admin_email": admin_email, "admin_logout_url": users.create_logout_url(dest_url="/admin"), "puzzles": [], "teams": [], } team_by_key = {} for team in model.Team.all().ancestor(game): team_props = team_by_key[team.key()] = model.GetProperties(team) team_props.update({ "feedback_count": 0, "works": [], }) props["teams"].append(team_props) puzzle_by_key = {} for p in sorted(model.Puzzle.all().ancestor(game), key=puzzle.SortKey): puzzle_props = puzzle_by_key[p.key()] = model.GetProperties(p) author_props = team_by_key.get(p.key().parent(), {}) puzzle_props.update({ "author": author_props.get("name"), "author_id": author_props.get("key_id"), "comment_count": 0, "solve_count": 0, }) props["puzzles"].append(puzzle_props) work_by_keys = {} for tp in props["teams"]: for pp in props["puzzles"]: work_props = work_by_keys[(tp["key"], pp["key"])] = { "puzzle": pp, "guess_count": 0, } tp["works"].append(work_props) for guess in model.Guess.all().ancestor(game).order("timestamp"): wp = work_by_keys[(guess.team.key(), guess.key().parent())] wp["guess_count"] += 1 if guess.answer in wp["puzzle"]["answers"] and not wp.get( "solve_time"): wp["puzzle"]["solve_count"] += 1 wp["solve_time"] = guess.timestamp wp["solve_rank"] = Ordinal(wp["puzzle"]["solve_count"]) for feedback in model.Feedback.all().ancestor(game): if feedback.key().parent().parent() == db.Key( feedback.key().name()): feedback.delete( ) # Remove bogus self-votes from older versions. else: team_props = team_by_key[db.Key(feedback.key().name())] team_props["feedback_count"] += 1 if feedback.comment and feedback.comment.strip(): puzzle_props = puzzle_by_key[feedback.key().parent()] puzzle_props["comment_count"] += 1 self.response.out.write(template.render("admin.dj.html", props))