Example #1
0
        public async Task <IActionResult> Delete(string id, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(id);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission"));
            }
            else
            {
                var contest = await DB.Contests.SingleOrDefaultAsync(x => x.Id == id, token);

                if (contest == null)
                {
                    return(Result(404, "Contest not found"));
                }
                else if (contest.Begin <= DateTime.UtcNow)
                {
                    return(Result(400, "Cannot remove a started contest."));
                }
                else
                {
                    await DB.UserClaims
                    .Where(x => x.ClaimType == Constants.ContestEditPermission)
                    .Where(x => x.ClaimValue == id)
                    .DeleteAsync(token);

                    return(Result(200, "Delete succeeded"));
                }
            }
        }
Example #2
0
 public HackStateMachineHandler(OnlineJudgeContext db, IHubContext <OnlineJudgeHub> hub, ManagementServiceClient mgmt, ContestExecutorFactory cef)
 {
     _db   = db;
     _hub  = hub;
     _mgmt = mgmt;
     _cef  = cef;
 }
Example #3
0
 private async Task <bool> IsStatusCouldBeHacked(JudgeStatus status, ContestExecutorFactory cef, CancellationToken token)
 {
     if (User.IsSignedIn() && User.Current.Id == status.UserId)
     {
         return(false);
     }
     return(await IsStatusCodeCouldBeViewed(status, cef, token));
 }
Example #4
0
        public async Task <IActionResult> GetContestProblems(string contestId, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var contest = await DB.Contests
                          .Include(x => x.Problems)
                          .SingleOrDefaultAsync(x => x.Id == contestId, token);

            if (contest == null)
            {
                return(Result <IEnumerable <ContestProblemViewModel> >(404, "Contest not found"));
            }

            var ce = cef.Create(contestId);

            if (contest.Begin > DateTime.UtcNow && !ce.HasPermissionToContest())
            {
                return(Result <IEnumerable <ContestProblemViewModel> >(400, "The contest has not started"));
            }
            else if (contest.End >= DateTime.UtcNow && !await IsRegisteredToContest(contestId, token) && !ce.HasPermissionToContest())
            {
                return(Result <IEnumerable <ContestProblemViewModel> >(new ContestProblemViewModel[] { }));
            }
            else
            {
                var userId = User.Current?.Id;
                var locked = await DB.ContestProblemLastStatuses
                             .Where(x => x.ContestId == contestId)
                             .Where(x => x.IsLocked)
                             .Where(x => x.UserId == userId)
                             .Select(x => x.ProblemId)
                             .ToListAsync(token);

                var ret = await DB.ContestProblems
                          .Include(x => x.Problem)
                          .Where(x => x.ContestId == contestId)
                          .OrderBy(x => x.Number)
                          .ThenBy(x => x.Point)
                          .Select(x => new ContestProblemViewModel
                {
                    problemId = x.ProblemId,
                    number    = x.Number,
                    point     = x.Point,
                    isVisible = x.Problem.IsVisible,
                    isLocked  = locked.Contains(x.ProblemId)
                })
                          .ToListAsync(token);

                if (User.IsSignedIn())
                {
                    foreach (var x in ret)
                    {
                        x.status = ce.GenerateProblemStatusText(x.problemId, User.Current.UserName);
                    }
                }

                return(Result <IEnumerable <ContestProblemViewModel> >(ret));
            }
        }
Example #5
0
        public async Task<IActionResult> Get(
            Guid id,
            [FromServices] ManagementServiceClient mgmt,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            var ret = await DB.HackStatuses
                .Include(x => x.Status)
                .Include(x => x.User)
                .SingleOrDefaultAsync(x => x.Id == id, token);

            if (IsGroupRequest() && ret.GroupId != CurrentGroup.Id)
            {
                return Result(400, "No permission");
            }

            if (ret.HackDataBlobId.HasValue)
            {
                ret.HackDataBody = Encoding.UTF8.GetString((await mgmt.GetBlobAsync(ret.HackDataBlobId.Value, token)).Body);
            }

            var username = ret.User.UserName;
            ret.User = null;

            if (ret == null)
            {
                return Result(404, "Hack status is not found");
            }

            if (!string.IsNullOrEmpty(ret.ContestId))
            {
                var ce = cef.Create(ret.ContestId);
                if ((ce.IsContestInProgress(User.Current?.UserName) || ce.IsContestInProgress(username)) && ret.UserId != User.Current?.Id && !IsMasterOrHigher && !ce.HasPermissionToContest(User.Current?.UserName))
                {
                    ce.OnShowHackResult(ret);
                }
            }

            if (User.Current?.Id != ret.UserId 
                && User.Current?.Id != ret.Status.UserId 
                && !await HasPermissionToProblemAsync(ret.Status.ProblemId, token)
                && !(IsGroupRequest() && await HasPermissionToGroupAsync(token)))
            {
                ret.HackDataBody = null;
            }

            return Result(ret);
        }
Example #6
0
        public async Task <IActionResult> PutLock(
            string contestId,
            string problemId,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            if (User.Current == null)
            {
                return(Result(401, "Not authorized"));
            }
            else
            {
                var ce = cef.Create(contestId);

                if (!ce.AllowLockProblem)
                {
                    return(Result(400, "This contest does not accept lock problem."));
                }

                var status = await DB.ContestProblemLastStatuses
                             .Where(x => x.ContestId == contestId)
                             .Where(x => x.UserId == User.Current.Id)
                             .Where(x => x.ProblemId == problemId)
                             .SingleOrDefaultAsync(token);

                if (status == null)
                {
                    return(Result(404, "Please pass the small data of this problem first."));
                }
                else if (status.IsLocked)
                {
                    return(Result(400, "Already locked"));
                }
                else if (!status.IsHackable)
                {
                    return(Result(400, "Please pass the small data of this problem first."));
                }
                else
                {
                    status.IsLocked = true;
                    await DB.SaveChangesAsync(token);

                    return(Result(200, "Put succeeded"));
                }
            }
        }
