public async Task <IActionResult> Index(string eventId, int puzzleId)
        {
            Event currentEvent = await EventHelper.GetEventFromEventId(context, eventId);

            PuzzleUser user = await PuzzleUser.GetPuzzleUserForCurrentUser(context, User, userManager);

            Team team = await UserEventHelper.GetTeamForPlayer(context, currentEvent, user);

            Puzzle thisPuzzle = await context.Puzzles.FirstOrDefaultAsync(m => m.ID == puzzleId);

            // Find the material file with the latest-alphabetically ShortName that contains the substring "customPage".
            var materialFile = await(from f in context.ContentFiles
                                     where f.Puzzle == thisPuzzle && f.FileType == ContentFileType.PuzzleMaterial && f.ShortName.Contains("customPage")
                                     orderby f.ShortName descending
                                     select f).FirstOrDefaultAsync();

            if (materialFile == null)
            {
                return(Content("ERROR:  There's no custom page uploaded for this puzzle"));
            }

            var materialUrl = materialFile.Url;

            // Download that material file.
            string fileContents;

            using (var wc = new System.Net.WebClient())
            {
                fileContents = await wc.DownloadStringTaskAsync(materialUrl);
            }

            // Return the file contents to the user.
            return(Content(fileContents, "text/html"));
        }
        public async Task IsPuzzleAuthorCheck(AuthorizationHandlerContext authContext, IAuthorizationRequirement requirement)
        {
            EventRole role = GetEventRoleFromRoute();

            if (role != EventRole.author)
            {
                return;
            }

            PuzzleUser puzzleUser = await PuzzleUser.GetPuzzleUserForCurrentUser(dbContext, authContext.User, userManager);

            Puzzle puzzle = await GetPuzzleFromRoute();

            Event thisEvent = await GetEventFromRoute();

            if (thisEvent != null && await UserEventHelper.IsAuthorOfPuzzle(dbContext, puzzle, puzzleUser))
            {
                authContext.Succeed(requirement);
            }

            if (puzzle != null)
            {
                dbContext.Entry(puzzle).State = EntityState.Detached;
            }
        }
        public async Task IsPlayerOnTeamCheck(AuthorizationHandlerContext authContext, IAuthorizationRequirement requirement)
        {
            EventRole role = GetEventRoleFromRoute();

            if (role != EventRole.play)
            {
                return;
            }

            PuzzleUser puzzleUser = await PuzzleUser.GetPuzzleUserForCurrentUser(dbContext, authContext.User, userManager);

            Team team = await GetTeamFromRoute();

            Event thisEvent = await GetEventFromRoute();

            if (thisEvent != null)
            {
                Team userTeam = await UserEventHelper.GetTeamForPlayer(dbContext, thisEvent, puzzleUser);

                if (userTeam != null && userTeam.ID == team.ID)
                {
                    authContext.Succeed(requirement);
                }
            }
        }
        public async Task <IActionResult> OnGetAsync(int?puzzleId, int?refresh)
        {
            if (refresh != null)
            {
                Refresh = refresh;
            }

            if (puzzleId != null)
            {
                Puzzle = await _context.Puzzles.Where(m => m.ID == puzzleId && m.EventID == Event.ID).FirstOrDefaultAsync();

                if (Puzzle == null)
                {
                    return(NotFound());
                }

                if (EventRole == EventRole.author && !await UserEventHelper.IsAuthorOfPuzzle(_context, Puzzle, LoggedInUser))
                {
                    return(Forbid());
                }
            }

            await PopulateUI(puzzleId);

            return(Page());
        }
