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")); } } }
public HackStateMachineHandler(OnlineJudgeContext db, IHubContext <OnlineJudgeHub> hub, ManagementServiceClient mgmt, ContestExecutorFactory cef) { _db = db; _hub = hub; _mgmt = mgmt; _cef = cef; }
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)); }
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)); } }
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); }
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")); } } }
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 })); } }
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")); } }
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)); }
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)); }
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)); }
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)); }
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 }
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)); }
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")); } }
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); }
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")); } }
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")); } }
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")); } }
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); }
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")); } }
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 })); }