Example #7
0
        public async Task <IActionResult> GetSession(string id, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var contest = await DB.Contests.SingleOrDefaultAsync(x => x.Id == id, token);

            if (contest == null)
            {
                return(Result(404, "The contest is not found"));
            }

            var ce = cef.Create(contest.Id);

            JoyOI.OnlineJudge.Models.Attendee attendee = null;
            if (User.IsSignedIn())
            {
                attendee = await DB.Attendees.SingleOrDefaultAsync(x => x.ContestId == id && x.UserId == User.Current.Id, token);
            }
            if (attendee == null)
            {
                return(Result(new
                {
                    isRegistered = false,
                    begin = contest.Begin,
                    end = contest.Begin.Add(contest.Duration),
                    isBegan = DateTime.UtcNow > contest.Begin,
                    isEnded = DateTime.UtcNow > contest.Begin.Add(contest.Duration),
                    isStandingsAvailable = ce.IsAvailableToGetStandings() || ce.HasPermissionToContest(),
                    allowLock = false
                }));
            }
            else
            {
                return(Result(new
                {
                    isRegistered = true,
                    isVirtual = attendee.IsVirtual,
                    begin = attendee.IsVirtual ? attendee.RegisterTime : contest.Begin,
                    end = attendee.IsVirtual ? attendee.RegisterTime.Add(contest.Duration) : contest.Begin.Add(contest.Duration),
                    isBegan = DateTime.UtcNow > (attendee.IsVirtual ? attendee.RegisterTime : contest.Begin),
                    isEnded = DateTime.UtcNow > (attendee.IsVirtual ? attendee.RegisterTime.Add(contest.Duration) : contest.Begin.Add(contest.Duration)),
                    isStandingsAvailable = ce.IsAvailableToGetStandings(User.Current.UserName) || ce.HasPermissionToContest(),
                    allowLock = ce.AllowLockProblem
                }));
            }
        }
Example #8
0
        public async Task <IActionResult> Patch(string id, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(id);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No Permission"));
            }
            else
            {
                var contest = await DB.Contests
                              .SingleOrDefaultAsync(x => x.Id == id, token);

                if (contest == null)
                {
                    return(Result(404, "Contest not found"));
                }

                var fields = PatchEntity(contest, RequestBody);
                if (fields.Any(x => x == nameof(contest.IsHighlighted)) && !IsMasterOrHigher)
                {
                    return(Result(403, "You don't have the permission to set the contest highlight."));
                }

                if (fields.Contains(nameof(Contest.Begin)))
                {
                    if (contest.Begin < DateTime.UtcNow)
                    {
                        return(Result(400, "Invalid begin time"));
                    }
                }

                if (fields.Contains(nameof(Contest.Domain)) && !string.IsNullOrWhiteSpace(contest.Domain) && !await DB.Contests.AnyAsync(x => x.Domain == contest.Domain, token))
                {
                    return(Result(400, "The domain is already existed."));
                }

                await DB.SaveChangesAsync(token);

                return(Result(200, "Patch succeeded"));
            }
        }
Example #9
0
        public async Task<IActionResult> GetData(
            Guid id,
            [FromServices] ManagementServiceClient mgmt,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            var hack = await DB.HackStatuses
                .Include(x => x.Status)
                .SingleOrDefaultAsync(x => x.Id == id);

            if (hack == null)
            {
                return Result(404, "Hack status is not found");
            }

            if (!hack.HackDataBlobId.HasValue)
            {
                return Result(404, "The hack data is not found");
            }

            if (!string.IsNullOrEmpty(hack.ContestId))
            {
                var ce = cef.Create(hack.ContestId);
                if (!IsMasterOrHigher && !await HasPermissionToProblemAsync(hack.Status.ProblemId, token) && ce.IsContestInProgress() && User.Current?.Id != hack.UserId)
                {
                    return Result(401, "No permission");
                }
            }
            else
            {
                if (!IsMasterOrHigher && !await HasPermissionToProblemAsync(hack.Status.ProblemId, token) && User.Current?.Id != hack.UserId)
                {
                    return Result(401, "No permission");
                }
            }

            var blob = await mgmt.GetBlobAsync(hack.HackDataBlobId.Value, token);
            return Result(Encoding.UTF8.GetString(blob.Body));
        }
Example #10
0
        private async Task <bool> IsStatusCodeCouldBeViewed(JudgeStatus status, ContestExecutorFactory cef, CancellationToken token)
        {
            if (!User.IsSignedIn() || status.IsSelfTest)
            {
                return(false);
            }

            if (!string.IsNullOrEmpty(status.ContestId))
            {
                var ce = cef.Create(status.ContestId);
                if (ce.IsContestInProgress(status.User.UserName) || ce.IsContestInProgress(User.Current?.UserName))
                {
                    return(ce.IsStatusHackable(status));
                }
            }

            if (Constants.HackInvalidResults.Contains(status.Result))
            {
                return(false);
            }

            return(await DB.JudgeStatuses.AnyAsync(x => x.UserId == User.Current.Id && x.ProblemId == status.ProblemId && string.IsNullOrEmpty(x.ContestId) && x.Result == JudgeResult.Accepted, token));
        }
