public async Task SetSolveStateAsync(Puzzle puzzle, Team team, bool value)
 {
     await PuzzleStateHelper.SetSolveStateAsync(
         _context,
         Event,
         puzzle,
         team,
         value?(DateTime?)DateTime.UtcNow : null,
         EventRole == EventRole.admin?null : LoggedInUser);
 }
Пример #2
0
        public async Task <IActionResult> OnPostAsync(int teamId)
        {
            Team = await _context.Teams.FindAsync(teamId);

            var mergeIntoTeam = await _context.Teams.FindAsync(MergeIntoID);

            if (Team == null || mergeIntoTeam == null || Team.Event != Event || mergeIntoTeam.Event != Event)
            {
                return(NotFound());
            }

            List <string> memberEmails          = null;
            List <string> mergeIntoMemberEmails = null;

            using (var transaction = await _context.Database.BeginTransactionAsync(IsolationLevel.Serializable))
            {
                var members = await _context.TeamMembers.Where(tm => tm.Team.ID == teamId).ToListAsync();

                memberEmails = await _context.TeamMembers.Where(tm => tm.Team.ID == teamId).Select(tm => tm.Member.Email).ToListAsync();

                mergeIntoMemberEmails = await _context.TeamMembers.Where(tm => tm.Team.ID == MergeIntoID).Select(m => m.Member.Email).ToListAsync();

                var states = await PuzzleStateHelper.GetSparseQuery(_context, Team.Event, null, Team).ToListAsync();

                var mergeIntoStates = await PuzzleStateHelper.GetSparseQuery(_context, Team.Event, null, mergeIntoTeam).ToDictionaryAsync(s => s.PuzzleID);

                // copy all the team members over
                foreach (var member in members)
                {
                    member.Team = mergeIntoTeam;
                }

                // also copy puzzle solves over
                foreach (var state in states)
                {
                    if (state.SolvedTime != null && mergeIntoStates.TryGetValue(state.PuzzleID, out var mergeIntoState) && mergeIntoState.SolvedTime == null)
                    {
                        await PuzzleStateHelper.SetSolveStateAsync(_context, Team.Event, mergeIntoState.Puzzle, mergeIntoTeam, state.UnlockedTime);
                    }
                }

                await TeamHelper.DeleteTeamAsync(_context, Team, sendEmail : false);

                await _context.SaveChangesAsync();

                transaction.Commit();
            }

            MailHelper.Singleton.SendPlaintextWithoutBcc(memberEmails.Union(mergeIntoMemberEmails),
                                                         $"{Event.Name}: Team '{Team.Name}' has been merged into '{mergeIntoTeam.Name}'",
                                                         $"These two teams have been merged into one superteam. Please welcome your new teammates!");

            return(RedirectToPage("./Index"));
        }
        public async Task <IActionResult> OnPostAsync(int?puzzleId)
        {
            // Handle no radio button selected
            if (Result == FreeformResult.None)
            {
                return(RedirectToPage());
            }

            bool accepted = (Result == FreeformResult.Accepted);

            if (String.IsNullOrWhiteSpace(FreeformResponse))
            {
                FreeformResponse = Result.ToString();
            }

            Submission submission;

            using (var transaction = _context.Database.BeginTransaction())
            {
                bool isAdmin = (EventRole == EventRole.admin);
                submission = await(from Submission sub in _context.Submissions
                                   join PuzzleAuthors author in _context.PuzzleAuthors on sub.PuzzleID equals author.PuzzleID
                                   where sub.ID == SubmissionID &&
                                   sub.FreeformAccepted == null &&
                                   sub.Puzzle.EventID == Event.ID &&
                                   (isAdmin || author.Author == LoggedInUser)
                                   select sub).FirstOrDefaultAsync();

                if (submission != null)
                {
                    submission.FreeformAccepted  = accepted;
                    submission.FreeformResponse  = FreeformResponse;
                    submission.FreeformJudge     = LoggedInUser;
                    submission.FreeformFavorited = Favorite;

                    if (accepted)
                    {
                        await PuzzleStateHelper.SetSolveStateAsync(_context, Event, submission.Puzzle, submission.Team, DateTime.UtcNow);
                    }

                    await _context.SaveChangesAsync();

                    await transaction.CommitAsync();
                }
            }

            if (submission != null)
            {
                MailHelper.Singleton.SendPlaintextOneAddress(submission.Submitter.Email, $"{submission.Puzzle.Name} Submission {Result}", $"Your submission for {submission.Puzzle.Name} has been {Result} with the response: {FreeformResponse}");
            }

            return(RedirectToPage());
        }
