diff --git a/GZCTF/ClientApp/src/components/WithNavbar.tsx b/GZCTF/ClientApp/src/components/WithNavbar.tsx index 8a30a8ffc..085fd8038 100644 --- a/GZCTF/ClientApp/src/components/WithNavbar.tsx +++ b/GZCTF/ClientApp/src/components/WithNavbar.tsx @@ -33,7 +33,7 @@ const WithNavBar: FC = ({ children, width, padding, isLoading, rotate={-9} textSize={15} gutter={20} - opacity={theme.colorScheme == 'dark' ? 0.004 : 0.010} + opacity={theme.colorScheme == 'dark' ? 0.004 : 0.01} fontFamily="JetBrains Mono" >
diff --git a/GZCTF/ClientApp/src/pages/admin/games/Index.tsx b/GZCTF/ClientApp/src/pages/admin/games/Index.tsx index b773cd174..3e4a15939 100644 --- a/GZCTF/ClientApp/src/pages/admin/games/Index.tsx +++ b/GZCTF/ClientApp/src/pages/admin/games/Index.tsx @@ -121,18 +121,23 @@ const Games: FC = () => { /> - - + + navigate(`/games/${game.id}`)} + sx={{ cursor: 'pointer' }} + > {game.title?.at(0)} - {game.title} + {game.title} {status} - + {dayjs(startTime).format('YYYY-MM-DD HH:mm')} diff --git a/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx b/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx index af084099f..637fafd81 100644 --- a/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx +++ b/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx @@ -302,9 +302,7 @@ const OneAttachmentWithFlags: FC = ({ onDelete }) => { }} /> - - 请输入 flag 模版字符串,留空以生成随机 UUID 作为 flag - + 请输入 flag 模版字符串,留空以生成随机 UUID 作为 flag 若指定 [TEAM_HASH] 则它将会被自动替换为队伍 Token 与相关信息所生成的哈希值 diff --git a/GZCTF/ClientApp/src/utils/ThemeOverride.ts b/GZCTF/ClientApp/src/utils/ThemeOverride.ts index af116a8b5..04db7d6a2 100644 --- a/GZCTF/ClientApp/src/utils/ThemeOverride.ts +++ b/GZCTF/ClientApp/src/utils/ThemeOverride.ts @@ -69,6 +69,15 @@ export const ThemeOverride: MantineThemeOverride = { fontFamily: "'IBM Plex Sans', sans-serif", }, loader: 'bars', + components: { + Switch: { + styles: { + body: { + alignItems: 'center', + }, + }, + }, + }, } export const useTableStyles = createStyles((theme) => ({ @@ -108,8 +117,8 @@ export const ACCEPT_IMAGE_MIME_TYPE = [ ] interface FixedButtonProps { - right?: string, - bottom?: string, + right?: string + bottom?: string } export const useFixedButtonStyles = createStyles((theme, { right, bottom }: FixedButtonProps) => ({ diff --git a/GZCTF/Controllers/EditController.cs b/GZCTF/Controllers/EditController.cs index 48560ea17..a056b98c2 100644 --- a/GZCTF/Controllers/EditController.cs +++ b/GZCTF/Controllers/EditController.cs @@ -541,7 +541,7 @@ await gameNoticeRepository.AddNotice(new() /// 比赛Id /// 题目Id /// - /// 成功添加比赛题目 + /// 成功开启比赛题目容器 [HttpPost("Games/{id}/Challenges/{cId}/Container")] [ProducesResponseType(typeof(ContainerInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] diff --git a/GZCTF/Repositories/GameRepository.cs b/GZCTF/Repositories/GameRepository.cs index c02631cdf..be1d068c5 100644 --- a/GZCTF/Repositories/GameRepository.cs +++ b/GZCTF/Repositories/GameRepository.cs @@ -88,7 +88,7 @@ private async Task GenScoreboard(Game game, CancellationToken t { var data = await FetchData(game, token); var bloods = GenBloods(data); - var items = GenScoreboardItems(data, bloods); + var items = GenScoreboardItems(data, game, bloods); return new() { Organizations = game.Organizations, @@ -153,7 +153,7 @@ private static IDictionary> GenChalleng .OrderBy(i => i.Key) .ToDictionary(c => c.Key, c => c.AsEnumerable()); - private static IEnumerable GenScoreboardItems(Data[] data, IDictionary bloods) + private static IEnumerable GenScoreboardItems(Data[] data, Game game, IDictionary bloods) => data.GroupBy(j => j.Instance.Participation) .Select(j => { @@ -167,9 +167,13 @@ private static IEnumerable GenScoreboardItems(Data[] data, IDict Organization = j.Key.Organization, Rank = 0, Team = TeamInfoModel.FromTeam(j.Key.Team, true), - LastSubmissionTime = j.Select(s => s.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) - .OrderByDescending(t => t).FirstOrDefault(), - SolvedCount = challengeGroup.Count(c => c.Any(s => s.Submission?.Status == AnswerResult.Accepted)), + LastSubmissionTime = j + .Where(s => s.Submission?.SubmitTimeUTC < game.EndTimeUTC) + .Select(s => s.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) + .OrderBy(t => t).LastOrDefault(), + SolvedCount = challengeGroup.Count(c => c.Any( + s => s.Submission?.Status == AnswerResult.Accepted + && s.Submission?.SubmitTimeUTC < game.EndTimeUTC)), Challenges = challengeGroup .Select(c => { diff --git a/GZCTF/Services/DockerService.cs b/GZCTF/Services/DockerService.cs index 58d5b202c..b8fc2e599 100644 --- a/GZCTF/Services/DockerService.cs +++ b/GZCTF/Services/DockerService.cs @@ -126,7 +126,7 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi Limits = new() { MemoryBytes = config.MemoryLimit * 1024 * 1024, - NanoCPUs = config.CPUCount * 10_0000_0000, // do some math here? + NanoCPUs = config.CPUCount * 10_0000_0000, } }, } @@ -143,9 +143,17 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi } catch (DockerApiException e) { - logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 状态:{e.StatusCode.ToString()}", TaskStatus.Fail, LogLevel.Warning); - logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 响应:{e.ResponseBody}", TaskStatus.Fail, LogLevel.Error); - return null; + if(e.StatusCode == HttpStatusCode.Conflict) + { + await dockerClient.Swarm.RemoveServiceAsync(parameters.Service.Name, token); + serviceRes = await dockerClient.Swarm.CreateServiceAsync(parameters, token); + } + else + { + logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 状态:{e.StatusCode.ToString()}", TaskStatus.Fail, LogLevel.Warning); + logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 响应:{e.ResponseBody}", TaskStatus.Fail, LogLevel.Error); + return null; + } } catch (Exception e) { diff --git a/GZCTF/Services/FlagChecker.cs b/GZCTF/Services/FlagChecker.cs index ed2a4dd5e..1d3c91e76 100644 --- a/GZCTF/Services/FlagChecker.cs +++ b/GZCTF/Services/FlagChecker.cs @@ -89,7 +89,9 @@ await eventRepository.AddEvent(new() } } - if (type != SubmissionType.Unaccepted && type != SubmissionType.Normal) + if (item.Game.EndTimeUTC > DateTimeOffset.UtcNow + && type != SubmissionType.Unaccepted + && type != SubmissionType.Normal) await gameNoticeRepository.AddNotice(GameNotice.FromSubmission(item, type), token); item.Status = ans;