Example #11
0
        public async Task <IActionResult> Get(Guid id, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ret = await DB.JudgeStatuses
                      .Include(x => x.User)
                      .Include(x => x.SubStatuses)
                      .Include(x => x.Problem)
                      .SingleOrDefaultAsync(x => x.Id == id, token);

            if (IsGroupRequest() && ret.GroupId != CurrentGroup.Id)
            {
                if (string.IsNullOrEmpty(ret.ContestId))
                {
                    return(Result(400, "No permission"));
                }
                else if (!await DB.GroupContestReferences.AnyAsync(x => x.ContestId == ret.ContestId && x.GroupId == CurrentGroup.Id, token))
                {
                    return(Result(400, "No permission"));
                }
            }

            var problem  = ret.Problem;
            var username = ret.User.UserName;

            if (!string.IsNullOrWhiteSpace(ret.ContestId))
            {
                var contest = DB.Contests
                              .Single(x => x.Id == ret.ContestId);
                if (!await HasPermissionToContestAsync(ret.ContestId) && !await HasPermissionToProblemAsync(ret.ProblemId))
                {
                    var ce = cef.Create(contest.Id);
                    if (ce.IsContestInProgress(User.Current?.UserName) || ce.IsContestInProgress(username))
                    {
                        ce.OnShowJudgeResult(ret);
                    }
                }
            }
            else
            {
                var hasPermissionToProblem = await HasPermissionToProblemAsync(problem.Id, token);

                if (!problem.IsVisible && !hasPermissionToProblem && !IsGroupRequest() && !await HasPermissionToGroupAsync(token))
                {
                    return(Result <JudgeStatus>(403, "No permission"));
                }
            }

            if (User.Current != null && User.Current.Id == ret.UserId)
            {
                HasOwnership = true;
            }

            ret.IsHackable = await IsStatusCouldBeHacked(ret, cef, token);

            if (!HasOwnership &&
                !await HasPermissionToProblemAsync(problem.Id, token) &&
                !await HasPermissionToContestAsync(ret.ContestId, token) &&
                !await IsStatusCodeCouldBeViewed(ret, cef, token) &&
                !(IsGroupRequest() && await HasPermissionToGroupAsync(token)))
            {
                ret.Code = null;
            }

            ret.SubStatuses  = ret.SubStatuses.OrderBy(x => x.SubId).ToList();
            ret.IsRejudgable = !(!User.IsSignedIn() || ret.UserId != User.Current.Id && !IsMasterOrHigher && !await HasPermissionToProblemAsync(ret.ProblemId) && !await HasPermissionToContestAsync(ret.ContestId, token) && !await HasPermissionToSpecifiedGroupAsync(ret.GroupId, token));

            return(Result(ret));
        }
Example #12
0
        public async Task <IActionResult> Get(
            string problemId,
            JudgeResult?status,
            string userId,
            string contestId,
            string language,
            int?page,
            DateTime?begin,
            DateTime?end,
            string judgeIds,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            IQueryable <JudgeStatus> ret = DB.JudgeStatuses;

            if (!string.IsNullOrWhiteSpace(problemId))
            {
                ret = ret.Where(x => x.ProblemId == problemId);
            }

            if (status.HasValue)
            {
                ret = ret.Where(x => x.Result == status.Value);
            }

            if (!string.IsNullOrWhiteSpace(userId))
            {
                ret = ret.Where(x => x.User.UserName == userId);
            }

            if (!string.IsNullOrWhiteSpace(contestId))
            {
                ret = ret.Where(x => x.ContestId == contestId);
            }

            if (!string.IsNullOrWhiteSpace(language))
            {
                ret = ret.Where(x => x.Language == language);
            }

            if (begin.HasValue)
            {
                ret = ret.Where(x => begin.Value <= x.CreatedTime);
            }

            if (end.HasValue)
            {
                ret = ret.Where(x => x.CreatedTime <= end.Value);
            }

            if (!string.IsNullOrWhiteSpace(judgeIds))
            {
                var ids = judgeIds.Split(',').Select(x => Guid.Parse(x.Trim()));
                ret = ret.Where(x => ids.Contains(x.Id));
            }

            if (IsGroupRequest())
            {
                ret = ret.Where(x => x.GroupId == CurrentGroup.Id);
            }

            var result = await DoPaging(ret.OrderByDescending(x => x.CreatedTime), page ?? 1, 20, token);

            if (!IsMasterOrHigher && result.data.result.Any(x => !string.IsNullOrWhiteSpace(x.ContestId)))
            {
                var pendingRemove = new ConcurrentBag <JudgeStatus>();
                foreach (var x in result.data.result.Where(x => !string.IsNullOrWhiteSpace(x.ContestId)))
                {
                    var ce = cef.Create(x.ContestId);
                    var submittorUsername   = DB.Users.Single(y => y.Id == x.UserId).UserName;
                    var isContestInProgress = ce.IsContestInProgress(User.Current?.UserName) || ce.IsContestInProgress(submittorUsername);
                    if (isContestInProgress && !await HasPermissionToContestAsync(x.ContestId, token) && !await HasPermissionToProblemAsync(x.ProblemId, token))
                    {
                        if (ce.AllowFilterByJudgeResult || !status.HasValue)
                        {
                            ce.OnShowJudgeResult(x);
                        }
                        else
                        {
                            pendingRemove.Add(x);
                        }
                    }
                    x.Contest = null;
                }
                foreach (var x in pendingRemove)
                {
                    (result.data.result as List <JudgeStatus>).Remove(x);
                }
            }

            FilterResult(result.data.result);
            return(Json(result));
        }