Exemplo n.º 5
0
        public async Task <IActionResult> OnGetAsync(int puzzleId)
        {
            Puzzle = await _context.Puzzles.Where(p => p.ID == puzzleId).FirstOrDefaultAsync();

            if (Puzzle == null)
            {
                return(NotFound("Puzzle does not exist."));
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            int solvedPuzzleCount = 0;

            switch (Puzzle.PieceMetaUsage)
            {
            case PieceMetaUsage.EntireEvent:
                solvedPuzzleCount = await _context.PuzzleStatePerTeam.Where(ps => ps.Team == team && ps.SolvedTime != null && ps.Puzzle.SolveValue >= 10).CountAsync();

                break;

            case PieceMetaUsage.GroupOnly:
                solvedPuzzleCount = await _context.PuzzleStatePerTeam.Where(ps => ps.Team == team && ps.SolvedTime != null && ps.Puzzle.SolveValue >= 10 && ps.Puzzle.Group == Puzzle.Group).CountAsync();

                break;

            default:
                return(NotFound("Puzzle does not support the simple meta view."));
            }

            EarnedPieces = await _context.Pieces.Where(p => p.PuzzleID == puzzleId && p.ProgressLevel <= solvedPuzzleCount).OrderBy(p => p.ProgressLevel).ToListAsync();

            return(Page());
        }
Exemplo n.º 6
0
        public async Task <IActionResult> Post(string eventId, int puzzleId, List <int> query_puzzle_ids, int?min_solve_count, string annotations,
                                               string last_sync_time)
        {
            // Find what team this user is on, relative to the event.

            Event currentEvent = await EventHelper.GetEventFromEventId(context, eventId);

            if (currentEvent == null)
            {
                return(Unauthorized());
            }
            PuzzleUser user = await PuzzleUser.GetPuzzleUserForCurrentUser(context, User, userManager);

            if (user == null)
            {
                return(Unauthorized());
            }
            Team team = await UserEventHelper.GetTeamForPlayer(context, currentEvent, user);

            if (team == null)
            {
                return(Unauthorized());
            }

            var helper   = new SyncHelper(context);
            var response = await helper.GetSyncResponse(currentEvent.ID, team.ID, puzzleId, query_puzzle_ids, min_solve_count,
                                                        annotations, last_sync_time, false);

            return(Json(response));
        }
        public async Task <IActionResult> OnGetAsync(int puzzleId)
        {
            Puzzle = await _context.Puzzles.Where(p => p.ID == puzzleId).FirstOrDefaultAsync();

            if (Puzzle == null)
            {
                return(NotFound("Puzzle does not exist."));
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            int totalWeight = 0;

            if (string.IsNullOrEmpty(Puzzle.PieceMetaTagFilter))
            {
                // NOTE: By default, puzzles are filtered by looking at score.
                // If you want a more sophisticated filtering mechanism, set a PieceMetaTagFilter (which is a Regex)
                // and set tags on all puzzles you wish to consider.
                IQueryable <PuzzleStatePerTeam> pieceQuery = _context.PuzzleStatePerTeam.Where(ps => ps.Team == team && ps.SolvedTime != null && ps.Puzzle.SolveValue >= 10 && ps.Puzzle.SolveValue < 50);

                if (Puzzle.PieceMetaUsage == PieceMetaUsage.GroupOnly)
                {
                    pieceQuery = pieceQuery.Where(ps => ps.Puzzle.Group == Puzzle.Group);
                }
                else if (Puzzle.PieceMetaUsage != PieceMetaUsage.EntireEvent)
                {
                    return(NotFound("Puzzle does not support the simple meta view."));
                }

                totalWeight = await pieceQuery.SumAsync(ps => ps.Puzzle.PieceWeight ?? 1);
            }
            else
            {
                var puzData = await(from pspt in _context.PuzzleStatePerTeam
                                    join puz in _context.Puzzles on pspt.PuzzleID equals puz.ID
                                    where pspt.Team == team &&
                                    pspt.SolvedTime != null &&
                                    (Puzzle.PieceMetaUsage != PieceMetaUsage.GroupOnly || puz.Group == Puzzle.Group)
                                    select new { PieceTag = puz.PieceTag, PieceWeight = puz.PieceWeight }).ToListAsync();

                Regex filterRegex = new Regex(Puzzle.PieceMetaTagFilter);
                foreach (var puz in puzData)
                {
                    if (!string.IsNullOrEmpty(puz.PieceTag) && filterRegex.Match(puz.PieceTag)?.Success == true)
                    {
                        totalWeight += puz.PieceWeight ?? 1;
                    }
                }
            }

            EarnedPieces = await _context.Pieces.Where(p => p.PuzzleID == puzzleId && p.ProgressLevel <= totalWeight).OrderBy(p => p.ProgressLevel).ThenBy(p => p.Contents).ToListAsync();

            return(Page());
        }
Exemplo n.º 8
0
        public async Task <IActionResult> OnGetAsync()
        {
            if (EventRole == EventRole.admin)
            {
                Puzzles = await _context.Puzzles.Where(p => p.Event == Event).ToListAsync();
            }
            else
            {
                Puzzles = await UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser).ToListAsync();
            }

            return(Page());
        }
        public async Task <int> GetTeamId()
        {
            if (EventRole == ModelBases.EventRole.play)
            {
                Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

                return(team != null ? team.ID : -1);
            }
            else
            {
                return(-1);
            }
        }
Exemplo n.º 10
0
        private async Task SetupContext(int puzzleId)
        {
            Team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            Puzzle = await _context.Puzzles.Where(
                (p) => p.ID == puzzleId).FirstOrDefaultAsync();

            PuzzleState = await(PuzzleStateHelper
                                .GetFullReadOnlyQuery(
                                    _context,
                                    Event,
                                    Puzzle,
                                    Team))
                          .FirstAsync();

            SubmissionViews = await(from submission in _context.Submissions
                                    join user in _context.PuzzleUsers on submission.Submitter equals user
                                    join r in _context.Responses on submission.Response equals r into responses
                                    from response in responses.DefaultIfEmpty()
                                    where submission.Team == Team &&
                                    submission.Puzzle == Puzzle
                                    orderby submission.TimeSubmitted
                                    select new SubmissionView()
            {
                Submission      = submission,
                Response        = response,
                SubmitterName   = user.Name,
                FreeformReponse = submission.FreeformResponse,
                IsFreeform      = Puzzle.IsFreeform
            }).ToListAsync();

            Submissions = new List <Submission>(SubmissionViews.Count);
            foreach (SubmissionView submissionView in SubmissionViews)
            {
                Submissions.Add(submissionView.Submission);
            }

            PuzzlesCausingGlobalLockout = await PuzzleStateHelper.PuzzlesCausingGlobalLockout(_context, Event, Team).ToListAsync();

            if (PuzzleState.SolvedTime != null)
            {
                if (!Puzzle.IsFreeform && Submissions?.Count > 0)
                {
                    AnswerToken = Submissions.Last().SubmissionText;
                }
                else
                {
                    AnswerToken = "(marked as solved by admin or author)";
                }
            }
        }
Exemplo n.º 11
0
        public async Task <IActionResult> OnGetAsync(SortOrder?sort)
        {
            Sort = sort;

            if (EventRole == EventRole.admin)
            {
                HintViews = await _context.Hints.Where(h => h.Puzzle.Event == Event)
                            .Select(h => new HintView {
                    PuzzleId = h.Puzzle.ID, PuzzleName = h.Puzzle.Name, Description = h.Description, Content = h.Content, Cost = h.Cost
                })
                            .ToListAsync();
            }
            else
            {
                HintViews = await(from p in UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser)
                                  join h in _context.Hints on p equals h.Puzzle
                                  select new HintView {
                    PuzzleId = p.ID, PuzzleName = p.Name, Description = h.Description, Content = h.Content, Cost = h.Cost
                })
                            .ToListAsync();
            }

            switch (sort ?? DefaultSort)
            {
            case SortOrder.PuzzleAscending:
                HintViews.Sort((a, b) => a.PuzzleName.CompareTo(b.PuzzleName));
                break;

            case SortOrder.PuzzleDescending:
                HintViews.Sort((a, b) => - a.PuzzleName.CompareTo(b.PuzzleName));
                break;

            case SortOrder.DescriptionAscending:
                HintViews.Sort((a, b) => a.Description.CompareTo(b.Description));
                break;

            case SortOrder.DescriptionDescending:
                HintViews.Sort((a, b) => - a.Description.CompareTo(b.Description));
                break;

            case SortOrder.CostAscending:
                HintViews.Sort((a, b) => Math.Abs(a.Cost).CompareTo(Math.Abs(b.Cost)));
                break;

            case SortOrder.CostDescending:
                HintViews.Sort((a, b) => - Math.Abs(a.Cost).CompareTo(Math.Abs(b.Cost)));
                break;
            }

            return(Page());
        }
Exemplo n.º 12
0
        public async Task <IActionResult> OnGetAsync(string eventId, int puzzleId)
        {
            Event currentEvent = await EventHelper.GetEventFromEventId(_context, eventId);

            if (currentEvent == null)
            {
                return(Unauthorized());
            }
            EventId = currentEvent.ID;

            PuzzleUser user = LoggedInUser;

            if (user == null)
            {
                return(Unauthorized());
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, currentEvent, user);

            if (team == null)
            {
                return(Unauthorized());
            }

            Puzzle kitchenSyncPuzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.Name == "Kitchen Sync" && m.Event.ID == EventId);

            KitchenSyncId = kitchenSyncPuzzle.ID;
            Puzzle heatSyncPuzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.Name == "Heat Sync" && m.Event.ID == EventId);

            HeatSyncId = heatSyncPuzzle.ID;
            Puzzle lipSyncPuzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.Name == "Lip Sync" && m.Event.ID == EventId);

            LipSyncId = lipSyncPuzzle.ID;
            Puzzle syncTestMetapuzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.Name == "Sync Test" && m.Event.ID == EventId);

            MetapuzzleId = syncTestMetapuzzle.ID;

            var        helper           = new SyncHelper(_context);
            List <int> query_puzzle_ids = new List <int> {
                KitchenSyncId, HeatSyncId, LipSyncId
            };
            var response = await helper.GetSyncResponse(currentEvent.ID, team.ID, puzzleId, query_puzzle_ids, 0, null, null);

            var responseSerialized = JsonConvert.SerializeObject(response);

            InitialSyncString = HttpUtility.JavaScriptStringEncode(responseSerialized);

            return(Page());
        }