Пример #4
0
        public async Task <IActionResult> OnPostAsync(int puzzleId, string submissionText)
        {
            if (String.IsNullOrWhiteSpace(submissionText))
            {
                ModelState.AddModelError("submissionText", "Your answer cannot be empty");
            }

            SubmissionText = submissionText;
            if (DateTime.UtcNow < Event.EventBegin)
            {
                return(NotFound("The event hasn't started yet!"));
            }

            await SetupContext(puzzleId);

            if (!ModelState.IsValid)
            {
                return(Page());
            }

            // Don't allow submissions if the team is locked out.
            if (PuzzleState.IsTeamLockedOut)
            {
                return(Page());
            }

            // Don't allow submissions if team is in email only mode.
            if (PuzzleState.IsEmailOnlyMode)
            {
                return(Page());
            }

            // Don't allow submissions after the answer has been found.
            if (PuzzleState.SolvedTime != null)
            {
                return(Page());
            }

            // Don't accept posted submissions when a puzzle is causing lockout
            if (PuzzlesCausingGlobalLockout.Count != 0 && !PuzzlesCausingGlobalLockout.Contains(Puzzle))
            {
                return(Page());
            }

            // Soft enforcement of duplicates to give a friendly message in most cases
            DuplicateSubmission = (from sub in Submissions
                                   where sub.SubmissionText == ServerCore.DataModel.Response.FormatSubmission(submissionText)
                                   select sub).Any();

            if (DuplicateSubmission)
            {
                return(Page());
            }

            // Create submission and add it to list
            Submission submission = new Submission
            {
                TimeSubmitted        = DateTime.UtcNow,
                Puzzle               = PuzzleState.Puzzle,
                Team                 = PuzzleState.Team,
                Submitter            = LoggedInUser,
                AllowFreeformSharing = AllowFreeformSharing
            };

            string submissionTextToCheck = ServerCore.DataModel.Response.FormatSubmission(submissionText);

            if (Puzzle.IsFreeform)
            {
                submission.UnformattedSubmissionText = submissionText;
            }
            else
            {
                submission.SubmissionText = submissionText;
            }

            submission.Response = await _context.Responses.Where(
                r => r.Puzzle.ID == puzzleId &&
                submissionTextToCheck == r.SubmittedText)
                                  .FirstOrDefaultAsync();

            Submissions.Add(submission);

            // Update puzzle state if submission was correct
            if (submission.Response != null && submission.Response.IsSolution)
            {
                await PuzzleStateHelper.SetSolveStateAsync(_context,
                                                           Event,
                                                           submission.Puzzle,
                                                           submission.Team,
                                                           submission.TimeSubmitted);

                AnswerToken = submission.SubmissionText;
            }
            else if (!Puzzle.IsFreeform && submission.Response == null && Event.IsAnswerSubmissionActive)
            {
                // We also determine if the puzzle should be set to email-only mode.
                if (IsPuzzleSubmissionLimitReached(
                        Event,
                        Submissions,
                        PuzzleState))
                {
                    await PuzzleStateHelper.SetEmailOnlyModeAsync(_context,
                                                                  Event,
                                                                  submission.Puzzle,
                                                                  submission.Team,
                                                                  true);

                    var authors = await _context.PuzzleAuthors.Where((pa) => pa.Puzzle == submission.Puzzle).Select((pa) => pa.Author.Email).ToListAsync();

                    MailHelper.Singleton.SendPlaintextBcc(authors,
                                                          $"{Event.Name}: Team {submission.Team.Name} is in email mode for {submission.Puzzle.Name}",
                                                          "");
                }
                else
                {
                    // If the submission was incorrect and not a partial solution,
                    // we will do the lockout computations now.
                    DateTime?lockoutExpiryTime = ComputeLockoutExpiryTime(
                        Event,
                        Submissions,
                        PuzzleState);

                    if (lockoutExpiryTime != null)
                    {
                        await PuzzleStateHelper.SetLockoutExpiryTimeAsync(_context,
                                                                          Event,
                                                                          submission.Puzzle,
                                                                          submission.Team,
                                                                          lockoutExpiryTime);
                    }
                }
            }

            _context.Submissions.Add(submission);
            await _context.SaveChangesAsync();

            SubmissionViews.Add(new SubmissionView()
            {
                Submission    = submission,
                Response      = submission.Response,
                SubmitterName = LoggedInUser.Name,
                IsFreeform    = Puzzle.IsFreeform
            });

            return(Page());
        }