Example #13
0
        public async Task <IActionResult> Put(
            [FromServices] IConfiguration Config,
            [FromServices] IServiceScopeFactory scopeFactory,
            [FromServices] StateMachineAwaiter awaiter,
            [FromServices] ManagementServiceClient MgmtSvc,
            [FromServices] IHubContext <OnlineJudgeHub> hub,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            var request = JsonConvert.DeserializeObject <JudgeRequest>(RequestBody);
            var problem = await DB.Problems
                          .Include(x => x.TestCases)
                          .SingleOrDefaultAsync(x => x.Id == request.problemId, token);

            if (problem == null)
            {
                return(Result(400, "The problem is not exist."));
            }

            if (!problem.IsVisible && string.IsNullOrWhiteSpace(request.contestId) && !await HasPermissionToProblemAsync(problem.Id, token))
            {
                return(Result(403, "You have no permission to the problem."));
            }

            if (IsGroupRequest() && !await IsGroupMemberAsync(token))
            {
                return(Result(401, "You are not a member of this group."));
            }

            if (!Constants.SupportedLanguages.Contains(request.language))
            {
                return(Result(400, "The language has not been supported."));
            }
            if (string.IsNullOrEmpty(request.code))
            {
                return(Result(400, "Code could not be empty."));
            }

            if (!string.IsNullOrEmpty(request.contestId))
            {
                var ce = cef.Create(request.contestId);

                if (!ce.IsContestInProgress(User.Current?.UserName))
                {
                    return(Result(400, "The contest is inactive."));
                }

                if (request.isSelfTest)
                {
                    return(Result(400, "You could not do a self test during the contest is in progress."));
                }

                if (await DB.ContestProblemLastStatuses.AnyAsync(x => x.IsLocked && x.ContestId == request.contestId && User.Current.Id == x.UserId && x.ProblemId == request.problemId, token))
                {
                    return(Result(400, "You have locked this problem."));
                }
            }

            if (!Constants.SupportedLanguages.Contains(request.language) && !Constants.UnsupportedLanguages.Contains(request.language) && problem.Source == ProblemSource.Local)
            {
                return(Result(400, "The programming language which you selected was not supported"));
            }

            if (request.isSelfTest && request.data.Count() == 0)
            {
                return(Result(400, "The self testing data has not been found"));
            }

            if (problem.Source != ProblemSource.Local && request.isSelfTest)
            {
                return(Result(400, "You could not use self data to test with a remote problem."));
            }

            if (IsGroupRequest() && !await DB.GroupProblems.AnyAsync(x => x.ProblemId == problem.Id && x.GroupId == CurrentGroup.Id) && string.IsNullOrEmpty(request.contestId))
            {
                return(Result(404, "The problem does not exist."));
            }

            #region Local Judge
            if (problem.Source == ProblemSource.Local)
            {
                var blobs = new ConcurrentDictionary <int, BlobInfo[]>();
                blobs.TryAdd(-1, new[] { new BlobInfo
                                         {
                                             Id   = await MgmtSvc.PutBlobAsync("Main" + Constants.GetSourceExtension(request.language), Encoding.UTF8.GetBytes(request.code)),
                                             Name = "Main" + Constants.GetSourceExtension(request.language),
                                             Tag  = "Problem=" + problem.Id
                                         } });
                blobs.TryAdd(-2, new[] { new BlobInfo
                                         {
                                             Id = await MgmtSvc.PutBlobAsync("limit.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
                        {
                            UserTime     = problem.TimeLimitationPerCaseInMs,
                            PhysicalTime = problem.TimeLimitationPerCaseInMs * 4,
                            Memory       = problem.MemoryLimitationPerCaseInByte
                        }))),
                                             Name = "limit.json",
                                             Tag  = "Problem=" + problem.Id
                                         } });
                if (!problem.ValidatorBlobId.HasValue)
                {
                    blobs.TryAdd(-3, new[]
                    {
                        new BlobInfo
                        {
                            Id   = Guid.Parse(Config["JoyOI:StandardValidatorBlobId"]),
                            Name = "Validator.out"
                        }
                    });
                }
                else
                {
                    blobs.TryAdd(-3, new[]
                    {
                        new BlobInfo
                        {
                            Id   = problem.ValidatorBlobId.Value,
                            Name = "Validator" + Constants.GetBinaryExtension(problem.ValidatorLanguage)
                        }
                    });
                }

                List <TestCase> testCases = null;
                if (request.isSelfTest)
                {
                    Parallel.For(0, request.data.Count(), i =>
                    {
                        // Uploading custom data
                        var inputId  = MgmtSvc.PutBlobAsync($"input_{ i }.txt", Encoding.UTF8.GetBytes(request.data.ElementAt(i).input), token).Result;
                        var outputId = MgmtSvc.PutBlobAsync($"output_{ i }.txt", Encoding.UTF8.GetBytes(request.data.ElementAt(i).output), token).Result;
                        blobs.TryAdd(i, new[] {
                            new BlobInfo {
                                Id = inputId, Name = $"input_{ i }.txt", Tag = i.ToString()
                            },
                            new BlobInfo {
                                Id = outputId, Name = $"output_{ i }.txt", Tag = i.ToString()
                            }
                        });
                    });
                }
                else
                {
                    testCases = await DB.TestCases
                                .Where(x => x.ProblemId == problem.Id && (x.Type == TestCaseType.Small || x.Type == TestCaseType.Large || x.Type == TestCaseType.Hack))
                                .ToListAsync(token);

                    if (testCases.Count == 0)
                    {
                        return(Result(400, "No test case found."));
                    }

                    for (var i = 0; i < testCases.Count; i++)
                    {
                        blobs.TryAdd(i, new[] {
                            new BlobInfo {
                                Id = testCases[i].InputBlobId, Name = $"input_{ i }.txt", Tag = i.ToString()
                            },
                            new BlobInfo {
                                Id = testCases[i].OutputBlobId, Name = $"output_{ i }.txt", Tag = i.ToString()
                            }
                        });
                    }
                }

                var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("JudgeStateMachine", Config["ManagementService:CallBack"], blobs.SelectMany(x => x.Value), await CalculatePriorityAsync(), token);

                var substatuses = blobs
                                  .Where(x => x.Key >= 0)
                                  .Select(x => new SubJudgeStatus
                {
                    SubId        = x.Key,
                    Result       = JudgeResult.Pending,
                    InputBlobId  = x.Value.Single(y => y.Name.StartsWith("input_")).Id,
                    OutputBlobId = x.Value.Single(y => y.Name.StartsWith("output_")).Id,
                    TestCaseId   = testCases != null ? (Guid?)testCases[x.Key].Id : null
                })
                                  .ToList();

                var status = new JudgeStatus
                {
                    Code                   = request.code,
                    Language               = request.language,
                    Result                 = JudgeResult.Pending,
                    CreatedTime            = DateTime.UtcNow,
                    ContestId              = request.contestId,
                    SubStatuses            = substatuses,
                    ProblemId              = problem.Id,
                    UserId                 = User.Current.Id,
                    IsSelfTest             = request.isSelfTest,
                    RelatedStateMachineIds = new List <JudgeStatusStateMachine>
                    {
                        new JudgeStatusStateMachine
                        {
                            StateMachine = new StateMachine
                            {
                                CreatedTime = DateTime.UtcNow,
                                Name        = "JudgeStateMachine",
                                Id          = stateMachineId
                            },
                            StateMachineId = stateMachineId
                        }
                    },
                };

                if (IsGroupRequest())
                {
                    status.GroupId = CurrentGroup.Id;
                }

                DB.JudgeStatuses.Add(status);
                await DB.SaveChangesAsync(token);

                hub.Clients.All.InvokeAsync("ItemUpdated", "judge", status.Id);

                // For debugging
                if (Config["ManagementService:Mode"] == "Polling")
                {
                    Task.Factory.StartNew(async() =>
                    {
                        using (var scope = scopeFactory.CreateScope())
                            using (var db = scope.ServiceProvider.GetService <OnlineJudgeContext>())
                            {
                                try
                                {
                                    await awaiter.GetStateMachineResultAsync(stateMachineId);
                                    var handler = scope.ServiceProvider.GetService <JudgeStateMachineHandler>();
                                    await handler.HandleJudgeResultAsync(stateMachineId, default(CancellationToken));
                                }
                                catch (Exception ex)
                                {
                                    Console.Error.WriteLine(ex);
                                }
                            }
                    });
                }
                return(Result(status.Id));
            }
            #endregion
            #region Bzoj, LeetCode, CodeVS
            else if (problem.Source == ProblemSource.Bzoj || problem.Source == ProblemSource.LeetCode || problem.Source == ProblemSource.CodeVS)
            {
                var metadata = new
                {
                    Source    = problem.Source.ToString(),
                    Language  = request.language,
                    Code      = request.code,
                    ProblemId = problem.Id.Replace(problem.Source.ToString().ToLower() + "-", "")
                };

                var metadataBlob = new BlobInfo
                {
                    Id   = await MgmtSvc.PutBlobAsync("metadata.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(metadata)), token),
                    Name = "metadata.json",
                    Tag  = "Problem=" + problem.Id
                };

                var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("VirtualJudgeStateMachine", Config["ManagementService:Callback"], new[] { metadataBlob }, await CalculatePriorityAsync(), token);

                var status = new JudgeStatus
                {
                    Code                   = request.code,
                    ContestId              = request.contestId,
                    Language               = request.language,
                    ProblemId              = problem.Id,
                    IsSelfTest             = false,
                    UserId                 = User.Current.Id,
                    Result                 = JudgeResult.Pending,
                    RelatedStateMachineIds = new List <JudgeStatusStateMachine>
                    {
                        new JudgeStatusStateMachine {
                            StateMachine = new StateMachine
                            {
                                CreatedTime = DateTime.UtcNow,
                                Name        = "JudgeStateMachine",
                                Id          = stateMachineId
                            },
                            StateMachineId = stateMachineId
                        }
                    }
                };

                if (IsGroupRequest())
                {
                    status.GroupId = CurrentGroup.Id;
                }

                DB.JudgeStatuses.Add(status);
                await DB.SaveChangesAsync(token);

                // For debugging
                if (Config["ManagementService:Mode"] == "Polling")
                {
                    Task.Factory.StartNew(async() =>
                    {
                        using (var scope = scopeFactory.CreateScope())
                        {
                            try
                            {
                                await awaiter.GetStateMachineResultAsync(stateMachineId);
                                var handler = scope.ServiceProvider.GetService <JudgeStateMachineHandler>();
                                await handler.HandleJudgeResultAsync(stateMachineId, default(CancellationToken));
                            }
                            catch (Exception ex)
                            {
                                Console.Error.WriteLine(ex);
                            }
                        }
                    });
                }

                hub.Clients.All.InvokeAsync("ItemUpdated", "judge", status.Id);

                return(Result(status.Id));
            }
            #endregion
            #region Others
            else
            {
                throw new NotSupportedException(problem.Source.ToString() + " has not been supported yet.");
            }
            #endregion
        }