Exemplo n.º 13
0
        public async Task <IActionResult> OnGet(int puzzleId)
        {
            PrereqPuzzleId = puzzleId;

            Puzzle puzzle = await(from puzz in _context.Puzzles
                                  where puzz.ID == puzzleId
                                  select puzz).FirstOrDefaultAsync();

            if (puzzle == null)
            {
                return(NotFound());
            }

            // Restrict this page to whistle stop non-puzzles
            if (puzzle.MinutesOfEventLockout == 0 || puzzle.IsPuzzle)
            {
                return(NotFound());
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            var puzzleStateQuery     = PuzzleStateHelper.GetFullReadOnlyQuery(_context, Event, null, team);
            PuzzleStatePerTeam state = await(from pspt in puzzleStateQuery
                                             where pspt.PuzzleID == puzzle.ID
                                             select pspt).FirstOrDefaultAsync();

            if (state == null)
            {
                return(NotFound());
            }

            // Only move forward if the puzzle is open and unsolved
            if (state.UnlockedTime == null || state.SolvedTime != null)
            {
                return(NotFound());
            }

            CurrentPuzzle = puzzle;

            // Treat all locked puzzles where this is a prerequisite as puzzles that can be unlocked
            PuzzleOptions = await(from pspt in puzzleStateQuery
                                  join prereq in _context.Prerequisites on pspt.PuzzleID equals prereq.PuzzleID
                                  where prereq.PrerequisiteID == puzzle.ID &&
                                  pspt.SolvedTime == null && pspt.UnlockedTime == null
                                  select prereq.Puzzle).ToListAsync();

            return(Page());
        }
        public async Task <IActionResult> OnGetAsync(int?puzzleId)
        {
            IQueryable <Submission> submissionsQ = null;

            if (puzzleId == null)
            {
                if (EventRole == EventRole.admin)
                {
                    submissionsQ = _context.Submissions.Where((s) => s.Puzzle.Event == Event);
                }
                else
                {
                    submissionsQ = UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser)
                                   .SelectMany((p) => p.Submissions);
                }
            }
            else
            {
                Puzzle = await _context.Puzzles.Where(m => m.ID == puzzleId).FirstOrDefaultAsync();

                if (EventRole == EventRole.author && !await UserEventHelper.IsAuthorOfPuzzle(_context, Puzzle, LoggedInUser))
                {
                    return(Forbid());
                }

                submissionsQ = _context.Submissions.Where((s) => s.Puzzle != null && s.Puzzle.ID == puzzleId);
            }

            IQueryable <SubmissionCountsView> incorrectCounts = submissionsQ
                                                                .Where(submission => submission.Response == null)
                                                                .GroupBy(submission => Tuple.Create <string, int>
                                                                         (
                                                                             submission.SubmissionText,
                                                                             submission.PuzzleID
                                                                         ))
                                                                .Select((submissions) => new SubmissionCountsView()
            {
                PuzzleID               = submissions.First().PuzzleID,
                PuzzleName             = submissions.First().Puzzle.Name,
                SubmissionText         = submissions.Key.Item1,
                NumberOfTimesSubmitted = submissions.Count()
            })
                                                                .OrderByDescending(incorrectCountView => incorrectCountView.NumberOfTimesSubmitted);

            SubmissionCounts = incorrectCounts.ToAsyncEnumerable().ToEnumerable();
            return(Page());
        }
Exemplo n.º 15
0
        public async Task <IActionResult> OnGetAsync()
        {
            IQueryable <Puzzle> query;

            if (EventRole == EventRole.admin)
            {
                query = _context.Puzzles.Where(p => p.Event == Event);
            }
            else
            {
                query = UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser);
            }

            Puzzles = await query.OrderBy((p) => p.Group).ThenBy((p) => p.OrderInGroup).ThenBy((p) => p.Name).ToListAsync();

            return(Page());
        }
        public async Task <IActionResult> OnGetAsync(int?puzzleId)
        {
            IQueryable <Submission> submissionsQ = null;

            if (puzzleId == null)
            {
                if (EventRole == EventRole.admin)
                {
                    submissionsQ = _context.Submissions.Where((s) => s.Puzzle.Event == Event);
                }
                else
                {
                    submissionsQ = UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser)
                                   .SelectMany((p) => p.Submissions);
                }
            }
            else
            {
                Puzzle = await _context.Puzzles.Where(m => m.ID == puzzleId).FirstOrDefaultAsync();

                if (EventRole == EventRole.author && !await UserEventHelper.IsAuthorOfPuzzle(_context, Puzzle, LoggedInUser))
                {
                    return(Forbid());
                }

                submissionsQ = _context.Submissions.Where((s) => s.Puzzle != null && s.Puzzle.ID == puzzleId);
            }

            SubmissionCounts = await(from submission in submissionsQ
                                     where submission.Response == null &&
                                     !submission.Puzzle.IsFreeform
                                     group submission by new { submission.PuzzleID, submission.SubmissionText, submission.Puzzle.Name } into submissionCounts
                                     orderby submissionCounts.Count() descending
                                     select new SubmissionCountsView
            {
                PuzzleID               = submissionCounts.Key.PuzzleID,
                PuzzleName             = submissionCounts.Key.Name,
                SubmissionText         = submissionCounts.Key.SubmissionText,
                NumberOfTimesSubmitted = submissionCounts.Count()
            }
                                     ).ToListAsync();
            return(Page());
        }