Пример #5
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));
        }
Пример #6
0
        public async Task <IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return(Page());
            }

            using (var transaction = _context.Database.BeginTransaction())
            {
                //
                // Add the event and save, so the event gets an ID.
                //
                Event.TeamRegistrationBegin       = DateTime.UtcNow;
                Event.TeamRegistrationEnd         = Event.AnswerSubmissionEnd;
                Event.TeamNameChangeEnd           = Event.AnswerSubmissionEnd;
                Event.TeamMembershipChangeEnd     = Event.AnswerSubmissionEnd;
                Event.TeamMiscDataChangeEnd       = Event.AnswerSubmissionEnd;
                Event.TeamDeleteEnd               = Event.AnswerSubmissionEnd;
                Event.AnswersAvailableBegin       = Event.AnswerSubmissionEnd;
                Event.StandingsAvailableBegin     = DateTime.UtcNow;
                Event.LockoutIncorrectGuessLimit  = 5;
                Event.LockoutIncorrectGuessPeriod = 1;
                Event.LockoutDurationMultiplier   = 2;
                Event.MaxSubmissionCount          = 50;
                Event.MaxNumberOfTeams            = 120;
                Event.MaxExternalsPerTeam         = 9;
                Event.MaxTeamSize = 12;
                _context.Events.Add(Event);

                await _context.SaveChangesAsync();

                //
                // Add start puzzle, three module puzzles, and one module meta (marked as the final event puzzle for this demo)
                //
                Puzzle start = new Puzzle
                {
                    Name     = "!!!Get Hopping!!!",
                    Event    = Event,
                    IsPuzzle = false,
                    IsGloballyVisiblePrerequisite = true,
                    Description = "Start the event",
                };
                _context.Puzzles.Add(start);

                Puzzle easy = new Puzzle
                {
                    Name                 = "Bunny Slope",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    HintCoinsForSolve    = 1,
                    Group                = "Thumper's Stumpers",
                    OrderInGroup         = 1,
                    MinPrerequisiteCount = 1,
                    Description          = "Bunsweeper",
                };
                _context.Puzzles.Add(easy);

                Puzzle intermediate = new Puzzle
                {
                    Name                        = "Rabbit Run (automatically solves in ~3 mins)",
                    Event                       = Event,
                    IsPuzzle                    = true,
                    SolveValue                  = 10,
                    HintCoinsForSolve           = 2,
                    Group                       = "Thumper's Stumpers",
                    OrderInGroup                = 2,
                    MinPrerequisiteCount        = 1,
                    MinutesToAutomaticallySolve = 3,
                    Description                 = "Rabbit's Cube",
                };
                _context.Puzzles.Add(intermediate);

                Puzzle hard = new Puzzle
                {
                    Name                 = "Hare-Raising",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    HintCoinsForSolve    = 3,
                    Group                = "Thumper's Stumpers",
                    OrderInGroup         = 3,
                    MinPrerequisiteCount = 1,
                    Description          = "Lateral Leaping",
                };
                _context.Puzzles.Add(hard);

                Puzzle meta = new Puzzle
                {
                    Name                 = "Lagomorph Meta",
                    Event                = Event,
                    IsPuzzle             = true,
                    IsMetaPuzzle         = true,
                    IsFinalPuzzle        = true,
                    SolveValue           = 100,
                    Group                = "Thumper's Stumpers",
                    OrderInGroup         = 99,
                    MinPrerequisiteCount = 2,
                    Description          = "Word Hutch",
                };
                _context.Puzzles.Add(meta);

                Puzzle other = new Puzzle
                {
                    Name                 = "Rabbit Season",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    Group                = "Daffy's Delights",
                    OrderInGroup         = 1,
                    MinPrerequisiteCount = 1,
                    Description          = "Hip Hop Identification",
                    CustomURL            = "https://www.bing.com/images/search?q=%22rabbit%22",
                };
                _context.Puzzles.Add(other);

                Puzzle cheat = new Puzzle
                {
                    Name                 = "You're Despicable (cheat code)",
                    Event                = Event,
                    IsPuzzle             = true,
                    IsCheatCode          = true,
                    SolveValue           = -1,
                    Group                = "Daffy's Delights",
                    OrderInGroup         = 2,
                    MinPrerequisiteCount = 1,
                    Description          = "Duck Konundrum",
                };
                _context.Puzzles.Add(cheat);

                Puzzle lockIntro = new Puzzle
                {
                    Name                 = "Wouldn't you know... (whistle stop intro)",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 0,
                    Group                = "Roger's Railway",
                    OrderInGroup         = 1,
                    MinPrerequisiteCount = 1,
                    Description          = "Whistle Hop Intro",
                };
                _context.Puzzles.Add(lockIntro);

                Puzzle lockPuzzle = new Puzzle
                {
                    Name                  = "...Locked! (whistle stop, lasts 5 minutes)",
                    Event                 = Event,
                    IsPuzzle              = true,
                    SolveValue            = 0,
                    Group                 = "Roger's Railway",
                    OrderInGroup          = 2,
                    MinPrerequisiteCount  = 1,
                    MinutesOfEventLockout = 5,
                    Description           = "Whistle Hop",
                };
                _context.Puzzles.Add(lockPuzzle);

                Puzzle kitchenSyncPuzzle = new Puzzle
                {
                    Name                 = "Kitchen Sync",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    Group                = "Sync Test",
                    OrderInGroup         = 1,
                    MinPrerequisiteCount = 1
                };
                _context.Puzzles.Add(kitchenSyncPuzzle);

                Puzzle heatSyncPuzzle = new Puzzle
                {
                    Name                 = "Heat Sync",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    Group                = "Sync Test",
                    OrderInGroup         = 2,
                    MinPrerequisiteCount = 1
                };
                _context.Puzzles.Add(heatSyncPuzzle);

                Puzzle lipSyncPuzzle = new Puzzle
                {
                    Name                 = "Lip Sync",
                    Event                = Event,
                    IsPuzzle             = true,
                    SolveValue           = 10,
                    Group                = "Sync Test",
                    OrderInGroup         = 3,
                    MinPrerequisiteCount = 1
                };
                _context.Puzzles.Add(lipSyncPuzzle);

                Puzzle syncTestMetapuzzle = new Puzzle
                {
                    Name                 = "Sync Test",
                    Event                = Event,
                    IsPuzzle             = true,
                    IsMetaPuzzle         = true,
                    SolveValue           = 50,
                    Group                = "Sync Test",
                    OrderInGroup         = 99,
                    MinPrerequisiteCount = 1,
                    MaxAnnotationKey     = 400
                };
                _context.Puzzles.Add(syncTestMetapuzzle);

                await _context.SaveChangesAsync();

                //
                // Add responses, PARTIAL is a partial, ANSWER is the answer.
                //
                _context.Responses.Add(new Response()
                {
                    Puzzle = easy, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = easy, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = intermediate, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = intermediate, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = hard, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = hard, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = meta, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = meta, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = other, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = other, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = cheat, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = cheat, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lockIntro, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lockIntro, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lockPuzzle, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lockPuzzle, SubmittedText = "ANSWER", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = kitchenSyncPuzzle, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = kitchenSyncPuzzle, SubmittedText = "SYNC", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = heatSyncPuzzle, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = heatSyncPuzzle, SubmittedText = "OR", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lipSyncPuzzle, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = lipSyncPuzzle, SubmittedText = "SWIM", ResponseText = "Correct!", IsSolution = true
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = syncTestMetapuzzle, SubmittedText = "PARTIAL", ResponseText = "Keep going..."
                });
                _context.Responses.Add(new Response()
                {
                    Puzzle = syncTestMetapuzzle, SubmittedText = "SYNCORSWIM", ResponseText = "Correct!", IsSolution = true
                });

                string hint1Description = "Tell me about the rabbits, George.";
                string hint1Content     = "O.K. Some day – we’re gonna get the jack together and we’re gonna have a little house and a couple of acres an’ a cow and some pigs and...";
                string hint2Description = "Go on... George. How I get to tend the rabbits.";
                string hint2Content     = "Well, we’ll have a big vegetable patch and a rabbit-hutch and chickens.";
                _context.Hints.Add(new Hint()
                {
                    Puzzle = easy, Description = hint1Description, DisplayOrder = 0, Cost = 0, Content = hint1Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = easy, Description = hint2Description, DisplayOrder = 1, Cost = 1, Content = hint2Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = intermediate, Description = hint1Description, DisplayOrder = 0, Cost = 0, Content = hint1Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = intermediate, Description = hint2Description, DisplayOrder = 1, Cost = 1, Content = hint2Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = hard, Description = hint1Description, DisplayOrder = 0, Cost = 0, Content = hint1Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = hard, Description = hint2Description, DisplayOrder = 1, Cost = 1, Content = hint2Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = meta, Description = hint1Description, DisplayOrder = 0, Cost = 0, Content = hint1Content
                });
                _context.Hints.Add(new Hint()
                {
                    Puzzle = meta, Description = hint2Description, DisplayOrder = 1, Cost = 1, Content = hint2Content
                });

                await _context.SaveChangesAsync();

                //
                // Set up prequisite links.
                // The first two depend on start puzzle, then the third depends on one of the first two, then the meta depends on two of the first three.
                //
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = easy, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = intermediate, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = hard, Prerequisite = easy
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = hard, Prerequisite = intermediate
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = meta, Prerequisite = easy
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = meta, Prerequisite = intermediate
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = meta, Prerequisite = hard
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = other, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = cheat, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = lockIntro, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = lockPuzzle, Prerequisite = lockIntro
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = kitchenSyncPuzzle, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = heatSyncPuzzle, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = lipSyncPuzzle, Prerequisite = start
                });
                _context.Prerequisites.Add(new Prerequisites()
                {
                    Puzzle = syncTestMetapuzzle, Prerequisite = start
                });

                await _context.SaveChangesAsync();

                //
                // Create puzzle pieces.
                //
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 0, 1, "xxx xxxx'x x xXxxx!", 3, "What Crocodile Dundee might say"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 1, 2, "xxx xxxx xxxx xxx Xxxxx", 1, "In <i>Hey Diddle Diddle</i>, what the dish did"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 1, 3, "xxXx", 1, "It smells"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 2, 4, "xxX", 4, "You reach things by extending it"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 2, 5, "Xxx xxxxx", 1, "Result of the <i>Exxon Valdez</i> crash"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 2, 6, "xxxxX", 2, "What you make out of turkey drippings"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 3, 7, "xxxXx xxx", 4, "Another name for a slow cooker"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 4, 8, "xXxxxx", 3, "The index is one of them"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 4, 9, "xxxxX", 2, "It can suffer when you play tennis"));
                _context.Pieces.Add(MakePiece(syncTestMetapuzzle, 4, 10, "xxxxxxX xxxxxxx", 2, "What Chekov asked strangers the location of in Star Trek IV, garnering suspicion due to his Russian accent"));

                await _context.SaveChangesAsync();

                //
                // Create teams. Can we add players to these?
                //
                Team team1 = new Team {
                    Name = "Team Bugs", Event = Event
                };
                _context.Teams.Add(team1);

                Team team2 = new Team {
                    Name = "Team Babs", Event = Event
                };
                _context.Teams.Add(team2);

                Team team3 = new Team {
                    Name = "Team Buster", Event = Event
                };
                _context.Teams.Add(team3);

                Team teamLoneWolf = null;
                if (AddCreatorToLoneWolfTeam)
                {
                    teamLoneWolf = new Team {
                        Name = "Lone Wolf", Event = Event
                    };
                    _context.Teams.Add(teamLoneWolf);
                }

                var demoCreatorUser = await PuzzleUser.GetPuzzleUserForCurrentUser(_context, User, _userManager);

                if (demoCreatorUser != null)
                {
                    //
                    // Event admin/author
                    //
                    _context.EventAdmins.Add(new EventAdmins()
                    {
                        Event = Event, Admin = demoCreatorUser
                    });
                    _context.EventAuthors.Add(new EventAuthors()
                    {
                        Event = Event, Author = demoCreatorUser
                    });

                    //
                    // Puzzle author (for Thumper module only)
                    //
                    _context.PuzzleAuthors.Add(new PuzzleAuthors()
                    {
                        Puzzle = easy, Author = demoCreatorUser
                    });
                    _context.PuzzleAuthors.Add(new PuzzleAuthors()
                    {
                        Puzzle = intermediate, Author = demoCreatorUser
                    });
                    _context.PuzzleAuthors.Add(new PuzzleAuthors()
                    {
                        Puzzle = hard, Author = demoCreatorUser
                    });
                    _context.PuzzleAuthors.Add(new PuzzleAuthors()
                    {
                        Puzzle = meta, Author = demoCreatorUser
                    });
                }

                // TODO: Files (need to know how to detect whether local blob storage is configured)
                // Is there a point to adding Feedback or is that quick/easy enough to demo by hand?

                await _context.SaveChangesAsync();

                if (teamLoneWolf != null)
                {
                    _context.TeamMembers.Add(new TeamMembers()
                    {
                        Team = teamLoneWolf, Member = demoCreatorUser
                    });
                }

                // line up all hints
                var teams = await _context.Teams.Where((t) => t.Event == Event).ToListAsync();

                var hints = await _context.Hints.Where((h) => h.Puzzle.Event == Event).ToListAsync();

                var puzzles = await _context.Puzzles.Where(p => p.Event == Event).ToListAsync();

                foreach (Team team in teams)
                {
                    foreach (Hint hint in hints)
                    {
                        _context.HintStatePerTeam.Add(new HintStatePerTeam()
                        {
                            Hint = hint, Team = team
                        });
                    }
                    foreach (Puzzle puzzle in puzzles)
                    {
                        _context.PuzzleStatePerTeam.Add(new PuzzleStatePerTeam()
                        {
                            PuzzleID = puzzle.ID, TeamID = team.ID
                        });
                    }
                }

                await _context.SaveChangesAsync();

                //
                // Mark the start puzzle as solved if we were asked to.
                //
                if (StartTheEvent)
                {
                    await PuzzleStateHelper.SetSolveStateAsync(_context, Event, start, null, DateTime.UtcNow);
                }

                transaction.Commit();
            }

            return(RedirectToPage("./Index"));
        }