Example #14
0
        public async Task <IActionResult> GetStandings(string contestId, Guid userId, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(contestId);

            if (!ce.IsAvailableToGetStandings(User.Current?.UserName) && !ce.HasPermissionToContest())
            {
                return(Result(401, "No permission"));
            }

            var username = (await DB.Users.SingleOrDefaultAsync(x => x.Id == userId)).UserName;
            var ret      = await ce.GenerateSingleStandingsAsync(username, token);

            if (ret == null)
            {
                return(Result(404, "Standings of this user is not found"));
            }
            return(Result(ret));
        }
Example #15
0
        public async Task <IActionResult> DeleteClaim(string username, string contestId, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(contestId);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission"));
            }

            var user = await User.Manager.FindByNameAsync(username);

            if (!await DB.UserClaims.AnyAsync(x => x.ClaimValue == contestId && x.ClaimType == Constants.ContestEditPermission && x.UserId == user.Id, token))
            {
                return(Result(404, "Claim not found"));
            }
            else if (username == User.Current.UserName)
            {
                return(Result(400, "Cannot remove yourself"));
            }
            else
            {
                await DB.UserClaims
                .Where(x => x.ClaimValue == contestId && x.ClaimType == Constants.ContestEditPermission && x.UserId == user.Id)
                .DeleteAsync(token);

                return(Result(200, "Delete succeeded"));
            }
        }
