Exemplo n.º 1
0
        public static async Task <List <Puzzle> > GetPuzzles(PuzzleServerContext context, Event Event, PuzzleUser user, EventRole role)
        {
            IQueryable <Puzzle> query;

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

            return(await query.OrderBy(p => p.Group).ThenBy(p => p.OrderInGroup).ThenBy(p => p.Name).ToListAsync());
        }
Exemplo n.º 2
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
            });
        }