Exemplo n.º 17
0
        public async Task <IActionResult> OnGet(int puzzleId)
        {
            Puzzle puzzle = await(from puzz in _context.Puzzles
                                  where puzz.ID == puzzleId
                                  select puzz).FirstOrDefaultAsync();

            if (puzzle == null)
            {
                return(NotFound());
            }

            // Restrict to the Backstage metapuzzle
            if (puzzle.Group != "Backstage")
            {
                return(NotFound());
            }
            if (puzzle.SolveValue != 50)
            {
                return(NotFound());
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            var puzzleQuery            = PuzzleStateHelper.GetFullReadOnlyQuery(_context, Event, null, team, null);
            var solvedBackstagePuzzles = await(from PuzzleStatePerTeam pspt in puzzleQuery
                                               where pspt.SolvedTime != null && pspt.UnlockedTime != null && pspt.Puzzle.IsPuzzle && pspt.Puzzle.Group == "Backstage"
                                               select new BackstageSolveStatus()
            {
                PuzzleName = pspt.Puzzle.Name, SolveTime = (int)(pspt.SolvedTime.Value - pspt.UnlockedTime.Value).TotalSeconds
            }).ToListAsync();

            string json        = JsonConvert.SerializeObject(solvedBackstagePuzzles);
            string escapedJson = Uri.EscapeDataString(json);

            byte[]   macKey = Encoding.ASCII.GetBytes(puzzle.Description);
            HMACSHA1 hasher = new HMACSHA1(macKey);

            byte[] jsonBytes = Encoding.ASCII.GetBytes(escapedJson);
            byte[] mac       = hasher.ComputeHash(jsonBytes);
            string macString = Convert.ToBase64String(mac).Replace('/', '_').Replace('+', '.');

            return(Redirect($"https://ph20backstage.azurewebsites.net/openingnight/{macString}/{escapedJson}"));
        }
Exemplo n.º 18
0
        public async Task <IActionResult> OnGetAsync(string eventId, int puzzleId)
        {
            Event currentEvent = await EventHelper.GetEventFromEventId(_context, eventId);

            if (currentEvent == null)
            {
                return(Unauthorized());
            }
            EventId = currentEvent.ID;

            PuzzleUser user = LoggedInUser;

            if (user == null)
            {
                return(Unauthorized());
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, currentEvent, user);

            if (team == null)
            {
                return(Unauthorized());
            }

            Puzzle thisPuzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.ID == puzzleId && m.Event.ID == EventId);

            if (thisPuzzle == null || !thisPuzzle.Name.Equals("The Play That Goes Wrong"))
            {
                return(Unauthorized());
            }
            MetapuzzleId = puzzleId;

            var        helper           = new SyncHelper(_context);
            List <int> query_puzzle_ids = Enumerable.Range(MetapuzzleId - 10, 11).ToList();
            var        response         = await helper.GetSyncResponse(currentEvent.ID, team.ID, puzzleId, query_puzzle_ids, 0, null, null);

            var responseSerialized = JsonConvert.SerializeObject(response);

            InitialSyncString = HttpUtility.JavaScriptStringEncode(responseSerialized);

            return(Page());
        }
Exemplo n.º 19
0
        public static async Task IsPuzzleAuthorCheck(AuthorizationHandlerContext authContext, PuzzleServerContext dbContext, UserManager <IdentityUser> userManager, IAuthorizationRequirement requirement)
        {
            PuzzleUser puzzleUser = await PuzzleUser.GetPuzzleUserForCurrentUser(dbContext, authContext.User, userManager);

            Puzzle puzzle = await AuthorizationHelper.GetPuzzleFromContext(authContext);

            Event thisEvent = await AuthorizationHelper.GetEventFromContext(authContext);

            EventRole role = AuthorizationHelper.GetEventRoleFromContext(authContext);

            if (thisEvent != null && role == EventRole.author && await UserEventHelper.IsAuthorOfPuzzle(dbContext, puzzle, puzzleUser))
            {
                authContext.Succeed(requirement);
            }

            if (puzzle != null)
            {
                dbContext.Entry(puzzle).State = EntityState.Detached;
            }
        }
Exemplo n.º 20
0
        public static async Task IsPlayerOnTeamCheck(AuthorizationHandlerContext authContext, PuzzleServerContext dbContext, UserManager <IdentityUser> userManager, IAuthorizationRequirement requirement)
        {
            PuzzleUser puzzleUser = await PuzzleUser.GetPuzzleUserForCurrentUser(dbContext, authContext.User, userManager);

            Team team = await AuthorizationHelper.GetTeamFromContext(authContext);

            Event thisEvent = await AuthorizationHelper.GetEventFromContext(authContext);

            EventRole role = AuthorizationHelper.GetEventRoleFromContext(authContext);

            if (thisEvent != null && role == EventRole.play)
            {
                Team userTeam = await UserEventHelper.GetTeamForPlayer(dbContext, thisEvent, puzzleUser);

                if (userTeam != null && userTeam.ID == team.ID)
                {
                    authContext.Succeed(requirement);
                }
            }
        }
Exemplo n.º 21
0
        private async Task PopulateUIAsync()
        {
            IQueryable <PuzzleUser> currentAuthorsQ   = _context.PuzzleAuthors.Where(m => m.Puzzle == Puzzle).Select(m => m.Author);
            IQueryable <PuzzleUser> potentialAuthorsQ = _context.EventAuthors.Where(m => m.Event == Event).Select(m => m.Author).Except(currentAuthorsQ);

            CurrentAuthors = await currentAuthorsQ.OrderBy(p => p.Name).ToListAsync();

            PotentialAuthors = await potentialAuthorsQ.OrderBy(p => p.Name).ToListAsync();

            IQueryable <Puzzle> allVisiblePuzzles;
            IQueryable <Puzzle> allVisiblePuzzlesAndGlobalPrerequisites;

            if (EventRole == EventRole.admin)
            {
                allVisiblePuzzles = allVisiblePuzzlesAndGlobalPrerequisites = _context.Puzzles.Where(m => m.Event == Event && m != Puzzle);
            }
            else
            {
                IQueryable <Puzzle> authorPuzzles = UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser);
                Puzzle[]            thisPuzzle    = new Puzzle[] { Puzzle };

                allVisiblePuzzles = authorPuzzles.Except(thisPuzzle);
                allVisiblePuzzlesAndGlobalPrerequisites = authorPuzzles.Union(_context.Puzzles.Where(m => m.Event == Event && m.IsGloballyVisiblePrerequisite)).Except(thisPuzzle);
            }

            IQueryable <Puzzle> currentPrerequisitesQ = _context.Prerequisites.Where(m => m.Puzzle == Puzzle).Select(m => m.Prerequisite);
            IQueryable <Puzzle> potentialPrerequitesQ = allVisiblePuzzlesAndGlobalPrerequisites.Except(currentPrerequisitesQ);

            CurrentPrerequisites = await currentPrerequisitesQ.OrderBy(p => p.Name).ToListAsync();

            PotentialPrerequisites = await potentialPrerequitesQ.OrderBy(p => p.Name).ToListAsync();

            IQueryable <Puzzle> currentPrerequisitesOfQ = _context.Prerequisites.Where(m => m.Prerequisite == Puzzle).Select(m => m.Puzzle);
            IQueryable <Puzzle> potentialPrerequitesOfQ = allVisiblePuzzles.Except(currentPrerequisitesOfQ);

            CurrentPrerequisitesOf = await currentPrerequisitesOfQ.OrderBy(p => p.Name).ToListAsync();

            PotentialPrerequisitesOf = await potentialPrerequitesOfQ.OrderBy(p => p.Name).ToListAsync();
        }