Example #16
0
        public async Task<IActionResult> Put(
            [FromServices] ContestExecutorFactory cef, 
            [FromServices] ManagementServiceClient mgmt,
            [FromServices] IHubContext<OnlineJudgeHub> hub,
            CancellationToken token)
        {
            var request = JsonConvert.DeserializeObject<HackRequest>(RequestBody);

            if (!User.IsSignedIn())
            {
                return Result(403, "Please login first.");
            }

            var judge = await DB.JudgeStatuses
                .Include(x => x.Problem)
                .SingleOrDefaultAsync(x => x.Id == request.JudgeStatusId, token);

            if (judge == null)
            {
                return Result(404, "The judge status is not found");
            }

            if (!judge.BinaryBlobId.HasValue)
            {
                return Result(400, "The lagency status could not be hacked.");
            }

            if (judge.UserId == User.Current.Id)
            {
                return Result(400, "You cannot hack yourself.");
            }
            
            if (IsGroupRequest() && !await IsGroupMemberAsync(token))
            {
                return Result(401, "You are not a member of this group.");
            }

            if (!string.IsNullOrEmpty(request.ContestId))
            {
                var ce = cef.Create(request.ContestId);

                if (!ce.IsStatusHackable(judge) || !ce.IsContestInProgress())
                {
                    return Result(400, "You cannot hack this status");
                }

                if (await DB.HackStatuses.AnyAsync(x => x.UserId == User.Current.Id && x.JudgeStatusId == request.JudgeStatusId && x.Result == HackResult.Succeeded && x.ContestId == request.ContestId, token))
                {
                    return Result(400, "You have already hacked this status.");
                }
            }

            // Upload hack data to management service
            if (request.IsBase64)
            {
                request.Data = request.Data.Substring(request.Data.IndexOf("base64,") + "base64,".Length);
            }
            var blobId = await mgmt.PutBlobAsync("data.txt", request.IsBase64 ? Convert.FromBase64String(request.Data) : Encoding.UTF8.GetBytes(request.Data), token);

            var hack = new HackStatus
            {
                ContestId = request.ContestId,
                JudgeStatusId = judge.Id,
                HackDataBlobId = blobId,
                Result = HackResult.Pending,
                Time = DateTime.UtcNow,
                UserId = User.Current.Id,
                HackeeResult = JudgeResult.Pending
            };
            DB.HackStatuses.Add(hack);
            await DB.SaveChangesAsync(token);

            var blobs = new List<BlobInfo>(10);

            // Put the limit.json into blob collection
            blobs.Add(new BlobInfo
            {
                Id = await mgmt.PutBlobAsync("limit.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
                {
                    UserTime = judge.Problem.TimeLimitationPerCaseInMs,
                    PhysicalTime = judge.Problem.TimeLimitationPerCaseInMs * 4,
                    Memory = judge.Problem.MemoryLimitationPerCaseInByte
                }))),
                Name = "limit.json",
                Tag = "Problem=" + judge.ProblemId
            });

            // Put the data into blob collection
            blobs.Add(new BlobInfo(blobId, "data.txt"));

            // Put the hackee program into blob collection
            blobs.Add(new BlobInfo(judge.BinaryBlobId.Value, "Hackee" + Constants.GetBinaryExtension(judge.Language), judge.Id.ToString()));

            // Put range validator program into blob collection
            if (judge.Problem.RangeBlobId.HasValue && string.IsNullOrEmpty(judge.Problem.RangeError))
            {
                blobs.Add(new BlobInfo(judge.Problem.RangeBlobId.Value, "Range" + Constants.GetBinaryExtension(judge.Problem.RangeLanguage)));
            }

            // Put standard program into blob collection
            if (judge.Problem.StandardBlobId.HasValue && string.IsNullOrEmpty(judge.Problem.StandardError))
            {
                blobs.Add(new BlobInfo(judge.Problem.StandardBlobId.Value, "Standard" + Constants.GetBinaryExtension(judge.Problem.StandardLanguage)));
            }
            else
            {
                // Get 3 accepted programs instead of standard program
                var statuses = await DB.JudgeStatuses
                    .Where(x => x.Result == JudgeResult.Accepted && x.ProblemId == judge.ProblemId && x.BinaryBlobId.HasValue && x.Id != judge.Id)
                    .OrderBy(x => x.TimeUsedInMs)
                    .ThenBy(x => x.MemoryUsedInByte)
                    .Take(3)
                    .ToListAsync(token);

                if (statuses.Count == 0)
                {
                    return Result(400, "Missing standard program, this status could not be hacked");
                }

                var standards = statuses.Select(x => new BlobInfo(x.BinaryBlobId.Value, "Standard-" + x.Id.ToString().Substring(0,8) + Constants.GetBinaryExtension(x.Language), x.Id.ToString()));
                blobs.AddRange(standards);
            }

            // Put validator into blob collection
            if (judge.Problem.ValidatorBlobId.HasValue)
            {
                blobs.Add(new BlobInfo(judge.Problem.ValidatorBlobId.Value, "Validator" + Constants.GetBinaryExtension(judge.Problem.ValidatorLanguage)));
            }
            else
            {
                blobs.Add(new BlobInfo(Guid.Parse(Configuration["JoyOI:StandardValidatorBlobId"]), "Validator.out"));
            }

            // Start hack state machine
            var stateMachineId = await mgmt.PutStateMachineInstanceAsync("HackStateMachine", Configuration["ManagementService:CallBack"], blobs.ToArray(), 1, token);
            var stateMachine = new StateMachine { CreatedTime = DateTime.Now, Name = "HackStateMachine", Id = stateMachineId };
            DB.StateMachines.Add(stateMachine);
            hack.RelatedStateMachineIds = new List<HackStatusStateMachine>();
            hack.RelatedStateMachineIds.Add(new HackStatusStateMachine { StateMachineId = stateMachine.Id, StatusId = judge.Id });
            await DB.SaveChangesAsync(token);

            hub.Clients.All.InvokeAsync("ItemUpdated", "hack", hack.Id);

            return Result(hack.Id);
        }