Пример #7
0
        public async Task <IActionResult> OnPostAsync(int puzzleId)
        {
            if (!this.Event.IsAnswerSubmissionActive)
            {
                return(RedirectToPage("/Submissions/Index", new { puzzleid = puzzleId }));
            }

            await SetupContext(puzzleId);

            if (!ModelState.IsValid)
            {
                return(Page());
            }

            // Don't allow submissions after the answer has been found.
            if (PuzzleState.SolvedTime != null)
            {
                return(Page());
            }

            // Create submission and add it to list
            Submission submission = new Submission
            {
                SubmissionText = SubmissionText,
                TimeSubmitted  = DateTime.UtcNow,
                Puzzle         = PuzzleState.Puzzle,
                Team           = PuzzleState.Team,
                Submitter      = LoggedInUser,
            };

            submission.Response = await _context.Responses.Where(
                r => r.Puzzle.ID == puzzleId &&
                submission.SubmissionText == r.SubmittedText)
                                  .FirstOrDefaultAsync();

            Submissions.Add(submission);

            // Update puzzle state if submission was correct
            if (submission.Response != null && submission.Response.IsSolution)
            {
                await PuzzleStateHelper.SetSolveStateAsync(_context,
                                                           Event,
                                                           submission.Puzzle,
                                                           submission.Team,
                                                           submission.TimeSubmitted);
            }
            else if (submission.Response == null)
            {
                // We also determine if the puzzle should be set to email-only mode.
                if (IsPuzzleSubmissionLimitReached(
                        Event,
                        Submissions,
                        PuzzleState))
                {
                    await PuzzleStateHelper.SetEmailOnlyModeAsync(_context,
                                                                  Event,
                                                                  submission.Puzzle,
                                                                  submission.Team,
                                                                  true);
                }
                else
                {
                    // If the submission was incorrect and not a partial solution,
                    // we will do the lockout computations now.
                    DateTime?lockoutExpiryTime = ComputeLockoutExpiryTime(
                        Event,
                        Submissions,
                        PuzzleState);

                    if (lockoutExpiryTime != null)
                    {
                        await PuzzleStateHelper.SetLockoutExpiryTimeAsync(_context,
                                                                          Event,
                                                                          submission.Puzzle,
                                                                          submission.Team,
                                                                          lockoutExpiryTime);
                    }
                }
            }

            _context.Submissions.Add(submission);
            await _context.SaveChangesAsync();

            return(RedirectToPage(
                       "/Submissions/Index",
                       new { puzzleid = puzzleId }));
        }