Exemplo n.º 22
0
        private async Task SetupContext(int puzzleId)
        {
            Team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            Puzzle = await _context.Puzzles.Where(
                (p) => p.ID == puzzleId).FirstOrDefaultAsync();

            PuzzleState = await(PuzzleStateHelper
                                .GetFullReadOnlyQuery(
                                    _context,
                                    Event,
                                    Puzzle,
                                    Team))
                          .FirstOrDefaultAsync();

            Submissions = await _context.Submissions.Where(
                (s) => s.Team == Team &&
                s.Puzzle == Puzzle)
                          .OrderBy(submission => submission.TimeSubmitted)
                          .ToListAsync();

            PuzzlesCausingGlobalLockout = await PuzzleStateHelper.PuzzlesCausingGlobalLockout(_context, Event, Team).ToListAsync();
        }
        public async Task PlayerCanSeePuzzleCheck(AuthorizationHandlerContext authContext, IAuthorizationRequirement requirement)
        {
            PuzzleUser puzzleUser = await PuzzleUser.GetPuzzleUserForCurrentUser(dbContext, authContext.User, userManager);

            Puzzle puzzle = await GetPuzzleFromRoute();

            Event thisEvent = await GetEventFromRoute();

            if (thisEvent != null && puzzle != null)
            {
                Team team = await UserEventHelper.GetTeamForPlayer(dbContext, thisEvent, puzzleUser);

                if (team != null)
                {
                    IQueryable <PuzzleStatePerTeam> statesQ = PuzzleStateHelper.GetFullReadOnlyQuery(dbContext, thisEvent, puzzle, team);

                    if (statesQ.FirstOrDefault().UnlockedTime != null || thisEvent.AreAnswersAvailableNow)
                    {
                        authContext.Succeed(requirement);
                    }
                }
            }
        }