Example #17
0
        public async Task <IActionResult> DeleteContestProblem(string contestId, string problemId, [FromServices] ContestExecutorFactory cef, [FromBody] string value, CancellationToken token)
        {
            var contestProblem = await DB.ContestProblems
                                 .SingleOrDefaultAsync(x => x.ContestId == contestId && x.ProblemId == problemId, token);

            if (contestProblem == null)
            {
                return(Result(404, "Contest problem not found"));
            }

            var ce = cef.Create(contestId);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission to this contest"));
            }
            else
            {
                await DB.JudgeStatuses
                .Where(x => x.ContestId == contestId)
                .Where(x => x.ProblemId == problemId)
                .DeleteAsync(token);

                await DB.ContestProblems
                .Where(x => x.ProblemId == problemId)
                .Where(x => x.ContestId == contestId)
                .DeleteAsync(token);

                return(Result(200, "Delete succeeded"));
            }
        }
Example #18
0
        public async Task <IActionResult> PatchContestProblem(string contestId, string problemId, [FromServices] ContestExecutorFactory cef, [FromBody] string value, CancellationToken token)
        {
            var contestProblem = await DB.ContestProblems
                                 .SingleOrDefaultAsync(x => x.ContestId == contestId && x.ProblemId == problemId, token);

            if (contestProblem == null)
            {
                return(Result(404, "Contest problem not found"));
            }

            var ce = cef.Create(contestId);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission to this contest"));
            }
            else
            {
                var fields = PatchEntity(contestProblem, value);
                if (fields.Contains(nameof(ContestProblem.Number)))
                {
                    if (await DB.ContestProblems.AnyAsync(x => x.ContestId == contestId && x.Number == contestProblem.Number))
                    {
                        return(Result(400, "The problem number is already existed."));
                    }
                }
                await DB.SaveChangesAsync(token);

                return(Result(200, "Patch succeeded"));
            }
        }
Example #19
0
        public async Task <IActionResult> PutContestProblem(string contestId, string problemId, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var contest = await DB.Contests
                          .SingleOrDefaultAsync(x => x.Id == contestId, token);

            var problem = await DB.Problems
                          .SingleOrDefaultAsync(x => x.Id == problemId, token);

            var problemCount = await DB.ContestProblems.CountAsync(x => x.ContestId == contestId);

            if (contest == null)
            {
                return(Result(404, "Contest not found"));
            }
            else if (problem == null)
            {
                return(Result(404, "Problem not found"));
            }

            var ce = cef.Create(contestId);

            if (problemCount >= 26)
            {
                return(Result(400, "The contest problem count cannot be greater than 26"));
            }
            else if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission to this contest"));
            }
            else if (!problem.IsVisible && !await HasPermissionToProblemAsync(contestId, token))
            {
                return(Result(401, "No permission to this problem"));
            }
            else if (await DB.ContestProblems.AnyAsync(x => x.ContestId == contestId && x.ProblemId == problemId, token))
            {
                return(Result(400, "The problem has been already added into this contest"));
            }
            else
            {
                var contestProblem = PutEntity <ContestProblem>(RequestBody);
                contestProblem.Entity.ContestId = contestId;
                contestProblem.Entity.ProblemId = problemId;

                if (contestProblem.Fields.Contains("Number"))
                {
                    if (await DB.ContestProblems.AnyAsync(x => x.ContestId == contestId && x.Number == contestProblem.Entity.Number, token))
                    {
                        return(Result(400, "The problem number is already existed."));
                    }
                }
                else
                {
                    contestProblem.Entity.Number = ProblemNumberString[problemCount].ToString();
                }

                DB.ContestProblems.Add(contestProblem.Entity);
                await DB.SaveChangesAsync(token);

                return(Result(200, "Put succeeded"));
            }
        }