Пример #8
0
        /// <summary>
        /// Evaulates player submissions then either saves them to the database or returns an error to the caller
        /// </summary>
        public static async Task <SubmissionResponse> EvaluateSubmission(PuzzleServerContext context, PuzzleUser loggedInUser, Event thisEvent, int puzzleId, string submissionText, bool allowFreeformSharing)
        {
            //Query data needed to process submission
            Team team = await UserEventHelper.GetTeamForPlayer(context, thisEvent, loggedInUser);

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

            PuzzleStatePerTeam puzzleState = await(PuzzleStateHelper
                                                   .GetFullReadOnlyQuery(
                                                       context,
                                                       thisEvent,
                                                       puzzle,
                                                       team))
                                             .FirstAsync();

            List <Puzzle> puzzlesCausingGlobalLockout = await PuzzleStateHelper.PuzzlesCausingGlobalLockout(context, thisEvent, team).ToListAsync();

            // Return early for cases when there's obviously nothing we can do with the submission
            // The submission text is empty
            if (String.IsNullOrWhiteSpace(submissionText))
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.EmptySubmission
                });
            }

            // The puzzle is locked
            if (puzzle == null || puzzleState.UnlockedTime == null)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.PuzzleLocked
                });
            }

            // The user or team isn't known
            if (loggedInUser == null || team == null)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.Unauthorized
                });
            }

            // The event hasn't started yet
            if (DateTime.UtcNow < thisEvent.EventBegin)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.Unauthorized
                });
            }

            // The team is locked out
            if (puzzleState.IsTeamLockedOut || puzzleState.IsEmailOnlyMode)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.TeamLockedOut
                });
            }

            // The puzzle has already been solved
            if (puzzleState.SolvedTime != null)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.AlreadySolved
                });
            }

            // The team is under a global lockout
            if (puzzlesCausingGlobalLockout.Count != 0 && !puzzlesCausingGlobalLockout.Contains(puzzle))
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.TeamLockedOut
                });
            }

            List <SubmissionView> submissionViews = await(from sub in context.Submissions
                                                          join user in context.PuzzleUsers on sub.Submitter equals user
                                                          join r in context.Responses on sub.Response equals r into responses
                                                          from response in responses.DefaultIfEmpty()
                                                          where sub.Team == team &&
                                                          sub.Puzzle == puzzle
                                                          orderby sub.TimeSubmitted
                                                          select new SubmissionView()
            {
                Submission      = sub,
                Response        = response,
                SubmitterName   = user.Name,
                FreeformReponse = sub.FreeformResponse,
                IsFreeform      = puzzle.IsFreeform
            }).ToListAsync();

            List <Submission> submissions = new List <Submission>(submissionViews.Count);

            foreach (SubmissionView submissionView in submissionViews)
            {
                submissions.Add(submissionView.Submission);
            }

            // The submission is a duplicate
            bool duplicateSubmission = (from sub in submissions
                                        where sub.SubmissionText == Response.FormatSubmission(submissionText)
                                        select sub).Any();

            if (duplicateSubmission)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.DuplicateSubmission
                });
            }

            // Create submission and add it to list
            Submission submission = new Submission
            {
                TimeSubmitted        = DateTime.UtcNow,
                Puzzle               = puzzleState.Puzzle,
                Team                 = puzzleState.Team,
                Submitter            = loggedInUser,
                AllowFreeformSharing = allowFreeformSharing
            };

            string submissionTextToCheck = Response.FormatSubmission(submissionText);

            if (puzzle.IsFreeform)
            {
                submission.UnformattedSubmissionText = submissionText;
            }
            else
            {
                submission.SubmissionText = submissionText;
            }

            submission.Response = await context.Responses.Where(
                r => r.Puzzle.ID == puzzleId &&
                submissionTextToCheck == r.SubmittedText)
                                  .FirstOrDefaultAsync();

            submissions.Add(submission);

            // Update puzzle state if submission was correct
            if (submission.Response != null && submission.Response.IsSolution)
            {
                await PuzzleStateHelper.SetSolveStateAsync(context,
                                                           thisEvent,
                                                           submission.Puzzle,
                                                           submission.Team,
                                                           submission.TimeSubmitted);
            }
            else if (!puzzle.IsFreeform && submission.Response == null && thisEvent.IsAnswerSubmissionActive)
            {
                // We also determine if the puzzle should be set to email-only mode.
                if (IsPuzzleSubmissionLimitReached(
                        thisEvent,
                        submissions,
                        puzzleState))
                {
                    await PuzzleStateHelper.SetEmailOnlyModeAsync(context,
                                                                  thisEvent,
                                                                  submission.Puzzle,
                                                                  submission.Team,
                                                                  true);

                    var authors = await context.PuzzleAuthors.Where((pa) => pa.Puzzle == submission.Puzzle).Select((pa) => pa.Author.Email).ToListAsync();

                    MailHelper.Singleton.SendPlaintextBcc(authors,
                                                          $"{thisEvent.Name}: Team {submission.Team.Name} is in email mode for {submission.Puzzle.Name}",
                                                          "");
                }
                else
                {
                    // If the submission was incorrect and not a partial solution,
                    // we will do the lockout computations now.
                    DateTime?lockoutExpiryTime = ComputeLockoutExpiryTime(
                        thisEvent,
                        submissions,
                        puzzleState);

                    if (lockoutExpiryTime != null)
                    {
                        await PuzzleStateHelper.SetLockoutExpiryTimeAsync(context,
                                                                          thisEvent,
                                                                          submission.Puzzle,
                                                                          submission.Team,
                                                                          lockoutExpiryTime);
                    }
                }
            }

            context.Submissions.Add(submission);
            await context.SaveChangesAsync();

            // Send back responses for cases where the database has been updated
            // Correct response
            if (submission.Response != null && submission.Response.IsSolution)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.Correct, CompleteResponse = submission.Response
                });
            }

            // Freeform response
            if (puzzle.IsFreeform)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.Freeform, FreeformResponse = submission.FreeformResponse
                });
            }

            // Partial response
            if (submission.Response != null && !submission.Response.IsSolution)
            {
                return(new SubmissionResponse()
                {
                    ResponseCode = SubmissionResponseCode.Partial, CompleteResponse = submission.Response
                });
            }

            // Default to incorrect
            return(new SubmissionResponse()
            {
                ResponseCode = SubmissionResponseCode.Incorrect
            });
        }