Exemplo n.º 24
0
        public async Task <IActionResult> OnGetAsync(int puzzleId)
        {
            Puzzle = await _context.Puzzles.Where(p => p.ID == puzzleId).FirstOrDefaultAsync();

            if (Puzzle == null)
            {
                return(NotFound("Puzzle does not exist."));
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            int solvedPuzzleCount = 0;

            switch (Puzzle.PieceMetaUsage)
            {
            // TODO: Metas are filtered out by looking at score.
            // Ideally each puzzle would have a flag saying whether it counts or not,
            // but changing the database is more risk than we need right now.
            case PieceMetaUsage.EntireEvent:
                solvedPuzzleCount = await _context.PuzzleStatePerTeam.Where(ps => ps.Team == team && ps.SolvedTime != null && ps.Puzzle.SolveValue >= 10 && ps.Puzzle.SolveValue < 50).CountAsync();

                break;

            case PieceMetaUsage.GroupOnly:
                solvedPuzzleCount = await _context.PuzzleStatePerTeam.Where(ps => ps.Team == team && ps.SolvedTime != null && ps.Puzzle.SolveValue >= 10 && ps.Puzzle.SolveValue < 50 && ps.Puzzle.Group == Puzzle.Group).CountAsync();

                break;

            default:
                return(NotFound("Puzzle does not support the simple meta view."));
            }

            EarnedPieces = await _context.Pieces.Where(p => p.PuzzleID == puzzleId && p.ProgressLevel <= solvedPuzzleCount).OrderBy(p => p.ProgressLevel).ThenBy(p => p.Contents).ToListAsync();

            return(Page());
        }
Exemplo n.º 25
0
        /// <summary>
        /// Get a writable query of puzzle state. In the course of constructing the query, it will instantiate any state records that are missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">The puzzle; if null, get all puzzles in the event.</param>
        /// <param name="team">The team; if null, get all the teams in the event.</param>
        /// <returns>A query of PuzzleStatePerTeam objects that can be sorted and instantiated, but you can't edit the results.</returns>
        private static async Task <IQueryable <PuzzleStatePerTeam> > GetFullReadWriteQueryAsync(PuzzleServerContext context, Event eventObj, Puzzle puzzle, Team team, PuzzleUser author)
        {
            if (context == null)
            {
                throw new ArgumentNullException("Context required.");
            }

            if (eventObj == null)
            {
                throw new ArgumentNullException("Event required.");
            }

            if (puzzle != null && team != null)
            {
                PuzzleStatePerTeam state = await context.PuzzleStatePerTeam.Where(s => s.Puzzle == puzzle && s.Team == team).FirstOrDefaultAsync();

                if (state == null)
                {
                    context.PuzzleStatePerTeam.Add(new DataModel.PuzzleStatePerTeam()
                    {
                        Puzzle = puzzle, Team = team
                    });
                }
            }
            else if (puzzle != null)
            {
                IQueryable <int> teamIdsQ            = context.Teams.Where(p => p.Event == eventObj).Select(p => p.ID);
                IQueryable <int> puzzleStateTeamIdsQ = context.PuzzleStatePerTeam.Where(s => s.Puzzle == puzzle).Select(s => s.TeamID);
                List <int>       teamIdsWithoutState = await teamIdsQ.Except(puzzleStateTeamIdsQ).ToListAsync();

                if (teamIdsWithoutState.Count > 0)
                {
                    for (int i = 0; i < teamIdsWithoutState.Count; i++)
                    {
                        context.PuzzleStatePerTeam.Add(new DataModel.PuzzleStatePerTeam()
                        {
                            Puzzle = puzzle, TeamID = teamIdsWithoutState[i]
                        });
                    }
                }
            }
            else if (team != null)
            {
                IQueryable <int> puzzleIdsQ = author == null?context.Puzzles.Where(p => p.Event == eventObj).Select(p => p.ID) : UserEventHelper.GetPuzzlesForAuthorAndEvent(context, eventObj, author).Select(p => p.ID);

                IQueryable <int> puzzleStatePuzzleIdsQ = context.PuzzleStatePerTeam.Where(s => s.Team == team).Select(s => s.PuzzleID);
                List <int>       puzzleIdsWithoutState = await puzzleIdsQ.Except(puzzleStatePuzzleIdsQ).ToListAsync();

                if (puzzleIdsWithoutState.Count > 0)
                {
                    for (int i = 0; i < puzzleIdsWithoutState.Count; i++)
                    {
                        context.PuzzleStatePerTeam.Add(new DataModel.PuzzleStatePerTeam()
                        {
                            Team = team, PuzzleID = puzzleIdsWithoutState[i]
                        });
                    }
                }
            }
            else if (puzzle == null && team == null)
            {
                throw new NotImplementedException("Full event query is NYI and may never be needed");
            }

            await context.SaveChangesAsync(); // query below will not return these unless we save

            // now this query is no longer sparse because we just filled it all out!
            return(GetSparseQuery(context, eventObj, puzzle, team, author));
        }
Exemplo n.º 26
0
        /// <summary>
        /// Get a read-only query of puzzle state. You won't be able to write to these values, but the query will be resilient to state records that are missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">The puzzle; if null, get all puzzles in the event.</param>
        /// <param name="team">The team; if null, get all the teams in the event.</param>
        /// <returns>A query of PuzzleStatePerTeam objects that can be sorted and instantiated, but you can't edit the results.</returns>
        public static IQueryable <PuzzleStatePerTeam> GetFullReadOnlyQuery(PuzzleServerContext context, Event eventObj, Puzzle puzzle, Team team, PuzzleUser author = null)
        {
            if (context == null)
            {
                throw new ArgumentNullException("Context required.");
            }

            if (eventObj == null)
            {
                throw new ArgumentNullException("Event required.");
            }

            if (puzzle != null && team != null)
            {
                return(context.PuzzleStatePerTeam
                       .Where(state => state.Puzzle == puzzle && state.Team == team)
                       .DefaultIfEmpty(new DataModel.PuzzleStatePerTeam()
                {
                    Puzzle = puzzle,
                    PuzzleID = puzzle.ID,
                    Team = team,
                    TeamID = team.ID
                }));
            }

#pragma warning disable IDE0031 // despite the compiler message, "teamstate?.UnlockedTime", etc does not compile here

            if (puzzle != null)
            {
                IQueryable <Team> teams = context.Teams.Where(t => t.Event == eventObj);
                IQueryable <PuzzleStatePerTeam> states = context.PuzzleStatePerTeam.Where(state => state.Puzzle == puzzle);

                return(from t in teams
                       join state in states on t.ID equals state.TeamID into tmp
                       from teamstate in tmp.DefaultIfEmpty()
                       select new PuzzleStatePerTeam
                {
                    Puzzle = puzzle,
                    PuzzleID = puzzle.ID,
                    Team = t,
                    TeamID = t.ID,
                    UnlockedTime = teamstate == null ? null : teamstate.UnlockedTime,
                    SolvedTime = teamstate == null ? null : teamstate.SolvedTime,
                    Printed = teamstate == null ? false : teamstate.Printed,
                    Notes = teamstate == null ? null : teamstate.Notes,
                    IsEmailOnlyMode = teamstate == null ? false : teamstate.IsEmailOnlyMode
                });
            }

            if (team != null)
            {
                IQueryable <Puzzle> puzzles = author == null?context.Puzzles.Where(p => p.Event == eventObj) : UserEventHelper.GetPuzzlesForAuthorAndEvent(context, eventObj, author);

                IQueryable <PuzzleStatePerTeam> states = context.PuzzleStatePerTeam.Where(state => state.Team == team);

                return(from p in puzzles
                       join state in states on p.ID equals state.PuzzleID into tmp
                       from teamstate in tmp.DefaultIfEmpty()
                       select new PuzzleStatePerTeam
                {
                    Puzzle = p,
                    PuzzleID = p.ID,
                    Team = team,
                    TeamID = team.ID,
                    UnlockedTime = teamstate == null ? null : teamstate.UnlockedTime,
                    SolvedTime = teamstate == null ? null : teamstate.SolvedTime,
                    Printed = teamstate == null ? false : teamstate.Printed,
                    Notes = teamstate == null ? null : teamstate.Notes,
                    IsEmailOnlyMode = teamstate == null ? false : teamstate.IsEmailOnlyMode
                });
            }
#pragma warning restore IDE0031

            throw new NotImplementedException("Full event query is NYI and may never be needed; use the sparse one");
        }
        public async Task <IActionResult> OnGetAsync(int?puzzleId, int?teamId, SortOrder?sort)
        {
            Sort = sort;

            if (puzzleId == null)
            {
                if (EventRole == EventRole.admin)
                {
                    IQueryable <Submission> submissionsQ;

                    if (teamId == null)
                    {
                        submissionsQ = _context.Submissions.Where((s) => s.Puzzle.Event == Event);
                    }
                    else
                    {
                        submissionsQ = _context.Submissions.Where((s) => s.Team.ID == teamId);
                    }

                    Submissions = await submissionsQ
                                  .Select((s) => new SubmissionView { SubmitterName = s.Submitter.Name, PuzzleID = s.Puzzle.ID, PuzzleName = s.Puzzle.Name, TeamID = s.Team.ID, TeamName = s.Team.Name, SubmissionText = s.SubmissionText, ResponseText = s.Response == null ? null : s.Response.ResponseText, TimeSubmitted = s.TimeSubmitted })
                                  .ToListAsync();
                }
                else
                {
                    var submissions = new List <SubmissionView>();

                    if (teamId == null)
                    {
                        List <IEnumerable <SubmissionView> > submissionsList = await UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser)
                                                                               .Select((p) => p.Submissions.Select((s) => new SubmissionView {
                            SubmitterName = s.Submitter.Name, PuzzleID = s.Puzzle.ID, PuzzleName = s.Puzzle.Name, TeamID = s.Team.ID, TeamName = s.Team.Name, SubmissionText = s.SubmissionText, ResponseText = s.Response == null ? null : s.Response.ResponseText, TimeSubmitted = s.TimeSubmitted
                        }))
                                                                               .ToListAsync();

                        foreach (var list in submissionsList)
                        {
                            submissions.AddRange(list);
                        }
                    }
                    else
                    {
                        List <IEnumerable <SubmissionView> > submissionsList = await UserEventHelper.GetPuzzlesForAuthorAndEvent(_context, Event, LoggedInUser)
                                                                               .Select((p) => p.Submissions.Where((s) => s.Team.ID == teamId).Select((s) => new SubmissionView {
                            SubmitterName = s.Submitter.Name, PuzzleID = s.Puzzle.ID, PuzzleName = s.Puzzle.Name, TeamID = s.Team.ID, TeamName = s.Team.Name, SubmissionText = s.SubmissionText, ResponseText = s.Response == null ? null : s.Response.ResponseText, TimeSubmitted = s.TimeSubmitted
                        }))
                                                                               .ToListAsync();

                        foreach (var list in submissionsList)
                        {
                            submissions.AddRange(list);
                        }
                    }

                    Submissions = submissions;
                }
            }
            else
            {
                Puzzle = await _context.Puzzles.Where(m => m.ID == puzzleId).FirstOrDefaultAsync();

                if (EventRole == EventRole.author && !await UserEventHelper.IsAuthorOfPuzzle(_context, Puzzle, LoggedInUser))
                {
                    return(Forbid());
                }

                IQueryable <Submission> submissionsQ;

                if (teamId == null)
                {
                    submissionsQ = _context.Submissions.Where((s) => s.Puzzle != null && s.Puzzle.ID == puzzleId);
                }
                else
                {
                    submissionsQ = _context.Submissions.Where((s) => s.Puzzle != null && s.Puzzle.ID == puzzleId && s.Team.ID == teamId);
                }

                Submissions = await submissionsQ
                              .Select((s) => new SubmissionView { SubmitterName = s.Submitter.Name, PuzzleID = s.Puzzle.ID, PuzzleName = s.Puzzle.Name, TeamID = s.Team.ID, TeamName = s.Team.Name, SubmissionText = s.SubmissionText, ResponseText = s.Response == null ? null : s.Response.ResponseText, TimeSubmitted = s.TimeSubmitted })
                              .ToListAsync();
            }

            if (teamId != null)
            {
                Team = await _context.Teams.Where(m => m.ID == teamId).FirstOrDefaultAsync();
            }

            switch (sort ?? DefaultSort)
            {
            case SortOrder.PlayerAscending:
                Submissions.Sort((a, b) => a.SubmitterName.CompareTo(b.SubmitterName));
                break;

            case SortOrder.PlayerDescending:
                Submissions.Sort((a, b) => - a.SubmitterName.CompareTo(b.SubmitterName));
                break;

            case SortOrder.TeamAscending:
                Submissions.Sort((a, b) => a.TeamName.CompareTo(b.TeamName));
                break;

            case SortOrder.TeamDescending:
                Submissions.Sort((a, b) => - a.TeamName.CompareTo(b.TeamName));
                break;

            case SortOrder.PuzzleAscending:
                Submissions.Sort((a, b) => a.PuzzleName.CompareTo(b.PuzzleName));
                break;

            case SortOrder.PuzzleDescending:
                Submissions.Sort((a, b) => - a.PuzzleName.CompareTo(b.PuzzleName));
                break;

            case SortOrder.ResponseAscending:
                Submissions.Sort((a, b) => a.ResponseText.CompareTo(b.ResponseText));
                break;

            case SortOrder.ResponseDescending:
                Submissions.Sort((a, b) => - a.ResponseText.CompareTo(b.ResponseText));
                break;

            case SortOrder.SubmissionAscending:
                Submissions.Sort((a, b) => a.SubmissionText.CompareTo(b.SubmissionText));
                break;

            case SortOrder.SubmissionDescending:
                Submissions.Sort((a, b) => - a.SubmissionText.CompareTo(b.SubmissionText));
                break;

            case SortOrder.TimeAscending:
                Submissions.Sort((a, b) => a.TimeSubmitted.CompareTo(b.TimeSubmitted));
                break;

            case SortOrder.TimeDescending:
                Submissions.Sort((a, b) => - a.TimeSubmitted.CompareTo(b.TimeSubmitted));
                break;
            }

            return(Page());
        }