Example #20
0
        public async Task<IActionResult> Get(
            HackResult? hackStatus,
            JudgeResult? judgeStatus,
            string problemId, 
            string hacker,
            string hackee,
            DateTime? begin, 
            DateTime? end, 
            string contestId, 
            int? page,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            IQueryable<HackStatus> ret = DB.HackStatuses
                .Include(x =>x.Status);

            if (!page.HasValue)
            {
                page = 1;
            }

            if (hackStatus.HasValue)
            {
                ret = ret.Where(x => x.Result == hackStatus.Value);
            }

            if (judgeStatus.HasValue)
            {
                ret = ret.Where(x => x.HackeeResult == judgeStatus.Value);
            }

            if (!string.IsNullOrEmpty(hacker))
            {
                ret = ret.Where(x => x.User.UserName == hacker);
            }
            
            if (!string.IsNullOrEmpty(hackee))
            {
                ret = ret.Where(x => x.Status.User.UserName == hackee);
            }

            if (begin.HasValue)
            {
                ret = ret.Where(x => x.Time >= begin.Value);
            }

            if (end.HasValue)
            {
                ret = ret.Where(x => x.Time <= end.Value);
            }

            if (!string.IsNullOrEmpty(contestId))
            {
                ret = ret.Where(x => x.ContestId == contestId);
            }

            if (!string.IsNullOrEmpty(problemId))
            {
                ret = ret.Where(x => x.Status.ProblemId == problemId);
            }

            if (IsGroupRequest())
            {
                ret = ret.Where(x => x.GroupId == CurrentGroup.Id);
            }

            return await Paged(ret.OrderByDescending(x => x.Time)
                .Select(x => new HackViewModel
                {
                    Id = x.Id,
                    problemId = x.Status.ProblemId,
                    HackerId = x.UserId,
                    HackeeId = x.Status.UserId,
                    HackResult = x.Result,
                    JudgeResult = x.HackeeResult,
                    Time = x.Time,
                    TimeUsedInMs = x.TimeUsedInMs,
                    MemoryUsedInByte = x.MemoryUsedInByte,
                    JudgeStatusId = x.JudgeStatusId
                }), 
                page.Value, 
                20, 
                token);
        }
Example #21
0
        public async Task <IActionResult> PutClaims(string contestId, string username, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(contestId);

            if (!ce.HasPermissionToContest())
            {
                return(Result(401, "No permission"));
            }
            var user = await User.Manager.FindByNameAsync(username);

            if (await DB.UserClaims.AnyAsync(x => x.ClaimValue == contestId && x.ClaimType == Constants.ContestEditPermission && x.UserId == user.Id, token))
            {
                return(Result(400, "Already exists"));
            }
            else
            {
                if (user == null)
                {
                    return(Result(404, "User is not found"));
                }
                else if (!(IsGroupRequest() && await HasPermissionToGroupAsync(token) && await DB.GroupMembers.AnyAsync(x => x.GroupId == CurrentGroup.Id && x.UserId == user.Id && x.Status == GroupMemberStatus.Approved)) && !IsMasterOrHigher)
                {
                    return(Result(401, user.UserName + " is not a member of your group."));
                }
                else if (await DB.UserClaims.Where(x => x.ClaimType == Constants.ContestEditPermission && x.ClaimValue == contestId).CountAsync(token) >= 5)
                {
                    return(Result(400, "Max 5 referees in a contest."));
                }
                DB.UserClaims.Add(new IdentityUserClaim <Guid>
                {
                    ClaimType  = Constants.ContestEditPermission,
                    UserId     = user.Id,
                    ClaimValue = contestId
                });
                await DB.SaveChangesAsync(token);

                return(Result(200, "Succeeded"));
            }
        }
Example #22
0
        public async Task <IActionResult> GetStandings(string contestId, bool?includingVirtual, [FromServices] ContestExecutorFactory cef, CancellationToken token)
        {
            var ce = cef.Create(contestId);

            if (!ce.IsAvailableToGetStandings(User.Current?.UserName) && !ce.HasPermissionToContest())
            {
                return(Result(401, "No permission"));
            }

            var contest = await DB.Contests.SingleOrDefaultAsync(x => x.Id == contestId, token);

            if (contest == null)
            {
                return(Result(404, "Not found"));
            }

            if (!includingVirtual.HasValue)
            {
                includingVirtual = true;
            }

            var problems = DB.ContestProblems
                           .Where(x => x.ContestId == contestId)
                           .OrderBy(x => x.Number)
                           .Select(x => new ContestExecutor.ProblemSummary
            {
                number = x.Number,
                point  = x.Point,
                id     = x.ProblemId
            })
                           .ToList();

            var attendees = await ce.GenerateFullStandingsAsync(includingVirtual.Value, token);

            return(Result(new Standings {
                id = contestId,
                title = contest.Title,
                columnDefinations = ce.PointColumnDefinations,
                problems = problems,
                attendees = attendees
            }));
        }