public async Task <ActionResult <Scoreboard> > OnGet(int cid, bool @public, [FromServices] ITeamStore store) { if (!Contest.StartTime.HasValue) { return(null); } var scb = await store.LoadScoreboardAsync(cid); var affs = await store.ListAffiliationAsync(cid); var orgs = await store.ListCategoryAsync(cid, false); var probs = Problems; var board = new FullBoardViewModel { RankCache = scb.Data.Values, UpdateTime = scb.RefreshTime, Problems = probs, IsPublic = @public, Categories = orgs, Contest = Contest, Affiliations = affs, }; var opt = new int[probs.Length]; for (int i = 0; i < probs.Length; i++) { opt[i] = i; } var go = board .SelectMany(a => a) .Select(t => new Scoreboard.Row { rank = t.Rank.Value, team_id = $"{t.TeamId}", score = new Scoreboard.Score(t.Points, t.Penalty), problems = opt.Select(i => MakeProblem(t.Problems[i], probs[i])) }); return(new Scoreboard { time = Contest.StartTime.Value, contest_time = DateTimeOffset.Now - Contest.StartTime.Value, event_id = $"{MaxEventId}", state = new State(Contest), rows = go, }); }
public async Task <ActionResult <Scoreboard> > OnGet( [FromRoute] int cid, [FromQuery] bool @public) { bool isXcpc = Contest.RankingStrategy == CcsDefaults.RuleXCPC; bool isOi = Contest.RankingStrategy == CcsDefaults.RuleIOI; if (!Contest.StartTime.HasValue || Contest.Feature == CcsDefaults.KindProblemset || (!isXcpc && !isOi)) { return(null); } var scb = await Context.GetScoreboardAsync(); var board = new FullBoardViewModel(scb, @public, !@public); var probs = board.Problems; var go = board .SelectMany(a => a) .Select(t => new Scoreboard.Row { Rank = t.Rank.Value, TeamId = $"{t.TeamId}", Score = new Scoreboard.Score(isXcpc, t.Points, t.Penalty, t.LastAc), Problems = Enumerable.Range(0, probs.Count).Select(i => MakeProblem(t.Problems[i], probs[i], isXcpc)), }); var maxEvent = await Context.GetMaxEventAsync(); maxEvent ??= new Xylab.Contesting.Entities.Event { EventTime = DateTimeOffset.Now }; return(new Scoreboard { Time = AbstractEvent.TrimToMilliseconds(maxEvent.EventTime), ContestTime = maxEvent.EventTime - Contest.StartTime.Value, EventId = $"{maxEvent.Id}", State = new State(Contest), Rows = go, }); }
public async Task <IActionResult> ScoreboardXlsx( [FromQuery] int[] affiliations = null, [FromQuery] int[] categories = null) { if (Contest.RankingStrategy == CcsDefaults.RuleCodeforces) { return(StatusCode(501)); } if (affiliations != null && affiliations.Length == 0) { affiliations = null; } if (categories != null && categories.Length == 0) { categories = null; } if (!Contest.StartTime.HasValue) { return(BadRequest()); } var scb = await Context.GetScoreboardAsync(); var board = new FullBoardViewModel(scb, false) { FilteredAffiliations = affiliations?.ToHashSet(), FilteredCategories = categories?.ToHashSet(), }; using var workbook = OpenXmlScoreboard.Create(board, Contest.Name); var memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream); memoryStream.Position = 0; return(File( fileStream: memoryStream, contentType: OpenXmlScoreboard.MimeType, fileDownloadName: $"c{Contest.Id}-scoreboard.xlsx")); }
public static XLWorkbook Create(FullBoardViewModel board, string contestName) { var workbook = new XLWorkbook(XLEventTracking.Disabled); foreach (var sortOrder in board) { var teams = sortOrder.ToList(); var cats = string.Join(", ", teams.Select(t => t.Category).Distinct().Where(a => !string.IsNullOrWhiteSpace(a))); var worksheet = workbook.Worksheets.Add(cats); worksheet.Range(1, 1, 1, 4 + board.Problems.Count).Merge().Value(contestName).Bold().Align(); worksheet.Range(2, 1, 2, 4 + board.Problems.Count).Merge().Value($"导出时间:{DateTimeOffset.Now}").Align(XLAlignmentHorizontalValues.Right); worksheet.Row(1).Height *= 3; worksheet.Row(1).Style.Font.FontSize *= 1.5; worksheet.Row(2).Height *= 1.5; worksheet.Row(3).Height *= 1.5; worksheet.Column(2).Width *= 2; worksheet.Cell(3, 1).Value("RANK").Bold().Align(); worksheet.Cell(3, 2).Value("TEAM").Bold().Align(); worksheet.Range(3, 3, 3, 4).Merge().Value("SCORE").Bold().Align(); for (int i = 0; i < board.Problems.Count; i++) { worksheet.Cell(3, 5 + i).Value(board.Problems[i].ShortName).Bold().Align(); } int rowid = 4; foreach (var team in teams) { var row = worksheet.Row(rowid++); row.Height *= 1.5; row.Cell(1).Value(team.Rank).Align(); row.Cell(2).Value(team.TeamName).Bold().Bgcolor(XLColor.FromHtml(team.CategoryColor)).Align(XLAlignmentHorizontalValues.Right); row.Cell(3).Value(team.Points).Bold().Align(); row.Cell(4).Value(team.Penalty).Align(); for (int i = 0; i < team.Problems.Length; i++) { if (board.RankingStrategy.Id == CcsDefaults.RuleXCPC) { if (team.Problems[i] == null) { continue; } var prob = team.Problems[i]; if (!prob.Score.HasValue && prob.JudgedCount == 0) { continue; } row.Cell(5 + i).Align() .Value(!prob.Score.HasValue ? $"(-{prob.JudgedCount})" : $"{prob.Score} (+{prob.JudgedCount})"); } else if (board.RankingStrategy.Id == CcsDefaults.RuleIOI) { if (team.Problems[i]?.Score is not int sc) { continue; } row.Cell(5 + i).Align().Value(sc); } } } } // sentinel worksheet workbook.AddWorksheet("Sheet0"); return(workbook); }
public async Task <JobStatus> ExecuteAsync(string arguments, Job job, ILogger logger) { var args = arguments.AsJson <Models.ScoreboardArguments>(); var context = await _factory.CreateAsync(args.ContestId, _serviceProvider, true); if (context == null) { logger.LogError("Unknown contest ID specified."); return(JobStatus.Failed); } var contest = context.Contest; if (!contest.StartTime.HasValue || contest.RankingStrategy == CcsDefaults.RuleCodeforces || contest.Feature == CcsDefaults.KindProblemset) { logger.LogError("Export constraint failed."); return(JobStatus.Failed); } logger.LogInformation("Calculating scoreboard..."); DateTimeOffset?endTime = args.IncludeUpsolving ? DateTimeOffset.Now : (contest.StartTime + contest.EndTime); var raw = await RankingSolver.Select(contest) .RefreshCache( _scoreboard, new Events.ScoreboardRefreshEvent(context, endTime)); var rankCaches = raw.RankCache.ToDictionary(r => r.TeamId); var scoreCaches = raw.ScoreCache.ToLookup(r => r.TeamId); var teams1 = await((ITeamContext)context).GetScoreboardRowsAsync(); var teams = teams1.ToDictionary( k => k.TeamId, v => v.With(rankCaches.GetValueOrDefault(v.TeamId), scoreCaches[v.TeamId])); logger.LogInformation("Loading other things from database..."); var affs = await context.ListAffiliationsAsync(); var orgs = await context.ListCategoriesAsync(); var probs = await context.ListProblemsAsync(); var scb = new ScoreboardModel(contest.Id, teams, orgs, affs, probs, contest, RankingSolver.Select(contest)); var board = new FullBoardViewModel(scb, false) { FilteredAffiliations = args.FilteredAffiliations?.ToHashSet(), FilteredCategories = args.FilteredCategories?.ToHashSet(), }; logger.LogInformation("Data loaded."); using var workbook = OpenXmlScoreboard.Create(board, contest.Name); using var memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream); memoryStream.Position = 0; await _files.SaveOutputAsync(job, memoryStream); logger.LogInformation("Export succeeded."); return(JobStatus.Finished); }
public static async Task <IActionResult> DomScoreboard <T>( this ContestControllerBase <T> that, bool isPublic, bool isJury, bool clear, int[] filtered_affiliations, int[] filtered_categories, int?page) where T : class, IContestContext { if (that.Contest.Feature != CcsDefaults.KindDom) { throw new NotSupportedException(); } var pageVal = that.Contest.ShouldScoreboardPaging() ? page ?? 1 : default(int?); that.ViewData["Paging"] = pageVal; if (pageVal.HasValue && pageVal < 1) { return(that.BadRequest()); } if (clear) { filtered_categories = filtered_affiliations = Array.Empty <int>(); } var scb = await that.Context.GetScoreboardAsync(); var board = new FullBoardViewModel(scb, isPublic && !isJury, isJury); if (filtered_affiliations.Length > 0) { var aff2 = filtered_affiliations.ToHashSet(); board.FilteredAffiliations = aff2; that.ViewData["Filter_affiliations"] = aff2; } if (filtered_categories.Length > 0) { var cat2 = filtered_categories.ToHashSet(); board.FilteredCategories = cat2; that.ViewData["Filter_categories"] = cat2; } if (that.Request.Cookies.TryGetValue("domjudge_teamselection", out var teamselection)) { try { var vals = teamselection.AsJson <string[]>(); if (vals != null && vals.Length <= 20 && vals.Length > 0) { var teams = new HashSet <int>(); for (int i = 0; i < vals.Length; i++) { if (int.TryParse(vals[i], out int teamid)) { teams.Add(teamid); } } board.FavoriteTeams = teams; } } catch { // The field `domjudge_teamselection` is wrongly set. that.Response.Cookies.Delete("domjudge_teamselection"); } } return(that.View("Scoreboard", board)); }