Exemplo n.º 28
0
        public async Task <IActionResult> OnPostUnlock(int puzzleId, int unlockId)
        {
            Puzzle puzzle = await(from puzz in _context.Puzzles
                                  where puzz.ID == puzzleId
                                  select puzz).FirstOrDefaultAsync();

            if (puzzle == null)
            {
                return(NotFound());
            }

            // Restrict this page to whistle stop non-puzzles
            if (puzzle.MinutesOfEventLockout == 0 || puzzle.IsPuzzle)
            {
                return(NotFound());
            }

            Team team = await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser);

            using (var transaction = _context.Database.BeginTransaction())
            {
                var puzzleStateQuery           = PuzzleStateHelper.GetFullReadOnlyQuery(_context, Event, null, team);
                PuzzleStatePerTeam prereqState = await(from pspt in puzzleStateQuery
                                                       where pspt.PuzzleID == puzzle.ID
                                                       select pspt).FirstOrDefaultAsync();
                if (prereqState == null)
                {
                    return(NotFound());
                }

                // Only move forward if the prereq is open and unsolved
                if (prereqState.UnlockedTime == null || prereqState.SolvedTime != null)
                {
                    return(NotFound("Your team has already chosen and can't choose again"));
                }

                PuzzleStatePerTeam unlockState = await(from pspt in puzzleStateQuery
                                                       where pspt.PuzzleID == unlockId
                                                       select pspt).FirstOrDefaultAsync();
                if (unlockState == null)
                {
                    return(NotFound());
                }

                // The chosen puzzle must be locked (and unsolved)
                if (unlockState.UnlockedTime != null || unlockState.SolvedTime != null)
                {
                    return(NotFound("You've already chosen this puzzle"));
                }

                // Ensure the puzzle is actually one of the unlock options
                Prerequisites prereq = await(from pre in _context.Prerequisites
                                             where pre.PrerequisiteID == puzzleId && pre.PuzzleID == unlockId
                                             select pre).FirstOrDefaultAsync();
                if (prereq == null)
                {
                    return(NotFound());
                }

                await PuzzleStateHelper.SetSolveStateAsync(_context, Event, puzzle, team, DateTime.UtcNow);

                await PuzzleStateHelper.SetUnlockStateAsync(_context, Event, unlockState.Puzzle, team, DateTime.UtcNow);

                transaction.Commit();
            }

            Puzzle puzzleToUnlock = await(from p in _context.Puzzles
                                          where p.ID == unlockId
                                          select p).FirstOrDefaultAsync();

            string puzzleUrl;

            if (puzzleToUnlock.CustomURL != null)
            {
                puzzleUrl = PuzzleHelper.GetFormattedUrl(puzzleToUnlock, Event.ID);
            }
            else
            {
                puzzleUrl = puzzleToUnlock.PuzzleFile.UrlString;
            }

            return(Redirect(puzzleUrl));
        }
