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> 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"));
        }