Exemplo n.º 29
0
        public async Task <IActionResult> Index(string eventId, int puzzleId)
        {
            Event currentEvent = await EventHelper.GetEventFromEventId(context, eventId);

            if (currentEvent == null)
            {
                return(Content("ERROR:  That event doesn't exist"));
            }

            PuzzleUser user = await PuzzleUser.GetPuzzleUserForCurrentUser(context, User, userManager);

            if (user == null)
            {
                return(Content("ERROR:  You aren't logged in"));
            }

            Team team = await UserEventHelper.GetTeamForPlayer(context, currentEvent, user);

            if (team == null)
            {
                return(Content("ERROR:  You're not on a team"));
            }

            Puzzle thisPuzzle = await context.Puzzles.FirstOrDefaultAsync(m => m.ID == puzzleId);

            if (thisPuzzle == null)
            {
                return(Content("ERROR:  That's not a valid puzzle ID"));
            }

            if (!currentEvent.AreAnswersAvailableNow)
            {
                var puzzleState = await(from state in context.PuzzleStatePerTeam
                                        where state.Puzzle == thisPuzzle && state.Team == team
                                        select state).FirstOrDefaultAsync();
                if (puzzleState == null || puzzleState.UnlockedTime == null)
                {
                    return(Content("ERROR:  You haven't unlocked this puzzle yet"));
                }
            }

            // Find the material file with the latest-alphabetically ShortName that contains the substring "client".

            var materialFile = await(from f in context.ContentFiles
                                     where f.Puzzle == thisPuzzle && f.FileType == ContentFileType.PuzzleMaterial && f.ShortName.Contains("client")
                                     orderby f.ShortName descending
                                     select f).FirstOrDefaultAsync();

            if (materialFile == null)
            {
                return(Content("ERROR:  There's no sync client registered for this puzzle"));
            }

            var materialUrl = materialFile.Url;

            // Start doing a sync asynchronously while we download the file contents.

            var helper = new SyncHelper(context);
            Task <Dictionary <string, object> > responseTask = helper.GetSyncResponse(currentEvent.ID, team.ID, puzzleId, null, 0, null, null, true);

            // Download that material file.

            string fileContents;

            using (var wc = new System.Net.WebClient())
            {
                fileContents = await wc.DownloadStringTaskAsync(materialUrl);
            }

            // Wait for the asynchronous sync we started earlier to complete, then serialize
            // its results and use them to replace the substring "@SYNC" where it appears
            // in the downloaded file contents.

            Dictionary <string, object> response = await responseTask;
            var responseSerialized = JsonConvert.SerializeObject(response);
            var initialSyncString  = HttpUtility.JavaScriptStringEncode(responseSerialized);

            fileContents = fileContents.Replace("@SYNC", initialSyncString);

            // Return the file contents to the user.

            return(Content(fileContents, "text/html"));
        }
        public async Task OnGetAsync(SortOrder?sort, PuzzleStateFilter?stateFilter)
        {
            this.Sort        = sort;
            this.StateFilter = stateFilter;
            this.CurrentTeam = (await UserEventHelper.GetTeamForPlayer(_context, Event, LoggedInUser));

            Dictionary <int, string> teamNameLookup = new Dictionary <int, string>();

            // build an ID-to-name mapping to improve perf
            var names = await _context.Teams.Where(t => t.Event == Event)
                        .Select(t => new { t.ID, t.Name })
                        .ToListAsync();

            names.ForEach(t => teamNameLookup[t.ID] = t.Name);

            // get the page data: puzzle, solve count, top three fastest
            var puzzlesData = await PuzzleStateHelper.GetSparseQuery(_context, this.Event, null, null)
                              .Where(s => s.SolvedTime != null && s.Puzzle.IsPuzzle)
                              .GroupBy(state => state.Puzzle)
                              .Select(g => new {
                Puzzle             = g.Key,
                SolveCount         = g.Count(),
                Fastest            = g.OrderBy(s => s.SolvedTime - s.UnlockedTime).Take(3).Select(s => new { s.Team.ID, Time = s.SolvedTime - s.UnlockedTime }),
                IsSolvedByUserTeam = g.Where(s => s.Team == this.CurrentTeam).Any()
            })
                              .OrderByDescending(p => p.SolveCount).ThenBy(p => p.Puzzle.Name)
                              .ToListAsync();

            var unlockedData = this.CurrentTeam == null ? null : (new HashSet <int>(
                                                                      await PuzzleStateHelper.GetSparseQuery(_context, this.Event, null, null)
                                                                      .Where(state => state.Team == this.CurrentTeam && state.UnlockedTime != null)
                                                                      .Select(s => s.PuzzleID)
                                                                      .ToListAsync()));

            var puzzles = new List <PuzzleStats>(puzzlesData.Count);

            for (int i = 0; i < puzzlesData.Count; i++)
            {
                var data = puzzlesData[i];

                // For players, we will hide puzzles they have not unlocked yet.
                if (EventRole == EventRole.play &&
                    (unlockedData == null ||
                     !unlockedData.Contains(data.Puzzle.ID)))
                {
                    continue;
                }

                var stats = new PuzzleStats()
                {
                    Puzzle     = data.Puzzle,
                    SolveCount = data.SolveCount,
                    SortOrder  = i,
                    Fastest    = data.Fastest.Select(f => new FastRecord()
                    {
                        ID = f.ID, Name = teamNameLookup[f.ID], Time = f.Time
                    }).ToArray(),
                    IsSolved = data.IsSolvedByUserTeam
                };

                puzzles.Add(stats);
            }

            if (this.StateFilter == PuzzleStateFilter.Unsolved)
            {
                puzzles = puzzles.Where(stats => !stats.IsSolved).ToList();
            }

            switch (sort ?? DefaultSort)
            {
            case SortOrder.RankAscending:
                puzzles.Sort((rhs, lhs) => (rhs.SortOrder - lhs.SortOrder));
                break;

            case SortOrder.RankDescending:
                puzzles.Sort((rhs, lhs) => (lhs.SortOrder - rhs.SortOrder));
                break;

            case SortOrder.CountAscending:
                puzzles.Sort((rhs, lhs) => (rhs.SolveCount - lhs.SolveCount));
                break;

            case SortOrder.CountDescending:
                puzzles.Sort((rhs, lhs) => (lhs.SolveCount - rhs.SolveCount));
                break;

            case SortOrder.PuzzleAscending:
                puzzles.Sort((rhs, lhs) => (String.Compare(rhs.Puzzle.Name,
                                                           lhs.Puzzle.Name,
                                                           StringComparison.OrdinalIgnoreCase)));

                break;

            case SortOrder.PuzzleDescending:
                puzzles.Sort((rhs, lhs) => (String.Compare(lhs.Puzzle.Name,
                                                           rhs.Puzzle.Name,
                                                           StringComparison.OrdinalIgnoreCase)));

                break;

            default:
                throw new ArgumentException($"unknown sort: {sort}");
            }

            this.Puzzles = puzzles;
        }