From 3465436ac521cb1bf468dff53d4346f3ea83e58a Mon Sep 17 00:00:00 2001 From: GZTime Date: Sun, 10 Sep 2023 13:09:55 +0800 Subject: [PATCH] Chore: Format code & tidy up (#142) --- src/.editorconfig | 33 +- src/.idea/.idea.GZCTF/.idea/.gitignore | 13 + src/.idea/.idea.GZCTF/.idea/.name | 1 + src/GZCTF.Test/AccountTest.cs | 39 +-- src/GZCTF.Test/ConfigServiceTest.cs | 12 +- src/GZCTF.Test/ContainerServiceTest.cs | 13 +- src/GZCTF.Test/GZCTF.Test.csproj | 76 ++--- src/GZCTF.Test/SignatureTest.cs | 42 +-- src/GZCTF.Test/TestMailSender.cs | 34 +- src/GZCTF.Test/TestWebAppFactory.cs | 6 +- src/GZCTF.sln.DotSettings | 26 ++ src/GZCTF/ClientApp/.vscode/settings.json | 2 +- src/GZCTF/ClientApp/index.html | 24 +- src/GZCTF/ClientApp/package.json | 12 +- src/GZCTF/ClientApp/pnpm-lock.yaml | 208 ++++++------ src/GZCTF/ClientApp/src/Api.ts | 55 ++- src/GZCTF/ClientApp/src/App.tsx | 8 +- .../ClientApp/src/components/AccountView.tsx | 2 +- .../src/components/ActionIconWithConfirm.tsx | 8 +- .../ClientApp/src/components/AppFooter.tsx | 2 +- .../ClientApp/src/components/AppHeader.tsx | 6 +- .../ClientApp/src/components/AppNavbar.tsx | 20 +- .../src/components/ChallengeCard.tsx | 15 +- .../src/components/ChallengeDetailModal.tsx | 3 +- .../src/components/CustomProgress.tsx | 19 +- .../ClientApp/src/components/FooterRender.tsx | 2 +- .../ClientApp/src/components/HintList.tsx | 6 +- .../src/components/InstanceEntry.tsx | 18 +- .../ClientApp/src/components/LogoHeader.tsx | 2 +- .../src/components/MobilePostCard.tsx | 2 +- .../components/MobileScoreboardItemModal.tsx | 14 +- .../src/components/MobileScoreboardTable.tsx | 2 +- .../ClientApp/src/components/PostCard.tsx | 14 +- .../src/components/RecentGameSlide.tsx | 2 +- .../src/components/ScoreboardItemModal.tsx | 12 +- .../src/components/ScoreboardTable.tsx | 16 +- .../ClientApp/src/components/ScrollSelect.tsx | 6 +- .../ClientApp/src/components/StickyHeader.tsx | 9 +- .../src/components/StrengthPasswordInput.tsx | 2 +- .../ClientApp/src/components/TeamCard.tsx | 10 +- .../src/components/TeamCreateModal.tsx | 6 +- .../src/components/TeamEditModal.tsx | 10 +- .../ClientApp/src/components/TeamRank.tsx | 14 +- .../ClientApp/src/components/TrafficItems.tsx | 8 +- .../src/components/WithGameMonitor.tsx | 2 +- .../ClientApp/src/components/WithGameTab.tsx | 4 +- .../ClientApp/src/components/WithRole.tsx | 2 +- .../src/components/WithWiderScreen.tsx | 2 +- .../src/components/admin/AdminPage.tsx | 3 +- .../admin/AttachmentRemoteEditModal.tsx | 2 +- .../admin/AttachmentUploadModal.tsx | 14 +- .../components/admin/ChallengeEditCard.tsx | 8 +- .../admin/ChallengePreviewModal.tsx | 3 +- .../src/components/admin/FlagEditPanel.tsx | 6 +- .../components/admin/GameNoticeEditCard.tsx | 4 +- .../src/components/admin/PostEditCard.tsx | 8 +- .../src/components/admin/TeamEditModal.tsx | 6 +- .../src/components/admin/UserEditModal.tsx | 4 +- .../src/components/admin/WithAdminTab.tsx | 4 +- .../src/components/icon/MainIcon.tsx | 2 +- src/GZCTF/ClientApp/src/mantine.d.ts | 2 +- src/GZCTF/ClientApp/src/pages/About.tsx | 4 +- src/GZCTF/ClientApp/src/pages/Teams.tsx | 14 +- src/GZCTF/ClientApp/src/pages/[...all].tsx | 4 +- .../ClientApp/src/pages/account/Confirm.tsx | 2 +- .../ClientApp/src/pages/account/Login.tsx | 2 +- .../ClientApp/src/pages/account/Profile.tsx | 20 +- .../ClientApp/src/pages/account/Recovery.tsx | 2 +- .../ClientApp/src/pages/account/Register.tsx | 2 +- .../ClientApp/src/pages/account/Reset.tsx | 2 +- .../ClientApp/src/pages/account/Verify.tsx | 2 +- .../ClientApp/src/pages/admin/Instances.tsx | 16 +- src/GZCTF/ClientApp/src/pages/admin/Logs.tsx | 14 +- src/GZCTF/ClientApp/src/pages/admin/Teams.tsx | 22 +- src/GZCTF/ClientApp/src/pages/admin/Users.tsx | 16 +- .../ClientApp/src/pages/admin/games/Index.tsx | 11 +- .../src/pages/admin/games/[id]/Info.tsx | 18 +- .../src/pages/admin/games/[id]/Notices.tsx | 4 +- .../src/pages/admin/games/[id]/Review.tsx | 2 +- .../src/pages/admin/games/[id]/Writeups.tsx | 2 +- .../admin/games/[id]/challenges/Index.tsx | 2 +- .../games/[id]/challenges/[chalId]/Flags.tsx | 12 +- .../games/[id]/challenges/[chalId]/Index.tsx | 14 +- .../ClientApp/src/pages/games/[id]/Index.tsx | 10 +- .../pages/games/[id]/monitor/CheatInfo.tsx | 18 +- .../src/pages/games/[id]/monitor/Events.tsx | 20 +- .../pages/games/[id]/monitor/Submissions.tsx | 14 +- .../src/pages/games/[id]/monitor/Traffic.tsx | 14 +- .../src/pages/posts/[postId]/Index.tsx | 4 +- .../src/pages/posts/[postId]/edit.tsx | 12 +- src/GZCTF/ClientApp/src/utils/Shared.tsx | 15 +- .../ClientApp/src/utils/ThemeOverride.ts | 16 +- src/GZCTF/ClientApp/tsconfig.json | 40 ++- src/GZCTF/ClientApp/vite.config.ts | 8 +- src/GZCTF/Controllers/AccountController.cs | 88 ++--- src/GZCTF/Controllers/AdminController.cs | 119 ++++--- src/GZCTF/Controllers/AssetsController.cs | 29 +- src/GZCTF/Controllers/EditController.cs | 228 ++++++------- src/GZCTF/Controllers/GameController.cs | 321 +++++++++--------- src/GZCTF/Controllers/InfoController.cs | 16 +- src/GZCTF/Controllers/ProxyController.cs | 128 +++---- src/GZCTF/Controllers/TeamController.cs | 140 ++++---- src/GZCTF/Extensions/CacheExtensions.cs | 10 +- src/GZCTF/Extensions/CaptchaExtension.cs | 56 +-- .../ConfigurationBuilderExtensions.cs | 7 +- src/GZCTF/Extensions/OtherExtensions.cs | 23 +- src/GZCTF/Extensions/SignalRSinkExtension.cs | 19 +- src/GZCTF/GZCTF.csproj | 256 +++++++------- src/GZCTF/Hubs/AdminHub.cs | 5 +- src/GZCTF/Hubs/Clients/IAdminClient.cs | 4 +- src/GZCTF/Hubs/Clients/IMonitorClient.cs | 2 +- src/GZCTF/Hubs/Clients/IUserClient.cs | 2 +- src/GZCTF/Hubs/MonitorHub.cs | 9 +- src/GZCTF/Hubs/UserHub.cs | 9 +- .../Middlewares/PrivilegeAuthentication.cs | 11 +- src/GZCTF/Middlewares/RateLimiter.cs | 133 ++++---- .../20220905103212_InitDb.Designer.cs | 128 +++---- ...907163829_AddUserParticipation.Designer.cs | 134 ++++---- .../20220909041834_AddGameHidden.Designer.cs | 134 ++++---- ...20220911143942_AddPracticeMode.Designer.cs | 134 ++++---- ...20220913083420_UpdateDataTypes.Designer.cs | 134 ++++---- ...13135843_AddDataProtectionKeys.Designer.cs | 134 ++++---- ...8120342_AddPrivilegedContainer.Designer.cs | 134 ++++---- .../20220921174925_UniqueFlagId.Designer.cs | 134 ++++---- .../20220929055922_StorageLimit.Designer.cs | 134 ++++---- .../20221109175757_AddWriteupInfo.Designer.cs | 136 ++++---- .../20221109200305_AddFileSize.Designer.cs | 136 ++++---- .../20221111044316_AddWriteupNote.Designer.cs | 136 ++++---- ...21111075728_UpdateFileSizeType.Designer.cs | 136 ++++---- .../20221116064912_FixModelTypo.Designer.cs | 136 ++++---- .../20221127174109_AddBloodBonus.Designer.cs | 136 ++++---- ...0418095639_AddConcurrencyStamp.Designer.cs | 136 ++++---- ...5626_UpdateParticipationStatus.Designer.cs | 136 ++++---- .../20230702191504_AddCheatInfo.Designer.cs | 148 ++++---- ...230816021558_AddCaptureTraffic.Designer.cs | 148 ++++---- .../Migrations/AppDbContextModelSnapshot.cs | 302 ++++++++-------- src/GZCTF/Models/AppDbContext.cs | 50 +-- src/GZCTF/Models/Data/Attachment.cs | 17 +- src/GZCTF/Models/Data/Challenge.cs | 134 ++++---- src/GZCTF/Models/Data/CheatInfo.cs | 2 +- src/GZCTF/Models/Data/Config.cs | 9 +- src/GZCTF/Models/Data/Container.cs | 15 +- src/GZCTF/Models/Data/FlagContext.cs | 5 +- src/GZCTF/Models/Data/Game.cs | 105 +++--- src/GZCTF/Models/Data/GameEvent.cs | 11 +- src/GZCTF/Models/Data/GameNotice.cs | 8 +- src/GZCTF/Models/Data/Instance.cs | 32 +- src/GZCTF/Models/Data/LocalFile.cs | 4 +- src/GZCTF/Models/Data/LogModel.cs | 4 +- src/GZCTF/Models/Data/Participation.cs | 4 +- src/GZCTF/Models/Data/Post.cs | 7 +- src/GZCTF/Models/Data/Submission.cs | 4 +- src/GZCTF/Models/Data/Team.cs | 43 ++- src/GZCTF/Models/Data/UserInfo.cs | 55 +-- src/GZCTF/Models/Data/UserParticipation.cs | 14 +- src/GZCTF/Models/Internal/CaptchaModel.cs | 8 +- src/GZCTF/Models/Internal/CheatCheckInfo.cs | 10 +- src/GZCTF/Models/Internal/Configs.cs | 32 +- src/GZCTF/Models/Internal/ContainerConfig.cs | 8 +- src/GZCTF/Models/Internal/ContainerInfo.cs | 2 +- .../Request/Account/AccountVerifyModel.cs | 2 +- .../Models/Request/Account/LoginModel.cs | 2 +- .../Models/Request/Account/MailChangeModel.cs | 2 +- .../Request/Account/PasswordChangeModel.cs | 2 +- .../Request/Account/PasswordResetModel.cs | 2 +- .../Request/Account/ProfileUpdateModel.cs | 2 +- .../Request/Account/ProfileUserInfoModel.cs | 6 +- .../Models/Request/Account/RecoveryModel.cs | 2 +- .../Models/Request/Account/RegisterModel.cs | 2 +- .../Models/Request/Admin/AdminTeamModel.cs | 2 +- .../Request/Admin/AdminUserInfoModel.cs | 2 +- .../Models/Request/Admin/ConfigEditModel.cs | 2 +- .../Request/Admin/ContainerInstanceModel.cs | 16 +- .../Models/Request/Admin/LogMessageModel.cs | 6 +- .../Request/Admin/ParticipationInfoModel.cs | 6 +- .../Request/Admin/TeamWithDetailedUserInfo.cs | 6 +- .../Models/Request/Admin/UserCreateModel.cs | 22 +- .../Models/Request/Admin/UserInfoModel.cs | 6 +- .../Models/Request/Admin/WriteupInfoModel.cs | 22 +- .../Request/Edit/AttachmentCreateModel.cs | 2 +- .../Request/Edit/ChallengeEditDetailModel.cs | 118 ++++--- .../Models/Request/Edit/ChallengeInfoModel.cs | 10 +- .../Request/Edit/ChallengeUpdateModel.cs | 59 ++-- .../Models/Request/Edit/FlagCreateModel.cs | 2 +- .../Models/Request/Edit/FlagInfoModel.cs | 15 +- .../Models/Request/Edit/GameInfoModel.cs | 13 +- .../Models/Request/Edit/GameNoticeModel.cs | 2 +- .../Models/Request/Edit/PostEditModel.cs | 2 +- .../Models/Request/Game/BasicGameInfoModel.cs | 8 +- .../Request/Game/BasicWriteupInfoModel.cs | 14 +- .../Request/Game/ChallengeDetailModel.cs | 14 +- .../Request/Game/ChallengeTrafficModel.cs | 14 +- .../Models/Request/Game/CheatInfoModel.cs | 11 +- .../Models/Request/Game/ContainerInfoModel.cs | 12 +- .../Request/Game/DetailedGameInfoModel.cs | 14 +- .../Models/Request/Game/FlagSubmitModel.cs | 4 +- .../Models/Request/Game/GameDetailModel.cs | 2 +- .../Models/Request/Game/GameJoinModel.cs | 2 +- .../Models/Request/Game/ScoreboardModel.cs | 4 +- .../Models/Request/Game/TeamTrafficModel.cs | 13 +- .../Request/Info/ClientCaptchaInfoModel.cs | 23 +- .../Models/Request/Info/PostDetailModel.cs | 10 +- .../Models/Request/Info/PostInfoModel.cs | 10 +- .../Models/Request/Info/TeamInfoModel.cs | 54 +-- .../Models/Request/Info/TeamTransferModel.cs | 2 +- .../Models/Request/Info/TeamUpdateModel.cs | 2 +- .../Models/Request/Info/TeamUserInfoModel.cs | 2 +- src/GZCTF/Pages/Error.cshtml.cs | 7 +- src/GZCTF/Pages/_ViewImports.cshtml | 3 +- src/GZCTF/Program.cs | 172 +++++----- .../Providers/EntityConfigurationProvider.cs | 64 ++-- .../Providers/EntityConfigurationSource.cs | 8 +- src/GZCTF/Repositories/ChallengeRepository.cs | 71 ++-- src/GZCTF/Repositories/CheatInfoRepository.cs | 22 +- src/GZCTF/Repositories/ContainerRepository.cs | 35 +- src/GZCTF/Repositories/FileRepository.cs | 118 ++++--- src/GZCTF/Repositories/GameEventRepository.cs | 9 +- .../Repositories/GameNoticeRepository.cs | 16 +- src/GZCTF/Repositories/GameRepository.cs | 235 ++++++------- src/GZCTF/Repositories/InstanceRepository.cs | 108 +++--- .../Interface/IChallengeRepository.cs | 2 +- .../Interface/ICheatInfoRepository.cs | 6 +- .../Interface/IContainerRepository.cs | 2 +- .../Repositories/Interface/IFileRepository.cs | 8 +- .../Interface/IGameEventRepository.cs | 5 +- .../Interface/IGameNoticeRepository.cs | 2 +- .../Repositories/Interface/IGameRepository.cs | 2 +- .../Interface/IInstanceRepository.cs | 6 +- .../Repositories/Interface/ILogRepository.cs | 2 +- .../Interface/IParticipationRepository.cs | 6 +- .../Repositories/Interface/IPostRepository.cs | 2 +- .../Repositories/Interface/IRepository.cs | 5 +- .../Interface/ISubmissionRepository.cs | 14 +- .../Repositories/Interface/ITeamRepository.cs | 2 +- src/GZCTF/Repositories/LogRepository.cs | 2 +- .../Repositories/ParticipationRepository.cs | 68 ++-- src/GZCTF/Repositories/PostRepository.cs | 17 +- src/GZCTF/Repositories/RepositoryBase.cs | 21 +- .../Repositories/SubmissionRepository.cs | 46 +-- src/GZCTF/Repositories/TeamRepository.cs | 25 +- .../Services/Assets/URLEmailTemplate.html | 30 +- src/GZCTF/Services/Cache/CacheHelper.cs | 92 +++-- src/GZCTF/Services/Cache/CacheMaker.cs | 81 +++-- src/GZCTF/Services/ConfigService.cs | 60 ++-- .../Container/ContainerServiceExtension.cs | 24 +- .../Container/Manager/DockerManager.cs | 112 +++--- .../Services/Container/Manager/K8sManager.cs | 135 ++++---- .../Container/Manager/SwarmManager.cs | 134 ++++---- .../Container/Provider/DockerProvider.cs | 42 ++- .../Container/Provider/K8sProvider.cs | 94 +++-- src/GZCTF/Services/CronJobService.cs | 42 +-- src/GZCTF/Services/FlagChecker.cs | 110 +++--- .../Services/Interface/IConfigService.cs | 2 +- .../Services/Interface/IContainerManager.cs | 6 +- .../Services/Interface/IContainerProvider.cs | 3 +- src/GZCTF/Services/Interface/IMailSender.cs | 5 +- src/GZCTF/Services/MailSender.cs | 50 +-- src/GZCTF/Utils/Codec.cs | 296 ++++++++-------- src/GZCTF/Utils/DigitalSignature.cs | 24 +- src/GZCTF/Utils/Enums.cs | 24 +- src/GZCTF/Utils/ExcelHelper.cs | 63 ++-- src/GZCTF/Utils/FilePath.cs | 28 +- src/GZCTF/Utils/HubHelper.cs | 25 +- src/GZCTF/Utils/LogHelper.cs | 102 +++--- src/GZCTF/Utils/PrelaunchHelper.cs | 28 +- ...rkStream.cs => RecordableNetworkStream.cs} | 39 ++- src/GZCTF/Utils/Shared.cs | 41 +-- .../Utils/TranslatedIdentityErrorDescriber.cs | 245 +++---------- 268 files changed, 4875 insertions(+), 5075 deletions(-) create mode 100644 src/.idea/.idea.GZCTF/.idea/.gitignore create mode 100644 src/.idea/.idea.GZCTF/.idea/.name create mode 100644 src/GZCTF.sln.DotSettings rename src/GZCTF/Utils/{CapturableNetworkStream.cs => RecordableNetworkStream.cs} (69%) diff --git a/src/.editorconfig b/src/.editorconfig index 82f4a2ccf..00d81f5ed 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -38,28 +38,28 @@ dotnet_style_predefined_type_for_member_access = true:suggestion # name all constant fields using PascalCase dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style -dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.pascal_case_style.capitalization = pascal_case # static fields should be PascalCase dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion -dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields -dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style +dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style -dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_style.static_prefix_style.capitalization = pascal_case # internal and private fields should be _camelCase dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion -dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields -dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style dotnet_naming_symbols.private_internal_fields.applicable_kinds = field dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal @@ -80,7 +80,7 @@ dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion # Expression-bodied members -csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_methods = true:suggestion csharp_style_expression_bodied_constructors = false:none csharp_style_expression_bodied_operators = false:none csharp_style_expression_bodied_properties = true:none @@ -121,7 +121,18 @@ csharp_space_between_parentheses = false csharp_space_between_square_brackets = false # IDE1006: 命名样式 -dotnet_diagnostic.IDE1006.severity = none +dotnet_diagnostic.ide1006.severity = none # CA1848: 使用 LoggerMessage 委托 -dotnet_diagnostic.CA1848.severity = none +dotnet_diagnostic.ca1848.severity = none + +# ReSharper properties +resharper_csharp_max_line_length = 150 +resharper_local_function_body = expression_body +resharper_place_accessorholder_attribute_on_same_line = false +resharper_place_field_attribute_on_same_line = false +resharper_wrap_switch_expression = wrap_if_long + +# ReSharper inspection severities +resharper_arrange_local_function_body_highlighting = hint +resharper_arrange_method_or_operator_body_highlighting = hint diff --git a/src/.idea/.idea.GZCTF/.idea/.gitignore b/src/.idea/.idea.GZCTF/.idea/.gitignore new file mode 100644 index 000000000..277382a41 --- /dev/null +++ b/src/.idea/.idea.GZCTF/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/modules.xml +/.idea.GZCTF.iml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/.idea/.idea.GZCTF/.idea/.name b/src/.idea/.idea.GZCTF/.idea/.name new file mode 100644 index 000000000..0ff892b6d --- /dev/null +++ b/src/.idea/.idea.GZCTF/.idea/.name @@ -0,0 +1 @@ +GZCTF \ No newline at end of file diff --git a/src/GZCTF.Test/AccountTest.cs b/src/GZCTF.Test/AccountTest.cs index befbb85ed..10fd82574 100644 --- a/src/GZCTF.Test/AccountTest.cs +++ b/src/GZCTF.Test/AccountTest.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; using Xunit; @@ -8,8 +9,8 @@ namespace GZCTF.Test; public class AccountTest : IClassFixture { - private readonly TestWebAppFactory _factory; - private readonly ITestOutputHelper _output; + readonly TestWebAppFactory _factory; + readonly ITestOutputHelper _output; public AccountTest(TestWebAppFactory factory, ITestOutputHelper output) { @@ -20,35 +21,21 @@ public AccountTest(TestWebAppFactory factory, ITestOutputHelper output) [Fact] public async Task TestCreateUser() { - using var client = _factory.CreateClient(); - var registerResult = await client.PostAsJsonAsync("/api/account/register", new - { - userName = "foo", - password = "foo12345", - email = "foo@example.com", - }); + using HttpClient client = _factory.CreateClient(); + HttpResponseMessage registerResult = await client.PostAsJsonAsync("/api/account/register", + new { userName = "foo", password = "foo12345", email = "foo@example.com" }); Assert.Equal(HttpStatusCode.BadRequest, registerResult.StatusCode); - registerResult = await client.PostAsJsonAsync("/api/account/register", new - { - userName = "foo", - password = "foo12345##Foo", - email = "foo@example.com", - }); + registerResult = await client.PostAsJsonAsync("/api/account/register", + new { userName = "foo", password = "foo12345##Foo", email = "foo@example.com" }); Assert.True(registerResult.IsSuccessStatusCode); - var loginResult = await client.PostAsJsonAsync("/api/account/login", new - { - userName = "foo", - password = "foo12345##" - }); + HttpResponseMessage loginResult = + await client.PostAsJsonAsync("/api/account/login", new { userName = "foo", password = "foo12345##" }); Assert.False(loginResult.IsSuccessStatusCode); - loginResult = await client.PostAsJsonAsync("/api/account/login", new - { - userName = "foo", - password = "foo12345##Foo" - }); + loginResult = + await client.PostAsJsonAsync("/api/account/login", new { userName = "foo", password = "foo12345##Foo" }); Assert.True(loginResult.IsSuccessStatusCode); } -} +} \ No newline at end of file diff --git a/src/GZCTF.Test/ConfigServiceTest.cs b/src/GZCTF.Test/ConfigServiceTest.cs index 8d0227819..10b770040 100644 --- a/src/GZCTF.Test/ConfigServiceTest.cs +++ b/src/GZCTF.Test/ConfigServiceTest.cs @@ -1,4 +1,6 @@ -using GZCTF.Models.Internal; +using System.Collections.Generic; +using GZCTF.Models.Data; +using GZCTF.Models.Internal; using GZCTF.Services; using Xunit; using Xunit.Abstractions; @@ -7,7 +9,7 @@ namespace GZCTF.Test; public class ConfigServiceTest { - private readonly ITestOutputHelper output; + readonly ITestOutputHelper output; public ConfigServiceTest(ITestOutputHelper _output) { @@ -17,11 +19,11 @@ public ConfigServiceTest(ITestOutputHelper _output) [Fact] public void TestGetConfigs() { - var configs = ConfigService.GetConfigs(new TestConfig()); + HashSet? configs = ConfigService.GetConfigs(new TestConfig()); Assert.True(configs is not null); Assert.True(configs.Count > 0); - foreach (var config in configs) + foreach (Config config in configs) output.WriteLine($"{config.ConfigKey,-32}={config.Value}"); } } @@ -31,4 +33,4 @@ public class TestConfig public AccountPolicy AccoutPolicy { get; set; } = new(); public DockerConfig DockerConfig { get; set; } = new(); public EmailConfig EmailConfig { get; set; } = new(); -} +} \ No newline at end of file diff --git a/src/GZCTF.Test/ContainerServiceTest.cs b/src/GZCTF.Test/ContainerServiceTest.cs index ccf408cee..4166c7862 100644 --- a/src/GZCTF.Test/ContainerServiceTest.cs +++ b/src/GZCTF.Test/ContainerServiceTest.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using GZCTF.Models.Internal; -using GZCTF.Services.Interface; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; @@ -12,8 +5,8 @@ namespace GZCTF.Test; public class ContainerServiceTest : IClassFixture { - private readonly TestWebAppFactory factory; - private readonly ITestOutputHelper output; + readonly TestWebAppFactory factory; + readonly ITestOutputHelper output; public ContainerServiceTest(ITestOutputHelper _output, TestWebAppFactory _factory) { @@ -81,4 +74,4 @@ public ContainerServiceTest(ITestOutputHelper _output, TestWebAppFactory _factor // output.WriteLine($"[{DateTime.Now:u}] Container destoryed."); //} -} +} \ No newline at end of file diff --git a/src/GZCTF.Test/GZCTF.Test.csproj b/src/GZCTF.Test/GZCTF.Test.csproj index 42ece9970..258bf2d29 100644 --- a/src/GZCTF.Test/GZCTF.Test.csproj +++ b/src/GZCTF.Test/GZCTF.Test.csproj @@ -1,44 +1,44 @@  - - net7.0 - enable - false - true - Debug;Release;GenAPI - 0.17.1 - True - + + net7.0 + enable + false + true + Debug;Release;GenAPI + 0.17.1 + True + - - 4 - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + 4 + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - - + + + + diff --git a/src/GZCTF.Test/SignatureTest.cs b/src/GZCTF.Test/SignatureTest.cs index b9e50e475..51788d430 100644 --- a/src/GZCTF.Test/SignatureTest.cs +++ b/src/GZCTF.Test/SignatureTest.cs @@ -12,7 +12,7 @@ namespace GZCTF.Test; public class SignatureTest { - private readonly ITestOutputHelper output; + readonly ITestOutputHelper output; public SignatureTest(ITestOutputHelper _output) { @@ -23,15 +23,15 @@ public SignatureTest(ITestOutputHelper _output) public void Ed25519Test() { var sAlgorithm = SignAlgorithm.Ed25519; - var s = "Hello " + sAlgorithm.ToString(); + var s = "Hello " + sAlgorithm; output.WriteLine(s); SecureRandom sr = new(); Ed25519KeyPairGenerator kpg = new(); kpg.Init(new Ed25519KeyGenerationParameters(sr)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); - Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.Private; - Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.Public; + var privateKey = (Ed25519PrivateKeyParameters)kp.Private; + var publicKey = (Ed25519PublicKeyParameters)kp.Public; output.WriteLine("私钥:"); output.WriteLine(Base64.ToBase64String(privateKey.GetEncoded())); @@ -52,16 +52,18 @@ public void Ed25519Test() public void Ed25519WithXorTest() { var sAlgorithm = SignAlgorithm.Ed25519; - var s = "Hello " + sAlgorithm.ToString(); + var s = "Hello " + sAlgorithm; output.WriteLine(s); - Ed25519PrivateKeyParameters privateKey = new(Codec.Base64.DecodeToBytes("Qu4G33WZ7DYTUEdlf3P5amVg7f8yXcOmFcG0EJvfQEY="), 0); - Ed25519PublicKeyParameters publicKey = new(Codec.Base64.DecodeToBytes("t4zduq4LGA1hEYhkCVK19xRACXuDxm/W72v4PBN1EXY="), 0); + Ed25519PrivateKeyParameters privateKey = + new(Codec.Base64.DecodeToBytes("Qu4G33WZ7DYTUEdlf3P5amVg7f8yXcOmFcG0EJvfQEY="), 0); + Ed25519PublicKeyParameters publicKey = + new(Codec.Base64.DecodeToBytes("t4zduq4LGA1hEYhkCVK19xRACXuDxm/W72v4PBN1EXY="), 0); output.WriteLine("私钥:"); output.WriteLine(Base64.ToBase64String(privateKey.GetEncoded())); - byte[] xorkey = Encoding.UTF8.GetBytes("helloworld"); + var xorkey = Encoding.UTF8.GetBytes("helloworld"); var encodedkey = Base64.ToBase64String(Codec.Xor(privateKey.GetEncoded(), xorkey)); output.WriteLine("编码私钥:"); @@ -88,16 +90,16 @@ public void Ed25519WithXorTest() [Fact] public void Ed25519ctxTest() { - var sAlgorithm = SignAlgorithm.Ed25519ctx; - var s = "Hello " + sAlgorithm.ToString(); + var sAlgorithm = SignAlgorithm.Ed25519Ctx; + var s = "Hello " + sAlgorithm; output.WriteLine(s); SecureRandom sr = new(); Ed25519KeyPairGenerator kpg = new(); kpg.Init(new Ed25519KeyGenerationParameters(sr)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); - Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.Private; - Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.Public; + var privateKey = (Ed25519PrivateKeyParameters)kp.Private; + var publicKey = (Ed25519PublicKeyParameters)kp.Public; output.WriteLine("私钥:"); output.WriteLine(Base64.ToBase64String(privateKey.GetEncoded())); @@ -118,15 +120,15 @@ public void Ed25519ctxTest() public void Ed448Test() { var sAlgorithm = SignAlgorithm.Ed448; - var s = "Hello " + sAlgorithm.ToString(); + var s = "Hello " + sAlgorithm; output.WriteLine(s); SecureRandom sr = new(); Ed448KeyPairGenerator kpg = new(); kpg.Init(new Ed448KeyGenerationParameters(sr)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); - Ed448PrivateKeyParameters privateKey = (Ed448PrivateKeyParameters)kp.Private; - Ed448PublicKeyParameters publicKey = (Ed448PublicKeyParameters)kp.Public; + var privateKey = (Ed448PrivateKeyParameters)kp.Private; + var publicKey = (Ed448PublicKeyParameters)kp.Public; output.WriteLine("私钥:"); output.WriteLine(Base64.ToBase64String(privateKey.GetEncoded())); @@ -146,16 +148,16 @@ public void Ed448Test() [Fact] public void SHA512withRSATest() { - var sAlgorithm = SignAlgorithm.SHA512withRSA; - var s = "Hello " + sAlgorithm.ToString(); + var sAlgorithm = SignAlgorithm.SHA512WithRSA; + var s = "Hello " + sAlgorithm; output.WriteLine(s); SecureRandom sr = new(); RsaKeyPairGenerator kpg = new(); kpg.Init(new KeyGenerationParameters(sr, 2048)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); - RsaKeyParameters privateKey = (RsaKeyParameters)kp.Private; - RsaKeyParameters publicKey = (RsaKeyParameters)kp.Public; + var privateKey = (RsaKeyParameters)kp.Private; + var publicKey = (RsaKeyParameters)kp.Public; output.WriteLine("私钥:"); output.WriteLine(privateKey.Exponent.ToString()); @@ -171,4 +173,4 @@ public void SHA512withRSATest() output.WriteLine(verified ? "Signature verified" : "Signature not verified"); Assert.True(verified); } -} +} \ No newline at end of file diff --git a/src/GZCTF.Test/TestMailSender.cs b/src/GZCTF.Test/TestMailSender.cs index 6a257d802..9f7b9bfc0 100644 --- a/src/GZCTF.Test/TestMailSender.cs +++ b/src/GZCTF.Test/TestMailSender.cs @@ -5,33 +5,17 @@ namespace GZCTF.Test; public class TestMailSender : IMailSender { - public bool SendChangeEmailUrl(string? userName, string? email, string? resetLink) - { - return true; - } + public bool SendChangeEmailUrl(string? userName, string? email, string? resetLink) => true; - public bool SendConfirmEmailUrl(string? userName, string? email, string? confirmLink) - { - return true; - } + public bool SendConfirmEmailUrl(string? userName, string? email, string? confirmLink) => true; - public Task SendEmailAsync(string subject, string content, string to) - { - return Task.FromResult(true); - } + public Task SendEmailAsync(string subject, string content, string to) => Task.FromResult(true); - public bool SendResetPasswordUrl(string? userName, string? email, string? resetLink) - { - return true; - } + public bool SendResetPasswordUrl(string? userName, string? email, string? resetLink) => true; - public bool SendResetPwdUrl(string? userName, string? email, string? resetLink) - { - return true; - } + public Task SendUrlAsync(string? title, string? infomation, string? btnmsg, string? userName, string? email, + string? url) => + Task.CompletedTask; - public Task SendUrlAsync(string? title, string? infomation, string? btnmsg, string? userName, string? email, string? url) - { - return Task.CompletedTask; - } -} + public bool SendResetPwdUrl(string? userName, string? email, string? resetLink) => true; +} \ No newline at end of file diff --git a/src/GZCTF.Test/TestWebAppFactory.cs b/src/GZCTF.Test/TestWebAppFactory.cs index cda30fefd..710cec26d 100644 --- a/src/GZCTF.Test/TestWebAppFactory.cs +++ b/src/GZCTF.Test/TestWebAppFactory.cs @@ -13,12 +13,10 @@ static TestWebAppFactory() Program.IsTesting = true; } - protected override void ConfigureWebHost(IWebHostBuilder builder) - { + protected override void ConfigureWebHost(IWebHostBuilder builder) => builder.ConfigureServices(services => { services.Remove(services.Single(d => d.ServiceType == typeof(IMailSender))); services.AddTransient(); }); - } -} +} \ No newline at end of file diff --git a/src/GZCTF.sln.DotSettings b/src/GZCTF.sln.DotSettings new file mode 100644 index 000000000..46b7af256 --- /dev/null +++ b/src/GZCTF.sln.DotSettings @@ -0,0 +1,26 @@ + + CPU + IP + PPC + RFC + RSA + SHA + UTF + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + diff --git a/src/GZCTF/ClientApp/.vscode/settings.json b/src/GZCTF/ClientApp/.vscode/settings.json index a0188768c..e8e74c90f 100644 --- a/src/GZCTF/ClientApp/.vscode/settings.json +++ b/src/GZCTF/ClientApp/.vscode/settings.json @@ -1,3 +1,3 @@ { - "liveServer.settings.root": "/build", + "liveServer.settings.root": "/build" } diff --git a/src/GZCTF/ClientApp/index.html b/src/GZCTF/ClientApp/index.html index c59e954a7..1770ea71b 100644 --- a/src/GZCTF/ClientApp/index.html +++ b/src/GZCTF/ClientApp/index.html @@ -1,15 +1,15 @@ - - - - - - - GZ::CTF - - -
- - + + + + + + + GZ::CTF + + +
+ + diff --git a/src/GZCTF/ClientApp/package.json b/src/GZCTF/ClientApp/package.json index 80997137e..624c26547 100644 --- a/src/GZCTF/ClientApp/package.json +++ b/src/GZCTF/ClientApp/package.json @@ -11,7 +11,7 @@ "genapi": "swagger-typescript-api -p template/swagger.json -t template -o src --module-name-first-tag --sort-routes" }, "dependencies": { - "@babel/core": "^7.22.15", + "@babel/core": "^7.22.17", "@emotion/react": "^11.11.1", "@mantine/carousel": "^6.0.20", "@mantine/core": "^6.0.20", @@ -21,7 +21,7 @@ "@mantine/hooks": "^6.0.20", "@mantine/modals": "^6.0.20", "@mantine/notifications": "^6.0.20", - "@marsidev/react-turnstile": "^0.3.0", + "@marsidev/react-turnstile": "^0.3.1", "@mdi/js": "^7.2.96", "@mdi/react": "^1.6.1", "@microsoft/signalr": "^7.0.10", @@ -33,7 +33,7 @@ "embla-carousel-react": "^7.1.0", "katex": "^0.16.8", "lz-string": "^1.5.0", - "marked": "^8.0.0", + "marked": "^8.0.1", "marked-highlight": "^2.0.5", "pdfjs-dist": "3.6.172", "prismjs": "^1.29.0", @@ -51,7 +51,7 @@ "@nabla/vite-plugin-eslint": "^1.5.0", "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@types/katex": "^0.16.2", - "@types/node": "20.5.9", + "@types/node": "20.6.0", "@types/prismjs": "^1.26.0", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", @@ -60,12 +60,12 @@ "@vitejs/plugin-react": "^4.0.4", "axios": "^1.5.0", "babel-plugin-prismjs": "^2.1.0", - "eslint": "8.48.0", + "eslint": "8.49.0", "eslint-plugin-react-hooks": "^4.6.0", "form-data": "~4.0.0", "lodash": "^4.17.21", "prettier": "~3.0.3", - "rollup": "^3.28.1", + "rollup": "^3.29.0", "swagger-typescript-api": "^13.0.3", "tslib": "^2.6.2", "typescript": "5.2.2", diff --git a/src/GZCTF/ClientApp/pnpm-lock.yaml b/src/GZCTF/ClientApp/pnpm-lock.yaml index ac5690c70..29591083e 100644 --- a/src/GZCTF/ClientApp/pnpm-lock.yaml +++ b/src/GZCTF/ClientApp/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: '@babel/core': - specifier: ^7.22.15 - version: 7.22.15 + specifier: ^7.22.17 + version: 7.22.17 '@emotion/react': specifier: ^11.11.1 version: 11.11.1(@types/react@18.2.21)(react@18.2.0) @@ -36,8 +36,8 @@ dependencies: specifier: ^6.0.20 version: 6.0.20(@mantine/core@6.0.20)(@mantine/hooks@6.0.20)(react-dom@18.2.0)(react@18.2.0) '@marsidev/react-turnstile': - specifier: ^0.3.0 - version: 0.3.0(react-dom@18.2.0)(react@18.2.0) + specifier: ^0.3.1 + version: 0.3.1(react-dom@18.2.0)(react@18.2.0) '@mdi/js': specifier: ^7.2.96 version: 7.2.96 @@ -72,11 +72,11 @@ dependencies: specifier: ^1.5.0 version: 1.5.0 marked: - specifier: ^8.0.0 - version: 8.0.0 + specifier: ^8.0.1 + version: 8.0.1 marked-highlight: specifier: ^2.0.5 - version: 2.0.5(marked@8.0.0) + version: 2.0.5(marked@8.0.1) pdfjs-dist: specifier: 3.6.172 version: 3.6.172 @@ -111,10 +111,10 @@ dependencies: devDependencies: '@babel/eslint-parser': specifier: ^7.22.15 - version: 7.22.15(@babel/core@7.22.15)(eslint@8.48.0) + version: 7.22.15(@babel/core@7.22.17)(eslint@8.49.0) '@nabla/vite-plugin-eslint': specifier: ^1.5.0 - version: 1.5.0(eslint@8.48.0)(vite@4.4.9) + version: 1.5.0(eslint@8.49.0)(vite@4.4.9) '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 version: 4.2.0(prettier@3.0.3) @@ -122,8 +122,8 @@ devDependencies: specifier: ^0.16.2 version: 0.16.2 '@types/node': - specifier: 20.5.9 - version: 20.5.9 + specifier: 20.6.0 + version: 20.6.0 '@types/prismjs': specifier: ^1.26.0 version: 1.26.0 @@ -135,10 +135,10 @@ devDependencies: version: 18.2.7 '@typescript-eslint/eslint-plugin': specifier: ^6.6.0 - version: 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.2.2) + version: 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/parser': specifier: ^6.6.0 - version: 6.6.0(eslint@8.48.0)(typescript@5.2.2) + version: 6.6.0(eslint@8.49.0)(typescript@5.2.2) '@vitejs/plugin-react': specifier: ^4.0.4 version: 4.0.4(vite@4.4.9) @@ -149,11 +149,11 @@ devDependencies: specifier: ^2.1.0 version: 2.1.0(prismjs@1.29.0) eslint: - specifier: 8.48.0 - version: 8.48.0 + specifier: 8.49.0 + version: 8.49.0 eslint-plugin-react-hooks: specifier: ^4.6.0 - version: 4.6.0(eslint@8.48.0) + version: 4.6.0(eslint@8.49.0) form-data: specifier: ~4.0.0 version: 4.0.0 @@ -164,8 +164,8 @@ devDependencies: specifier: ~3.0.3 version: 3.0.3 rollup: - specifier: ^3.28.1 - version: 3.28.1 + specifier: ^3.29.0 + version: 3.29.0 swagger-typescript-api: specifier: ^13.0.3 version: 13.0.3 @@ -177,7 +177,7 @@ devDependencies: version: 5.2.2 vite: specifier: ^4.4.9 - version: 4.4.9(@types/node@20.5.9) + version: 4.4.9(@types/node@20.6.0) vite-plugin-pages: specifier: ^0.31.0 version: 0.31.0(vite@4.4.9) @@ -225,20 +225,20 @@ packages: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} - /@babel/core@7.22.15: - resolution: {integrity: sha512-PtZqMmgRrvj8ruoEOIwVA3yoF91O+Hgw9o7DAUTNBA6Mo2jpu31clx9a7Nz/9JznqetTR6zwfC4L3LAjKQXUwA==} + /@babel/core@7.22.17: + resolution: {integrity: sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.22.13 '@babel/generator': 7.22.15 '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.22.15(@babel/core@7.22.15) + '@babel/helper-module-transforms': 7.22.17(@babel/core@7.22.17) '@babel/helpers': 7.22.15 - '@babel/parser': 7.22.15 + '@babel/parser': 7.22.16 '@babel/template': 7.22.15 - '@babel/traverse': 7.22.15 - '@babel/types': 7.22.15 + '@babel/traverse': 7.22.17 + '@babel/types': 7.22.17 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -247,16 +247,16 @@ packages: transitivePeerDependencies: - supports-color - /@babel/eslint-parser@7.22.15(@babel/core@7.22.15)(eslint@8.48.0): + /@babel/eslint-parser@7.22.15(@babel/core@7.22.17)(eslint@8.49.0): resolution: {integrity: sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': ^7.11.0 eslint: ^7.5.0 || ^8.0.0 dependencies: - '@babel/core': 7.22.15 + '@babel/core': 7.22.17 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.48.0 + eslint: 8.49.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: true @@ -274,7 +274,7 @@ packages: resolution: {integrity: sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.15 + '@babel/types': 7.22.17 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 @@ -317,15 +317,15 @@ packages: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.15 + '@babel/types': 7.22.17 - /@babel/helper-module-transforms@7.22.15(@babel/core@7.22.15): - resolution: {integrity: sha512-l1UiX4UyHSFsYt17iQ3Se5pQQZZHa22zyIXURmvkmLCD4t/aU+dvNWHatKac/D9Vm9UES7nvIqHs4jZqKviUmQ==} + /@babel/helper-module-transforms@7.22.17(@babel/core@7.22.17): + resolution: {integrity: sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.15 + '@babel/core': 7.22.17 '@babel/helper-environment-visitor': 7.22.5 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -341,7 +341,7 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.15 + '@babel/types': 7.22.17 /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} @@ -379,8 +379,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.22.15 - '@babel/types': 7.22.15 + '@babel/traverse': 7.22.17 + '@babel/types': 7.22.17 transitivePeerDependencies: - supports-color @@ -408,12 +408,12 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/parser@7.22.15: - resolution: {integrity: sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==} + /@babel/parser@7.22.16: + resolution: {integrity: sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.22.15 + '@babel/types': 7.22.17 /@babel/parser@7.22.7: resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==} @@ -422,23 +422,23 @@ packages: dependencies: '@babel/types': 7.22.5 - /@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.15): + /@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.17): resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.15 + '@babel/core': 7.22.17 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.15): + /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.17): resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.15 + '@babel/core': 7.22.17 '@babel/helper-plugin-utils': 7.22.5 dev: true @@ -461,8 +461,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.22.13 - '@babel/parser': 7.22.15 - '@babel/types': 7.22.15 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.17 /@babel/template@7.22.5: resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} @@ -490,8 +490,8 @@ packages: - supports-color dev: true - /@babel/traverse@7.22.15: - resolution: {integrity: sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==} + /@babel/traverse@7.22.17: + resolution: {integrity: sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.22.13 @@ -500,8 +500,8 @@ packages: '@babel/helper-function-name': 7.22.5 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.22.15 - '@babel/types': 7.22.15 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.17 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -524,8 +524,8 @@ packages: to-fast-properties: 2.0.0 dev: false - /@babel/types@7.22.15: - resolution: {integrity: sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==} + /@babel/types@7.22.17: + resolution: {integrity: sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.22.5 @@ -805,13 +805,13 @@ packages: requiresBuild: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.49.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.48.0 + eslint: 8.49.0 eslint-visitor-keys: 3.4.3 dev: true @@ -837,8 +837,8 @@ packages: - supports-color dev: true - /@eslint/js@8.48.0: - resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} + /@eslint/js@8.49.0: + resolution: {integrity: sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -1090,8 +1090,8 @@ packages: dev: false optional: true - /@marsidev/react-turnstile@0.3.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-TSBOtQ4w+kDXVGQOpbTbkw7cuaRXxiQr6WNuPassvzEc1V+FNPYRCx2cRZ/0lSGtdClSUvsyG9prueeDQ6uhuw==} + /@marsidev/react-turnstile@0.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XnpIUqufuZp2VoC14fmYztB2/8lSABh8eFG6TWAR7Loipdy0p2lZXzuvUOTcQl69j1XKvWu3WChFCBWx/Cbd1A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -1124,7 +1124,7 @@ packages: - utf-8-validate dev: false - /@nabla/vite-plugin-eslint@1.5.0(eslint@8.48.0)(vite@4.4.9): + /@nabla/vite-plugin-eslint@1.5.0(eslint@8.49.0)(vite@4.4.9): resolution: {integrity: sha512-3NR+mHcW4lY9n1t+cqM8W1xM/UQXKpuDyaoJmPPQKoBCEjFoSvE4XcJwG86lk7K0AauqWwecsgEhmdZLDW07YQ==} peerDependencies: eslint: '*' @@ -1132,8 +1132,8 @@ packages: dependencies: '@types/eslint': 8.40.0 chalk: 4.1.2 - eslint: 8.48.0 - vite: 4.4.9(@types/node@20.5.9) + eslint: 8.49.0 + vite: 4.4.9(@types/node@20.6.0) dev: true /@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1: @@ -1338,8 +1338,8 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/node@20.5.9: - resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==} + /@types/node@20.6.0: + resolution: {integrity: sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==} /@types/parse-json@4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} @@ -1376,7 +1376,7 @@ packages: resolution: {integrity: sha512-7yQiX6MWSFSvc/1wW5smJMZTZ4fHOd+hqLr3qr/HONDxHEa2bnYAsOcGBOEqFIjd4yetwMOdEDdeW+udRAQnHA==} dev: true - /@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.49.0)(typescript@5.2.2): resolution: {integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1388,13 +1388,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.6.0(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/scope-manager': 6.6.0 - '@typescript-eslint/type-utils': 6.6.0(eslint@8.48.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 6.6.0(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.6.0(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4 - eslint: 8.48.0 + eslint: 8.49.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -1405,7 +1405,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.6.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/parser@6.6.0(eslint@8.49.0)(typescript@5.2.2): resolution: {integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1420,7 +1420,7 @@ packages: '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4 - eslint: 8.48.0 + eslint: 8.49.0 typescript: 5.2.2 transitivePeerDependencies: - supports-color @@ -1434,7 +1434,7 @@ packages: '@typescript-eslint/visitor-keys': 6.6.0 dev: true - /@typescript-eslint/type-utils@6.6.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/type-utils@6.6.0(eslint@8.49.0)(typescript@5.2.2): resolution: {integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1445,9 +1445,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.6.0(eslint@8.49.0)(typescript@5.2.2) debug: 4.3.4 - eslint: 8.48.0 + eslint: 8.49.0 ts-api-utils: 1.0.2(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: @@ -1480,19 +1480,19 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@6.6.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/utils@6.6.0(eslint@8.49.0)(typescript@5.2.2): resolution: {integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.1 '@typescript-eslint/scope-manager': 6.6.0 '@typescript-eslint/types': 6.6.0 '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.2.2) - eslint: 8.48.0 + eslint: 8.49.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -1513,11 +1513,11 @@ packages: peerDependencies: vite: ^4.2.0 dependencies: - '@babel/core': 7.22.15 - '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.15) - '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.15) + '@babel/core': 7.22.17 + '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.17) + '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.17) react-refresh: 0.14.0 - vite: 4.4.9(@types/node@20.5.9) + vite: 4.4.9(@types/node@20.6.0) transitivePeerDependencies: - supports-color dev: true @@ -1687,8 +1687,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001527 - electron-to-chromium: 1.4.508 + caniuse-lite: 1.0.30001532 + electron-to-chromium: 1.4.513 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) @@ -1707,8 +1707,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - /caniuse-lite@1.0.30001527: - resolution: {integrity: sha512-YkJi7RwPgWtXVSgK4lG9AHH57nSzvvOp9MesgXmw4Q7n0C3H04L0foHqfxcmSAm5AcWb8dW9AYj2tR7/5GnddQ==} + /caniuse-lite@1.0.30001532: + resolution: {integrity: sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==} /canvas@2.11.2: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} @@ -1999,8 +1999,8 @@ packages: zrender: 5.4.4 dev: false - /electron-to-chromium@1.4.508: - resolution: {integrity: sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==} + /electron-to-chromium@1.4.513: + resolution: {integrity: sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==} /embla-carousel-autoplay@7.1.0(embla-carousel@7.1.0): resolution: {integrity: sha512-nYfgSGn3ek44OzwO0t/Ptuxq4PNPD5l7Y9X7JjLYI/DN1uGjqxz9L73YYqR6YCRDnTYJ88s9fep48dzBnSG4vQ==} @@ -2095,13 +2095,13 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - /eslint-plugin-react-hooks@4.6.0(eslint@8.48.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.49.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.48.0 + eslint: 8.49.0 dev: true /eslint-scope@5.1.1: @@ -2130,15 +2130,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.48.0: - resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} + /eslint@8.49.0: + resolution: {integrity: sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) '@eslint-community/regexpp': 4.8.0 '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.48.0 + '@eslint/js': 8.49.0 '@humanwhocodes/config-array': 0.11.11 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -2918,16 +2918,16 @@ packages: resolution: {integrity: sha512-JhvWq/iz1BvlmnPvLJjXv+xnMPJZuychrDC68V+yCGQJn5chcA8rLGKo5EP1XwIKVrigSXKLmbeXAGkf36wdCQ==} dev: false - /marked-highlight@2.0.5(marked@8.0.0): + /marked-highlight@2.0.5(marked@8.0.1): resolution: {integrity: sha512-SnMOy3LBe3ZMVyew7sO/wqAzBBSrLrOejeayP2bmnB00rrETtNyEvJkR5f3kDRYv5nT+ueEMba6XcGlmcyaN+A==} peerDependencies: marked: '>=4 <9' dependencies: - marked: 8.0.0 + marked: 8.0.1 dev: false - /marked@8.0.0: - resolution: {integrity: sha512-RI/D5csFVreNrFchdKFSdV38GDHJdD7OdmbNWYzGvApPb0A9pyypgfHC/FBH4ugmRE8cr7yg/TH7tu8585eMhA==} + /marked@8.0.1: + resolution: {integrity: sha512-eEbeEb/mJwh+sNLEhHOWtxMgjN/NEwZUBs1nkiIH2sTQTq07KmPMQ48ihyvo5+Ya56spVOPhunfGr6406crCVA==} engines: {node: '>= 16'} hasBin: true dev: false @@ -3571,8 +3571,8 @@ packages: dependencies: glob: 7.2.3 - /rollup@3.28.1: - resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==} + /rollup@3.29.0: + resolution: {integrity: sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -4073,7 +4073,7 @@ packages: json5: 2.2.3 local-pkg: 0.4.3 picocolors: 1.0.0 - vite: 4.4.9(@types/node@20.5.9) + vite: 4.4.9(@types/node@20.6.0) yaml: 2.3.1 transitivePeerDependencies: - supports-color @@ -4083,7 +4083,7 @@ packages: resolution: {integrity: sha512-mBPPMS/hwVUArdqCtp/oajZT7iq1qwJDDCciNZ3R5+Q5tQUuUHXtDKuZHYnklPLElNbENf2FyuOtC4FrgxQRAA==} engines: {node: '>=12.0.0'} dependencies: - '@babel/core': 7.22.15 + '@babel/core': 7.22.17 babel-plugin-prismjs: 2.1.0(prismjs@1.29.0) transitivePeerDependencies: - prismjs @@ -4099,7 +4099,7 @@ packages: clean-css: 5.3.2 flat-cache: 3.0.4 picocolors: 1.0.0 - vite: 4.4.9(@types/node@20.5.9) + vite: 4.4.9(@types/node@20.6.0) transitivePeerDependencies: - debug dev: true @@ -4115,13 +4115,13 @@ packages: debug: 4.3.4 globrex: 0.1.2 tsconfck: 2.1.1(typescript@5.2.2) - vite: 4.4.9(@types/node@20.5.9) + vite: 4.4.9(@types/node@20.6.0) transitivePeerDependencies: - supports-color - typescript dev: false - /vite@4.4.9(@types/node@20.5.9): + /vite@4.4.9(@types/node@20.6.0): resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -4149,10 +4149,10 @@ packages: terser: optional: true dependencies: - '@types/node': 20.5.9 + '@types/node': 20.6.0 esbuild: 0.18.19 postcss: 8.4.27 - rollup: 3.28.1 + rollup: 3.29.0 optionalDependencies: fsevents: 2.3.3 diff --git a/src/GZCTF/ClientApp/src/Api.ts b/src/GZCTF/ClientApp/src/Api.ts index 4ca08cf80..77e934188 100644 --- a/src/GZCTF/ClientApp/src/Api.ts +++ b/src/GZCTF/ClientApp/src/Api.ts @@ -844,6 +844,19 @@ export interface ChallengeEditDetailModel { flagTemplate?: string | null /** 是否启用题目 */ isEnabled: boolean + /** + * 通过人数 + * @format int32 + */ + acceptedCount: number + /** 统一文件名(仅用于动态附件) */ + fileName?: string | null + /** 题目附件(动态附件存放于 FlagInfoModel) */ + attachment?: Attachment | null + /** 测试容器 */ + testContainer?: ContainerInfoModel | null + /** 题目 Flag 信息 */ + flags: FlagInfoModel[] /** * 镜像名称与标签 * @minLength 1 @@ -856,7 +869,6 @@ export interface ChallengeEditDetailModel { memoryLimit: number /** * CPU 限制 (0.1 CPUs) - * * @format int32 */ cpuCount: number @@ -889,19 +901,6 @@ export interface ChallengeEditDetailModel { * @format double */ difficulty: number - /** - * 通过人数 - * @format int32 - */ - acceptedCount: number - /** 统一文件名(仅用于动态附件) */ - fileName?: string | null - /** 题目附件(动态附件存放于 FlagInfoModel) */ - attachment?: Attachment | null - /** 测试容器 */ - testContainer?: ContainerInfoModel | null - /** 题目 Flag 信息 */ - flags: FlagInfoModel[] } export enum ChallengeType { @@ -1023,6 +1022,8 @@ export interface ChallengeUpdateModel { hints?: string[] | null /** 是否启用题目 */ isEnabled?: boolean | null + /** 统一文件名 */ + fileName?: string | null /** 镜像名称与标签 */ containerImage?: string | null /** @@ -1070,8 +1071,6 @@ export interface ChallengeUpdateModel { * @format double */ difficulty?: number | null - /** 统一文件名 */ - fileName?: string | null } /** 新建附件信息(Edit) */ @@ -4177,13 +4176,13 @@ export class Api extends HttpClient + gameParticipation: (id: number, params: RequestParams = {}) => this.request({ - path: `/api/game/${id}/participations`, + path: `/api/game/${id}/participation`, method: 'GET', format: 'json', ...params, @@ -4192,13 +4191,13 @@ export class Api extends HttpClient + useGameParticipation: (id: number, options?: SWRConfiguration, doFetch: boolean = true) => useSWR( - doFetch ? `/api/game/${id}/participations` : null, + doFetch ? `/api/game/${id}/participation` : null, options ), @@ -4206,15 +4205,15 @@ export class Api extends HttpClient, options?: MutatorOptions - ) => mutate(`/api/game/${id}/participations`, data, options), + ) => mutate(`/api/game/${id}/participation`, data, options), /** * @description 延长容器时间,需要User权限,且只能在到期前十分钟延期两小时 diff --git a/src/GZCTF/ClientApp/src/App.tsx b/src/GZCTF/ClientApp/src/App.tsx index 245398ec3..1f21b4aa0 100644 --- a/src/GZCTF/ClientApp/src/App.tsx +++ b/src/GZCTF/ClientApp/src/App.tsx @@ -3,18 +3,18 @@ import routes from '~react-pages' import { FC, Suspense } from 'react' import { useRoutes } from 'react-router-dom' import { - MantineProvider, - Global, + Center, ColorScheme, ColorSchemeProvider, - Center, + Global, Loader, + MantineProvider, } from '@mantine/core' import { useLocalStorage } from '@mantine/hooks' import { ModalsProvider } from '@mantine/modals' import { Notifications } from '@mantine/notifications' import { ThemeOverride } from '@Utils/ThemeOverride' -import { useLocalStorageCache, useBanner } from '@Utils/useConfig' +import { useBanner, useLocalStorageCache } from '@Utils/useConfig' import { fetcher } from '@Api' export const App: FC = () => { diff --git a/src/GZCTF/ClientApp/src/components/AccountView.tsx b/src/GZCTF/ClientApp/src/components/AccountView.tsx index a619f930f..491b59f9f 100644 --- a/src/GZCTF/ClientApp/src/components/AccountView.tsx +++ b/src/GZCTF/ClientApp/src/components/AccountView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' import { useNavigate } from 'react-router-dom' -import { Stack, Center, createStyles } from '@mantine/core' +import { Center, createStyles, Stack } from '@mantine/core' import LogoHeader from '@Components/LogoHeader' const useStyles = createStyles(() => ({ diff --git a/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx b/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx index fd9acca96..e27205305 100644 --- a/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx +++ b/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx @@ -1,13 +1,13 @@ import { FC, useState } from 'react' import { + ActionIcon, + Button, + Group, MantineColor, + MantineNumberSize, Popover, - ActionIcon, Stack, - Group, - Button, Text, - MantineNumberSize, } from '@mantine/core' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/AppFooter.tsx b/src/GZCTF/ClientApp/src/components/AppFooter.tsx index f0e188591..2b7e8b6a1 100644 --- a/src/GZCTF/ClientApp/src/components/AppFooter.tsx +++ b/src/GZCTF/ClientApp/src/components/AppFooter.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { Text, Stack, Divider, Anchor, Center } from '@mantine/core' +import { Anchor, Center, Divider, Stack, Text } from '@mantine/core' import FooterRender from '@Components/FooterRender' import MainIcon from '@Components/icon/MainIcon' import { useFooterStyles, useIsMobile, useLogoStyles } from '@Utils/ThemeOverride' diff --git a/src/GZCTF/ClientApp/src/components/AppHeader.tsx b/src/GZCTF/ClientApp/src/components/AppHeader.tsx index 228423050..4be8a3cc5 100644 --- a/src/GZCTF/ClientApp/src/components/AppHeader.tsx +++ b/src/GZCTF/ClientApp/src/components/AppHeader.tsx @@ -2,12 +2,12 @@ import { FC, useState } from 'react' import { Link, useLocation, useNavigate } from 'react-router-dom' import { Burger, createStyles, Group, Header, Menu, useMantineColorScheme } from '@mantine/core' import { - mdiWeatherSunny, - mdiWeatherNight, mdiAccountCircleOutline, - mdiLogout, mdiAccountGroupOutline, mdiCached, + mdiLogout, + mdiWeatherNight, + mdiWeatherSunny, } from '@mdi/js' import { Icon } from '@mdi/react' import LogoHeader from '@Components/LogoHeader' diff --git a/src/GZCTF/ClientApp/src/components/AppNavbar.tsx b/src/GZCTF/ClientApp/src/components/AppNavbar.tsx index d9d931a13..3a6c24937 100644 --- a/src/GZCTF/ClientApp/src/components/AppNavbar.tsx +++ b/src/GZCTF/ClientApp/src/components/AppNavbar.tsx @@ -1,29 +1,29 @@ import React, { FC, useEffect, useState } from 'react' import { Link, useLocation, useNavigate } from 'react-router-dom' import { - Menu, - Stack, - Center, - Navbar, + ActionIcon, Avatar, - Tooltip, + Center, createStyles, getStylesRef, + Menu, + Navbar, + Stack, + Tooltip, useMantineColorScheme, - ActionIcon, } from '@mantine/core' import { mdiAccountCircleOutline, mdiAccountGroupOutline, + mdiCached, mdiFlagOutline, mdiHomeVariantOutline, mdiInformationOutline, - mdiWeatherSunny, - mdiWeatherNight, mdiLogout, - mdiWrenchOutline, mdiNoteTextOutline, - mdiCached, + mdiWeatherNight, + mdiWeatherSunny, + mdiWrenchOutline, } from '@mdi/js' import { Icon } from '@mdi/react' import MainIcon from '@Components/icon/MainIcon' diff --git a/src/GZCTF/ClientApp/src/components/ChallengeCard.tsx b/src/GZCTF/ClientApp/src/components/ChallengeCard.tsx index c2af6d6d5..dc13394e4 100644 --- a/src/GZCTF/ClientApp/src/components/ChallengeCard.tsx +++ b/src/GZCTF/ClientApp/src/components/ChallengeCard.tsx @@ -1,16 +1,16 @@ import dayjs from 'dayjs' import { FC } from 'react' import { + Box, Card, + createStyles, Divider, Group, - Tooltip, + keyframes, Stack, Text, Title, - createStyles, - keyframes, - Box, + Tooltip, } from '@mantine/core' import { mdiFlag } from '@mdi/js' import { Icon } from '@mdi/react' @@ -38,7 +38,12 @@ export const useStyles = createStyles((theme, { colorMap }: ChallengeCardProps) width: '70%', height: '200%', zIndex: 91, - animation: `${keyframes`0% {opacity: .3;} 100% {opacity: 1;}`} 2s linear 0s infinite alternate`, + animation: `${keyframes`0% { + opacity: .3; + } + 100% { + opacity: 1; + }`} 2s linear 0s infinite alternate`, }, blood1: { background: `linear-gradient(0deg, #fff0, ${colorMap.get(SubmissionType.FirstBlood)}, #fff0)`, diff --git a/src/GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx b/src/GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx index 39ba9d2ad..99aea07b7 100644 --- a/src/GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx +++ b/src/GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx @@ -1,5 +1,4 @@ -import { FC, useEffect, useState } from 'react' -import React from 'react' +import React, { FC, useEffect, useState } from 'react' import { ActionIcon, Box, diff --git a/src/GZCTF/ClientApp/src/components/CustomProgress.tsx b/src/GZCTF/ClientApp/src/components/CustomProgress.tsx index 996a0b7a0..267c67154 100644 --- a/src/GZCTF/ClientApp/src/components/CustomProgress.tsx +++ b/src/GZCTF/ClientApp/src/components/CustomProgress.tsx @@ -28,7 +28,12 @@ export const useStyles = createStyles( theme.colorScheme === 'dark' ? theme.colors.white[0] : theme.colors[_color][5], '& div': { - animation: `${keyframes`0% {opacity: .3;} 100% {opacity: 1;}`} 2s linear 0s infinite alternate`, + animation: `${keyframes`0% { + opacity: .3; + } + 100% { + opacity: 1; + }`} 2s linear 0s infinite alternate`, }, }, progressPulseContainer: { @@ -41,7 +46,17 @@ export const useStyles = createStyles( width: '25%', height: '100%', background: `linear-gradient(-90deg, ${spikeColor}, #fff0)`, - animation: `${keyframes`0% { width: 0%;} 80% {opacity: 1; width: 100%;} 100% {opacity: 0; width: 100%;}`} 2s linear 0s infinite normal`, + animation: `${keyframes`0% { + width: 0%; + } + 80% { + opacity: 1; + width: 100%; + } + 100% { + opacity: 0; + width: 100%; + }`} 2s linear 0s infinite normal`, }, }, progressBar: { diff --git a/src/GZCTF/ClientApp/src/components/FooterRender.tsx b/src/GZCTF/ClientApp/src/components/FooterRender.tsx index 090dc99fe..998ecb9c7 100644 --- a/src/GZCTF/ClientApp/src/components/FooterRender.tsx +++ b/src/GZCTF/ClientApp/src/components/FooterRender.tsx @@ -1,6 +1,6 @@ import { marked } from 'marked' import { forwardRef } from 'react' -import { TypographyStylesProvider, createStyles } from '@mantine/core' +import { createStyles, TypographyStylesProvider } from '@mantine/core' import { MarkdownProps } from '@Components/MarkdownRender' import { useIsMobile } from '@Utils/ThemeOverride' diff --git a/src/GZCTF/ClientApp/src/components/HintList.tsx b/src/GZCTF/ClientApp/src/components/HintList.tsx index 91f38bbbe..07d6b8704 100644 --- a/src/GZCTF/ClientApp/src/components/HintList.tsx +++ b/src/GZCTF/ClientApp/src/components/HintList.tsx @@ -1,12 +1,12 @@ import { FC } from 'react' import { - ScrollArea, + ActionIcon, + Button, Input, + ScrollArea, Stack, TextInput, TextInputProps, - Button, - ActionIcon, } from '@mantine/core' import { mdiClose, mdiPlus } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/InstanceEntry.tsx b/src/GZCTF/ClientApp/src/components/InstanceEntry.tsx index f1d390fee..b8b7b09d9 100644 --- a/src/GZCTF/ClientApp/src/components/InstanceEntry.tsx +++ b/src/GZCTF/ClientApp/src/components/InstanceEntry.tsx @@ -2,25 +2,25 @@ import dayjs from 'dayjs' import duration from 'dayjs/plugin/duration' import { FC, useEffect, useState } from 'react' import { - Stack, - Text, + ActionIcon, + Anchor, Button, + Divider, Group, - Tooltip, - Anchor, + Stack, + Text, TextInput, - ActionIcon, - Divider, + Tooltip, } from '@mantine/core' import { useClipboard } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' import { mdiCheck, - mdiServerNetwork, mdiContentCopy, - mdiOpenInNew, - mdiOpenInApp, mdiExclamation, + mdiOpenInApp, + mdiOpenInNew, + mdiServerNetwork, } from '@mdi/js' import { Icon } from '@mdi/react' import { getProxyUrl } from '@Utils/Shared' diff --git a/src/GZCTF/ClientApp/src/components/LogoHeader.tsx b/src/GZCTF/ClientApp/src/components/LogoHeader.tsx index d73e3f898..379f77d14 100644 --- a/src/GZCTF/ClientApp/src/components/LogoHeader.tsx +++ b/src/GZCTF/ClientApp/src/components/LogoHeader.tsx @@ -1,5 +1,5 @@ import { forwardRef } from 'react' -import { Group, Title, createStyles, GroupProps } from '@mantine/core' +import { createStyles, Group, GroupProps, Title } from '@mantine/core' import MainIcon from '@Components/icon/MainIcon' import { useConfig } from '@Utils/useConfig' diff --git a/src/GZCTF/ClientApp/src/components/MobilePostCard.tsx b/src/GZCTF/ClientApp/src/components/MobilePostCard.tsx index aedd02ff7..d81a63950 100644 --- a/src/GZCTF/ClientApp/src/components/MobilePostCard.tsx +++ b/src/GZCTF/ClientApp/src/components/MobilePostCard.tsx @@ -1,7 +1,7 @@ import dayjs from 'dayjs' import { FC, useState } from 'react' import { useNavigate } from 'react-router-dom' -import { Group, Card, Title, Text, Stack, ActionIcon, Box, Avatar } from '@mantine/core' +import { ActionIcon, Avatar, Box, Card, Group, Stack, Text, Title } from '@mantine/core' import { mdiPencilOutline, mdiPinOffOutline, mdiPinOutline } from '@mdi/js' import { Icon } from '@mdi/react' import MarkdownRender from '@Components/MarkdownRender' diff --git a/src/GZCTF/ClientApp/src/components/MobileScoreboardItemModal.tsx b/src/GZCTF/ClientApp/src/components/MobileScoreboardItemModal.tsx index cbbdfbc9f..2ba106e99 100644 --- a/src/GZCTF/ClientApp/src/components/MobileScoreboardItemModal.tsx +++ b/src/GZCTF/ClientApp/src/components/MobileScoreboardItemModal.tsx @@ -1,20 +1,20 @@ import dayjs from 'dayjs' import { FC } from 'react' import { + Avatar, + Badge, + Center, Group, - Text, + Input, + LoadingOverlay, Modal, ModalProps, + Progress, ScrollArea, Stack, Table, - Progress, - Center, - LoadingOverlay, - Avatar, + Text, Title, - Badge, - Input, } from '@mantine/core' import TeamRadarMap from '@Components/TeamRadarMap' import { BonusLabel } from '@Utils/Shared' diff --git a/src/GZCTF/ClientApp/src/components/MobileScoreboardTable.tsx b/src/GZCTF/ClientApp/src/components/MobileScoreboardTable.tsx index 78a8516bc..9f69b5a43 100644 --- a/src/GZCTF/ClientApp/src/components/MobileScoreboardTable.tsx +++ b/src/GZCTF/ClientApp/src/components/MobileScoreboardTable.tsx @@ -1,6 +1,6 @@ import React, { FC, useEffect, useState } from 'react' import { useParams } from 'react-router-dom' -import { Paper, Table, Group, Avatar, Box, Stack, Pagination, Select, Input } from '@mantine/core' +import { Avatar, Box, Group, Input, Pagination, Paper, Select, Stack, Table } from '@mantine/core' import MobileScoreboardItemModal from '@Components/MobileScoreboardItemModal' import { ScoreboardProps, useScoreboardStyles } from '@Components/ScoreboardTable' import { BloodBonus } from '@Utils/Shared' diff --git a/src/GZCTF/ClientApp/src/components/PostCard.tsx b/src/GZCTF/ClientApp/src/components/PostCard.tsx index 47ab42c21..95d35042c 100644 --- a/src/GZCTF/ClientApp/src/components/PostCard.tsx +++ b/src/GZCTF/ClientApp/src/components/PostCard.tsx @@ -2,15 +2,15 @@ import dayjs from 'dayjs' import { FC, useState } from 'react' import { Link, useNavigate } from 'react-router-dom' import { - Group, - Card, + ActionIcon, + Anchor, + Avatar, Blockquote, - Title, - Text, + Card, + Group, Stack, - Avatar, - Anchor, - ActionIcon, + Text, + Title, useMantineTheme, } from '@mantine/core' import { mdiPencilOutline, mdiPinOffOutline, mdiPinOutline } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/components/RecentGameSlide.tsx b/src/GZCTF/ClientApp/src/components/RecentGameSlide.tsx index 9d48c0126..77a5f47d9 100644 --- a/src/GZCTF/ClientApp/src/components/RecentGameSlide.tsx +++ b/src/GZCTF/ClientApp/src/components/RecentGameSlide.tsx @@ -1,7 +1,7 @@ import dayjs from 'dayjs' import { FC } from 'react' import { Link } from 'react-router-dom' -import { Badge, Group, Stack, Title, createStyles, Paper } from '@mantine/core' +import { Badge, createStyles, Group, Paper, Stack, Title } from '@mantine/core' import { GameColorMap, GameStatus } from '@Components/GameCard' import { RecentGameProps } from '@Components/RecentGame' import { getGameStatus } from '@Utils/useGame' diff --git a/src/GZCTF/ClientApp/src/components/ScoreboardItemModal.tsx b/src/GZCTF/ClientApp/src/components/ScoreboardItemModal.tsx index 890e86530..7e3650649 100644 --- a/src/GZCTF/ClientApp/src/components/ScoreboardItemModal.tsx +++ b/src/GZCTF/ClientApp/src/components/ScoreboardItemModal.tsx @@ -1,19 +1,19 @@ import dayjs from 'dayjs' import { FC } from 'react' import { + Avatar, + Badge, + Center, Group, - Text, + LoadingOverlay, Modal, ModalProps, + Progress, ScrollArea, Stack, Table, - Progress, - Center, - LoadingOverlay, - Avatar, + Text, Title, - Badge, } from '@mantine/core' import TeamRadarMap from '@Components/TeamRadarMap' import { BloodsTypes, BonusLabel } from '@Utils/Shared' diff --git a/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx b/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx index ff08268b1..5ecb94b1f 100644 --- a/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx +++ b/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx @@ -2,19 +2,19 @@ import dayjs from 'dayjs' import React, { FC, useEffect, useState } from 'react' import { useParams } from 'react-router-dom' import { - Paper, - createStyles, - Table, - Group, - Text, Avatar, Box, - Stack, + Center, + createStyles, + Group, + Input, Pagination, + Paper, Select, + Stack, + Table, + Text, Tooltip, - Center, - Input, } from '@mantine/core' import { Icon } from '@mdi/react' import ScoreboardItemModal from '@Components/ScoreboardItemModal' diff --git a/src/GZCTF/ClientApp/src/components/ScrollSelect.tsx b/src/GZCTF/ClientApp/src/components/ScrollSelect.tsx index 48a0e22ad..a782b3962 100644 --- a/src/GZCTF/ClientApp/src/components/ScrollSelect.tsx +++ b/src/GZCTF/ClientApp/src/components/ScrollSelect.tsx @@ -1,11 +1,11 @@ import { FC, forwardRef } from 'react' import { - ScrollAreaProps, - ScrollArea, Center, - Stack, createStyles, rem, + ScrollArea, + ScrollAreaProps, + Stack, UnstyledButton, UnstyledButtonProps, } from '@mantine/core' diff --git a/src/GZCTF/ClientApp/src/components/StickyHeader.tsx b/src/GZCTF/ClientApp/src/components/StickyHeader.tsx index 2028aea89..bf9ea7caa 100644 --- a/src/GZCTF/ClientApp/src/components/StickyHeader.tsx +++ b/src/GZCTF/ClientApp/src/components/StickyHeader.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { Group, Title, Text, createStyles, keyframes } from '@mantine/core' +import { createStyles, Group, keyframes, Text, Title } from '@mantine/core' import LogoHeader from '@Components/LogoHeader' import { useConfig } from '@Utils/useConfig' @@ -25,7 +25,12 @@ const useStyles = createStyles((theme) => ({ }, }, blink: { - animation: `${keyframes`0%, 100% {opacity:0;} 50% {opacity:1;}`} 1s infinite steps(1,start)`, + animation: `${keyframes`0%, 100% { + opacity: 0; + } + 50% { + opacity: 1; + }`} 1s infinite steps(1,start)`, }, subtitle: { fontFamily: theme.fontFamilyMonospace, diff --git a/src/GZCTF/ClientApp/src/components/StrengthPasswordInput.tsx b/src/GZCTF/ClientApp/src/components/StrengthPasswordInput.tsx index d6453c9ef..ea6289e7e 100644 --- a/src/GZCTF/ClientApp/src/components/StrengthPasswordInput.tsx +++ b/src/GZCTF/ClientApp/src/components/StrengthPasswordInput.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { Text, Box, Center, PasswordInput, Popover, Progress } from '@mantine/core' +import { Box, Center, PasswordInput, Popover, Progress, Text } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { mdiCheck, mdiClose } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/TeamCard.tsx b/src/GZCTF/ClientApp/src/components/TeamCard.tsx index 64852ae70..dea293c77 100644 --- a/src/GZCTF/ClientApp/src/components/TeamCard.tsx +++ b/src/GZCTF/ClientApp/src/components/TeamCard.tsx @@ -1,14 +1,14 @@ import { FC } from 'react' import { - Group, - Title, - Text, - Divider, Avatar, Badge, + Box, Card, + Divider, + Group, Stack, - Box, + Text, + Title, Tooltip, } from '@mantine/core' import { mdiLockOutline } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/components/TeamCreateModal.tsx b/src/GZCTF/ClientApp/src/components/TeamCreateModal.tsx index 5228d2d90..125473876 100644 --- a/src/GZCTF/ClientApp/src/components/TeamCreateModal.tsx +++ b/src/GZCTF/ClientApp/src/components/TeamCreateModal.tsx @@ -1,18 +1,18 @@ import { FC, useState } from 'react' import { Button, + Center, Modal, ModalProps, Stack, + Text, Textarea, TextInput, - Text, Title, - Center, useMantineTheme, } from '@mantine/core' import { showNotification } from '@mantine/notifications' -import { mdiCloseCircle, mdiCheck } from '@mdi/js' +import { mdiCheck, mdiCloseCircle } from '@mdi/js' import { Icon } from '@mdi/react' import { showErrorNotification } from '@Utils/ApiErrorHandler' import api, { TeamUpdateModel } from '@Api' diff --git a/src/GZCTF/ClientApp/src/components/TeamEditModal.tsx b/src/GZCTF/ClientApp/src/components/TeamEditModal.tsx index 52b4734b0..22c7c0d8f 100644 --- a/src/GZCTF/ClientApp/src/components/TeamEditModal.tsx +++ b/src/GZCTF/ClientApp/src/components/TeamEditModal.tsx @@ -1,5 +1,6 @@ import { FC, useEffect, useState } from 'react' import { + ActionIcon, Avatar, Box, Button, @@ -9,20 +10,19 @@ import { Image, Modal, ModalProps, + PasswordInput, + ScrollArea, Stack, Text, Textarea, TextInput, - useMantineTheme, - PasswordInput, - ActionIcon, - ScrollArea, Tooltip, + useMantineTheme, } from '@mantine/core' import { Dropzone } from '@mantine/dropzone' import { useClipboard } from '@mantine/hooks' import { useModals } from '@mantine/modals' -import { showNotification, updateNotification, notifications } from '@mantine/notifications' +import { notifications, showNotification, updateNotification } from '@mantine/notifications' import { mdiCheck, mdiClose, mdiRefresh, mdiStar } from '@mdi/js' import { Icon } from '@mdi/react' import { showErrorNotification, tryGetErrorMsg } from '@Utils/ApiErrorHandler' diff --git a/src/GZCTF/ClientApp/src/components/TeamRank.tsx b/src/GZCTF/ClientApp/src/components/TeamRank.tsx index 0f943d908..c2a262b5a 100644 --- a/src/GZCTF/ClientApp/src/components/TeamRank.tsx +++ b/src/GZCTF/ClientApp/src/components/TeamRank.tsx @@ -2,17 +2,17 @@ import { FC, useEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Avatar, - Group, + Badge, Card, - Stack, - Title, - Text, - PaperProps, createStyles, + Group, + PaperProps, + PasswordInput, Progress, Skeleton, - PasswordInput, - Badge, + Stack, + Text, + Title, } from '@mantine/core' import { useClipboard } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/components/TrafficItems.tsx b/src/GZCTF/ClientApp/src/components/TrafficItems.tsx index 56c139e6a..b8f7d636c 100644 --- a/src/GZCTF/ClientApp/src/components/TrafficItems.tsx +++ b/src/GZCTF/ClientApp/src/components/TrafficItems.tsx @@ -1,15 +1,15 @@ import dayjs from 'dayjs' -import { Avatar, Badge, Group, Stack, Text, rem, useMantineTheme } from '@mantine/core' +import { Avatar, Badge, Group, rem, Stack, Text, useMantineTheme } from '@mantine/core' import { mdiFileDownloadOutline, mdiMenuRight } from '@mdi/js' import { Icon } from '@mdi/react' import { SelectableItem, SelectableItemComponent } from '@Components/ScrollSelect' import { ChallengeTagLabelMap, HunamizeSize } from '@Utils/Shared' import { - ChallengeTrafficModel, - TeamTrafficModel, - FileRecord, ChallengeTag, + ChallengeTrafficModel, ChallengeType, + FileRecord, + TeamTrafficModel, } from '@Api' const itemHeight = rem(60) diff --git a/src/GZCTF/ClientApp/src/components/WithGameMonitor.tsx b/src/GZCTF/ClientApp/src/components/WithGameMonitor.tsx index 84bcda10e..c3673bf87 100644 --- a/src/GZCTF/ClientApp/src/components/WithGameMonitor.tsx +++ b/src/GZCTF/ClientApp/src/components/WithGameMonitor.tsx @@ -2,10 +2,10 @@ import React, { FC, useEffect, useState } from 'react' import { useLocation, useNavigate, useParams } from 'react-router-dom' import { Button, Group, LoadingOverlay, Stack, Tabs, useMantineTheme } from '@mantine/core' import { + mdiExclamationThick, mdiFileTableOutline, mdiFlag, mdiLightningBolt, - mdiExclamationThick, mdiPackageVariant, } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/WithGameTab.tsx b/src/GZCTF/ClientApp/src/components/WithGameTab.tsx index cc64c4a8c..46dcab037 100644 --- a/src/GZCTF/ClientApp/src/components/WithGameTab.tsx +++ b/src/GZCTF/ClientApp/src/components/WithGameTab.tsx @@ -2,9 +2,9 @@ import dayjs from 'dayjs' import duration from 'dayjs/plugin/duration' import React, { FC, useEffect, useState } from 'react' import { useLocation, useNavigate, useParams } from 'react-router-dom' -import { Card, Stack, Title, Text, LoadingOverlay, useMantineTheme } from '@mantine/core' +import { Card, LoadingOverlay, Stack, Text, Title, useMantineTheme } from '@mantine/core' import { showNotification } from '@mantine/notifications' -import { mdiFlagOutline, mdiMonitorEye, mdiChartLine, mdiExclamationThick } from '@mdi/js' +import { mdiChartLine, mdiExclamationThick, mdiFlagOutline, mdiMonitorEye } from '@mdi/js' import { Icon } from '@mdi/react' import CustomProgress from '@Components/CustomProgress' import IconTabs from '@Components/IconTabs' diff --git a/src/GZCTF/ClientApp/src/components/WithRole.tsx b/src/GZCTF/ClientApp/src/components/WithRole.tsx index 9b3d53d4e..9f26b8679 100644 --- a/src/GZCTF/ClientApp/src/components/WithRole.tsx +++ b/src/GZCTF/ClientApp/src/components/WithRole.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { Center, Loader } from '@mantine/core' import { useUserRole } from '@Utils/useUser' import { Role } from '@Api' diff --git a/src/GZCTF/ClientApp/src/components/WithWiderScreen.tsx b/src/GZCTF/ClientApp/src/components/WithWiderScreen.tsx index e40f1ee4b..2309211cc 100644 --- a/src/GZCTF/ClientApp/src/components/WithWiderScreen.tsx +++ b/src/GZCTF/ClientApp/src/components/WithWiderScreen.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { Stack, Title, Text } from '@mantine/core' +import { Stack, Text, Title } from '@mantine/core' import { useViewportSize } from '@mantine/hooks' import IconWiderScreenRequired from '@Components/icon/WiderScreenRequiredIcon' diff --git a/src/GZCTF/ClientApp/src/components/admin/AdminPage.tsx b/src/GZCTF/ClientApp/src/components/admin/AdminPage.tsx index f0a2d87aa..aa8bb6455 100644 --- a/src/GZCTF/ClientApp/src/components/admin/AdminPage.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/AdminPage.tsx @@ -1,8 +1,7 @@ import React, { FC } from 'react' import WithNavBar from '@Components/WithNavbar' import WithRole from '@Components/WithRole' -import WithAdminTab from '@Components/admin/WithAdminTab' -import { AdminTabProps } from '@Components/admin/WithAdminTab' +import WithAdminTab, { AdminTabProps } from '@Components/admin/WithAdminTab' import { Role } from '@Api' const AdminPage: FC = (props) => { diff --git a/src/GZCTF/ClientApp/src/components/admin/AttachmentRemoteEditModal.tsx b/src/GZCTF/ClientApp/src/components/admin/AttachmentRemoteEditModal.tsx index 9625839f3..c281c9526 100644 --- a/src/GZCTF/ClientApp/src/components/admin/AttachmentRemoteEditModal.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/AttachmentRemoteEditModal.tsx @@ -1,6 +1,6 @@ import { FC, useEffect, useState } from 'react' import { useParams } from 'react-router-dom' -import { Button, Modal, Text, Stack, Textarea, useMantineTheme, ModalProps } from '@mantine/core' +import { Button, Modal, ModalProps, Stack, Text, Textarea, useMantineTheme } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiCheck } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/admin/AttachmentUploadModal.tsx b/src/GZCTF/ClientApp/src/components/admin/AttachmentUploadModal.tsx index 2f045fe54..3b0fa323c 100644 --- a/src/GZCTF/ClientApp/src/components/admin/AttachmentUploadModal.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/AttachmentUploadModal.tsx @@ -1,20 +1,20 @@ import { FC, useState } from 'react' import { useParams } from 'react-router-dom' import { + ActionIcon, Button, + Card, + Center, FileButton, + Group, Modal, ModalProps, + Overlay, Progress, - Text, - Stack, ScrollArea, - Group, - ActionIcon, - Overlay, - Center, + Stack, + Text, Title, - Card, } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/components/admin/ChallengeEditCard.tsx b/src/GZCTF/ClientApp/src/components/admin/ChallengeEditCard.tsx index 75ababaf0..68ba73474 100644 --- a/src/GZCTF/ClientApp/src/components/admin/ChallengeEditCard.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/ChallengeEditCard.tsx @@ -1,15 +1,15 @@ import { Dispatch, FC, SetStateAction, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { + ActionIcon, + Badge, Card, Group, - Switch, Progress, - Badge, - ActionIcon, + Switch, Text, - useMantineTheme, Tooltip, + useMantineTheme, } from '@mantine/core' import { mdiDatabaseEditOutline, mdiPuzzleEditOutline } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/components/admin/ChallengePreviewModal.tsx b/src/GZCTF/ClientApp/src/components/admin/ChallengePreviewModal.tsx index 18d96f2fa..f71e5987e 100644 --- a/src/GZCTF/ClientApp/src/components/admin/ChallengePreviewModal.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/ChallengePreviewModal.tsx @@ -1,6 +1,5 @@ import dayjs from 'dayjs' -import { FC, useEffect, useState } from 'react' -import React from 'react' +import React, { FC, useEffect, useState } from 'react' import { ActionIcon, Box, diff --git a/src/GZCTF/ClientApp/src/components/admin/FlagEditPanel.tsx b/src/GZCTF/ClientApp/src/components/admin/FlagEditPanel.tsx index 258bd8d4c..c3524440b 100644 --- a/src/GZCTF/ClientApp/src/components/admin/FlagEditPanel.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/FlagEditPanel.tsx @@ -1,13 +1,13 @@ import { FC } from 'react' import { ActionIcon, + Card, Group, + Input, + SimpleGrid, Stack, Text, - Card, useMantineTheme, - SimpleGrid, - Input, } from '@mantine/core' import { useClipboard } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/components/admin/GameNoticeEditCard.tsx b/src/GZCTF/ClientApp/src/components/admin/GameNoticeEditCard.tsx index aaf3189e5..6c63af368 100644 --- a/src/GZCTF/ClientApp/src/components/admin/GameNoticeEditCard.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/GameNoticeEditCard.tsx @@ -1,7 +1,7 @@ import dayjs from 'dayjs' import { FC } from 'react' -import { ActionIcon, Group, Card, PaperProps, Stack, Text } from '@mantine/core' -import { mdiPencilOutline, mdiDeleteOutline } from '@mdi/js' +import { ActionIcon, Card, Group, PaperProps, Stack, Text } from '@mantine/core' +import { mdiDeleteOutline, mdiPencilOutline } from '@mdi/js' import { Icon } from '@mdi/react' import { InlineMarkdownRender } from '@Components/MarkdownRender' import { GameNotice } from '@Api' diff --git a/src/GZCTF/ClientApp/src/components/admin/PostEditCard.tsx b/src/GZCTF/ClientApp/src/components/admin/PostEditCard.tsx index 7f9248512..bd7bc4224 100644 --- a/src/GZCTF/ClientApp/src/components/admin/PostEditCard.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/PostEditCard.tsx @@ -1,15 +1,15 @@ import { FC } from 'react' import { ActionIcon, - Group, - Stack, Badge, Card, - Title, + Group, PaperProps, + Stack, + Title, useMantineTheme, } from '@mantine/core' -import { mdiPinOffOutline, mdiPinOutline, mdiDeleteOutline, mdiPencilOutline } from '@mdi/js' +import { mdiDeleteOutline, mdiPencilOutline, mdiPinOffOutline, mdiPinOutline } from '@mdi/js' import { Icon } from '@mdi/react' import MarkdownRender from '@Components/MarkdownRender' import { PostInfoModel } from '@Api' diff --git a/src/GZCTF/ClientApp/src/components/admin/TeamEditModal.tsx b/src/GZCTF/ClientApp/src/components/admin/TeamEditModal.tsx index 5c4c2c309..72c8ba409 100644 --- a/src/GZCTF/ClientApp/src/components/admin/TeamEditModal.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/TeamEditModal.tsx @@ -1,24 +1,24 @@ import { FC, useEffect, useState } from 'react' import { Avatar, - Text, Button, Center, Grid, Group, Modal, ModalProps, + ScrollArea, Stack, + Text, Textarea, TextInput, - ScrollArea, useMantineTheme, } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiCheck, mdiLockOutline, mdiStar } from '@mdi/js' import { Icon } from '@mdi/react' import { showErrorNotification } from '@Utils/ApiErrorHandler' -import api, { TeamInfoModel, AdminTeamModel } from '@Api' +import api, { AdminTeamModel, TeamInfoModel } from '@Api' interface TeamEditModalProps extends ModalProps { team: TeamInfoModel diff --git a/src/GZCTF/ClientApp/src/components/admin/UserEditModal.tsx b/src/GZCTF/ClientApp/src/components/admin/UserEditModal.tsx index a012add0b..5033916be 100644 --- a/src/GZCTF/ClientApp/src/components/admin/UserEditModal.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/UserEditModal.tsx @@ -2,7 +2,6 @@ import dayjs from 'dayjs' import { FC, useEffect, useState } from 'react' import { Avatar, - Text, Button, Center, Grid, @@ -13,6 +12,7 @@ import { SegmentedControl, SimpleGrid, Stack, + Text, Textarea, TextInput, useMantineTheme, @@ -22,7 +22,7 @@ import { mdiCheck } from '@mdi/js' import { Icon } from '@mdi/react' import { showErrorNotification } from '@Utils/ApiErrorHandler' import { useUser } from '@Utils/useUser' -import api, { UserInfoModel, AdminUserInfoModel, Role } from '@Api' +import api, { AdminUserInfoModel, Role, UserInfoModel } from '@Api' export const RoleColorMap = new Map([ [Role.Admin, 'blue'], diff --git a/src/GZCTF/ClientApp/src/components/admin/WithAdminTab.tsx b/src/GZCTF/ClientApp/src/components/admin/WithAdminTab.tsx index 72f82df2d..97e361480 100644 --- a/src/GZCTF/ClientApp/src/components/admin/WithAdminTab.tsx +++ b/src/GZCTF/ClientApp/src/components/admin/WithAdminTab.tsx @@ -3,11 +3,11 @@ import { useLocation, useNavigate } from 'react-router-dom' import { Group, GroupProps, LoadingOverlay, Stack, useMantineTheme } from '@mantine/core' import { mdiAccountCogOutline, - mdiFlagOutline, mdiAccountGroupOutline, mdiFileDocumentOutline, - mdiSitemapOutline, + mdiFlagOutline, mdiPackageVariantClosed, + mdiSitemapOutline, } from '@mdi/js' import { Icon } from '@mdi/react' import IconTabs from '@Components/IconTabs' diff --git a/src/GZCTF/ClientApp/src/components/icon/MainIcon.tsx b/src/GZCTF/ClientApp/src/components/icon/MainIcon.tsx index 909bb1d7b..8d7b42b3d 100644 --- a/src/GZCTF/ClientApp/src/components/icon/MainIcon.tsx +++ b/src/GZCTF/ClientApp/src/components/icon/MainIcon.tsx @@ -1,4 +1,4 @@ -import { SVGProps, FC } from 'react' +import { FC, SVGProps } from 'react' import { createStyles } from '@mantine/core' const useStyles = createStyles((theme) => ({ diff --git a/src/GZCTF/ClientApp/src/mantine.d.ts b/src/GZCTF/ClientApp/src/mantine.d.ts index 5185d9fd1..8cd13c571 100644 --- a/src/GZCTF/ClientApp/src/mantine.d.ts +++ b/src/GZCTF/ClientApp/src/mantine.d.ts @@ -1,4 +1,4 @@ -import { Tuple, DefaultMantineColor } from '@mantine/core' +import { DefaultMantineColor, Tuple } from '@mantine/core' type ExtendedCustomColors = 'gray' | 'brand' | 'dark' | 'alert' | 'white' | DefaultMantineColor diff --git a/src/GZCTF/ClientApp/src/pages/About.tsx b/src/GZCTF/ClientApp/src/pages/About.tsx index ce3bcec2c..9bfdcf3c0 100644 --- a/src/GZCTF/ClientApp/src/pages/About.tsx +++ b/src/GZCTF/ClientApp/src/pages/About.tsx @@ -1,9 +1,9 @@ import { FC } from 'react' -import { Text, Stack, Badge, Group, HoverCard, Title, Anchor, Center } from '@mantine/core' +import { Anchor, Badge, Center, Group, HoverCard, Stack, Text, Title } from '@mantine/core' import WithNavBar from '@Components/WithNavbar' import MainIcon from '@Components/icon/MainIcon' import { useLogoStyles } from '@Utils/ThemeOverride' -import { ValidatedRepoMeta, useConfig } from '@Utils/useConfig' +import { useConfig, ValidatedRepoMeta } from '@Utils/useConfig' import { usePageTitle } from '@Utils/usePageTitle' const About: FC = () => { diff --git a/src/GZCTF/ClientApp/src/pages/Teams.tsx b/src/GZCTF/ClientApp/src/pages/Teams.tsx index cc47d4735..cf3780a56 100644 --- a/src/GZCTF/ClientApp/src/pages/Teams.tsx +++ b/src/GZCTF/ClientApp/src/pages/Teams.tsx @@ -1,16 +1,16 @@ import { FC, useState } from 'react' import { - Stack, - SimpleGrid, - Loader, + Button, Center, Group, - Button, + Loader, Modal, - TextInput, + SimpleGrid, + Stack, Text, - useMantineTheme, + TextInput, Title, + useMantineTheme, } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiAccountMultiplePlus, mdiCheck, mdiClose, mdiHumanGreetingVariant } from '@mdi/js' @@ -25,7 +25,7 @@ import { showErrorNotification } from '@Utils/ApiErrorHandler' import { useIsMobile } from '@Utils/ThemeOverride' import { usePageTitle } from '@Utils/usePageTitle' import { useTeams, useUser } from '@Utils/useUser' -import api, { TeamInfoModel, Role } from '@Api' +import api, { Role, TeamInfoModel } from '@Api' const Teams: FC = () => { const { user, error: userError } = useUser() diff --git a/src/GZCTF/ClientApp/src/pages/[...all].tsx b/src/GZCTF/ClientApp/src/pages/[...all].tsx index 616952ca3..9ab40aab1 100644 --- a/src/GZCTF/ClientApp/src/pages/[...all].tsx +++ b/src/GZCTF/ClientApp/src/pages/[...all].tsx @@ -1,6 +1,6 @@ import { FC, useEffect } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' -import { Stack, Title, Text } from '@mantine/core' +import { useLocation, useNavigate } from 'react-router-dom' +import { Stack, Text, Title } from '@mantine/core' import WithNavBar from '@Components/WithNavbar' import Icon404 from '@Components/icon/404Icon' import { usePageTitle } from '@Utils/usePageTitle' diff --git a/src/GZCTF/ClientApp/src/pages/account/Confirm.tsx b/src/GZCTF/ClientApp/src/pages/account/Confirm.tsx index 12ebee1b6..5f0479a1f 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Confirm.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Confirm.tsx @@ -1,5 +1,5 @@ import { FC, useState } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { Button, Text } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/account/Login.tsx b/src/GZCTF/ClientApp/src/pages/account/Login.tsx index fe53958bb..ea00446e1 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Login.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Login.tsx @@ -1,6 +1,6 @@ import { FC, useEffect, useState } from 'react' import { Link, useNavigate, useSearchParams } from 'react-router-dom' -import { PasswordInput, Grid, TextInput, Button, Anchor } from '@mantine/core' +import { Anchor, Button, Grid, PasswordInput, TextInput } from '@mantine/core' import { useInputState } from '@mantine/hooks' import { showNotification, updateNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/account/Profile.tsx b/src/GZCTF/ClientApp/src/pages/account/Profile.tsx index ed72b213b..d2dc95215 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Profile.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Profile.tsx @@ -1,20 +1,20 @@ import { FC, useEffect, useState } from 'react' import { + Avatar, Box, - Stack, - Group, - Divider, - Text, Button, + Center, + Divider, Grid, - TextInput, - Paper, - Textarea, - Modal, - Avatar, + Group, Image, - Center, + Modal, + Paper, SimpleGrid, + Stack, + Text, + Textarea, + TextInput, Title, } from '@mantine/core' import { Dropzone } from '@mantine/dropzone' diff --git a/src/GZCTF/ClientApp/src/pages/account/Recovery.tsx b/src/GZCTF/ClientApp/src/pages/account/Recovery.tsx index f8844dcc4..e83377da3 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Recovery.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Recovery.tsx @@ -1,6 +1,6 @@ import { FC, useState } from 'react' import { Link } from 'react-router-dom' -import { TextInput, Button, Anchor } from '@mantine/core' +import { Anchor, Button, TextInput } from '@mantine/core' import { useInputState } from '@mantine/hooks' import { showNotification, updateNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/account/Register.tsx b/src/GZCTF/ClientApp/src/pages/account/Register.tsx index 5acbe52a4..f41ed3fe2 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Register.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Register.tsx @@ -1,6 +1,6 @@ import { FC, useState } from 'react' import { Link, useNavigate } from 'react-router-dom' -import { Button, Anchor, TextInput, PasswordInput } from '@mantine/core' +import { Anchor, Button, PasswordInput, TextInput } from '@mantine/core' import { useInputState } from '@mantine/hooks' import { showNotification, updateNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/account/Reset.tsx b/src/GZCTF/ClientApp/src/pages/account/Reset.tsx index df3a9349b..7f4256f08 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Reset.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Reset.tsx @@ -1,5 +1,5 @@ import { FC, useState } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { Button, PasswordInput } from '@mantine/core' import { getHotkeyHandler, useInputState } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/pages/account/Verify.tsx b/src/GZCTF/ClientApp/src/pages/account/Verify.tsx index 85ced5aac..70328c561 100644 --- a/src/GZCTF/ClientApp/src/pages/account/Verify.tsx +++ b/src/GZCTF/ClientApp/src/pages/account/Verify.tsx @@ -1,5 +1,5 @@ import { FC, useState } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { Button, Text } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiCheck, mdiClose } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/admin/Instances.tsx b/src/GZCTF/ClientApp/src/pages/admin/Instances.tsx index e19607016..ce01d11c1 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/Instances.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/Instances.tsx @@ -1,18 +1,18 @@ import dayjs from 'dayjs' import { FC, forwardRef, useEffect, useState } from 'react' import { - Text, - Select, - Stack, - useMantineTheme, - Group, - ScrollArea, - Paper, - Table, Badge, Box, Code, + Group, + Paper, + ScrollArea, + Select, + Stack, + Table, + Text, Tooltip, + useMantineTheme, } from '@mantine/core' import { useClipboard } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/pages/admin/Logs.tsx b/src/GZCTF/ClientApp/src/pages/admin/Logs.tsx index 4bb4ea7ae..89dbc10d6 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/Logs.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/Logs.tsx @@ -1,19 +1,19 @@ import dayjs from 'dayjs' import React, { FC, useEffect, useRef, useState } from 'react' import { - Group, - SegmentedControl, ActionIcon, - Table, + Badge, + createStyles, + Group, + Input, Paper, ScrollArea, - Input, - createStyles, + SegmentedControl, + Table, Text, - Badge, } from '@mantine/core' import { showNotification } from '@mantine/notifications' -import { mdiClose, mdiCheck, mdiArrowLeftBold, mdiArrowRightBold } from '@mdi/js' +import { mdiArrowLeftBold, mdiArrowRightBold, mdiCheck, mdiClose } from '@mdi/js' import { Icon } from '@mdi/react' import * as signalR from '@microsoft/signalr' import AdminPage from '@Components/admin/AdminPage' diff --git a/src/GZCTF/ClientApp/src/pages/admin/Teams.tsx b/src/GZCTF/ClientApp/src/pages/admin/Teams.tsx index ef52c40b1..0c818ea59 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/Teams.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/Teams.tsx @@ -1,29 +1,29 @@ import React, { FC, useEffect, useState } from 'react' import { - TextInput, - Group, ActionIcon, + Avatar, + Badge, + Code, + Group, + Input, Paper, + ScrollArea, Table, - Avatar, Text, + TextInput, Tooltip, - ScrollArea, - Code, - Badge, - Input, } from '@mantine/core' import { useInputState } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' import { - mdiMagnify, mdiArrowLeftBold, mdiArrowRightBold, - mdiLockOutline, - mdiDeleteOutline, mdiCheck, - mdiPencilOutline, + mdiDeleteOutline, mdiLockOpenVariantOutline, + mdiLockOutline, + mdiMagnify, + mdiPencilOutline, } from '@mdi/js' import { Icon } from '@mdi/react' import { ActionIconWithConfirm } from '@Components/ActionIconWithConfirm' diff --git a/src/GZCTF/ClientApp/src/pages/admin/Users.tsx b/src/GZCTF/ClientApp/src/pages/admin/Users.tsx index 4e37dcf10..1a04f1b8f 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/Users.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/Users.tsx @@ -1,18 +1,18 @@ import React, { FC, useEffect, useState } from 'react' import { - Group, - Table, - Text, ActionIcon, - Badge, Avatar, - TextInput, + Badge, + Button, + Code, + Group, Paper, ScrollArea, - Switch, Stack, - Button, - Code, + Switch, + Table, + Text, + TextInput, } from '@mantine/core' import { useClipboard, useInputState } from '@mantine/hooks' import { useModals } from '@mantine/modals' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/Index.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/Index.tsx index 9e573311a..78bbfd0f1 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/Index.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/Index.tsx @@ -1,19 +1,18 @@ import dayjs from 'dayjs' -import { FC, useState } from 'react' -import { useEffect } from 'react' +import { FC, useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { ActionIcon, Avatar, + Badge, Button, + Code, Group, Paper, - Text, - Table, - Badge, ScrollArea, Switch, - Code, + Table, + Text, } from '@mantine/core' import { mdiArrowLeftBold, diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Info.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Info.tsx index a1a7f7fed..144fed645 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Info.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Info.tsx @@ -2,22 +2,22 @@ import dayjs from 'dayjs' import { FC, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { + ActionIcon, Button, Center, Grid, Group, + Image, Input, + MultiSelect, NumberInput, + PasswordInput, + SimpleGrid, Stack, + Switch, + Text, Textarea, TextInput, - Image, - Text, - MultiSelect, - ActionIcon, - Switch, - PasswordInput, - SimpleGrid, } from '@mantine/core' import { DatePickerInput, TimeInput } from '@mantine/dates' import { Dropzone } from '@mantine/dropzone' @@ -25,12 +25,12 @@ import { useClipboard, useInputState } from '@mantine/hooks' import { useModals } from '@mantine/modals' import { notifications, showNotification, updateNotification } from '@mantine/notifications' import { - mdiKeyboardBackspace, mdiCheck, mdiClose, mdiContentSaveOutline, - mdiRefresh, mdiDeleteOutline, + mdiKeyboardBackspace, + mdiRefresh, } from '@mdi/js' import { Icon } from '@mdi/react' import { SwitchLabel } from '@Components/admin/SwitchLabel' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Notices.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Notices.tsx index 0ad1ad36f..3e674956f 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Notices.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Notices.tsx @@ -1,9 +1,9 @@ import React, { FC, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import { Stack, Button, Text, Group, ScrollArea, Center, Title } from '@mantine/core' +import { Button, Center, Group, ScrollArea, Stack, Text, Title } from '@mantine/core' import { useModals } from '@mantine/modals' import { showNotification } from '@mantine/notifications' -import { mdiKeyboardBackspace, mdiCheck, mdiPlus } from '@mdi/js' +import { mdiCheck, mdiKeyboardBackspace, mdiPlus } from '@mdi/js' import { Icon } from '@mdi/react' import GameNoticeEditCard from '@Components/admin/GameNoticeEditCard' import GameNoticeEditModal from '@Components/admin/GameNoticeEditModal' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Review.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Review.tsx index c98ed5861..3bd6504e1 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Review.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Review.tsx @@ -18,11 +18,11 @@ import { import { showNotification } from '@mantine/notifications' import { mdiAccountOutline, - mdiKeyboardBackspace, mdiBadgeAccountHorizontalOutline, mdiCheck, mdiClose, mdiEmailOutline, + mdiKeyboardBackspace, mdiPhoneOutline, mdiStar, } from '@mdi/js' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Writeups.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Writeups.tsx index 6e9328567..d2ff0faf2 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Writeups.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/Writeups.tsx @@ -1,6 +1,6 @@ import React, { FC, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import { Button, Center, Group, Stack, Title, Text, ScrollArea } from '@mantine/core' +import { Button, Center, Group, ScrollArea, Stack, Text, Title } from '@mantine/core' import { mdiFolderDownloadOutline, mdiKeyboardBackspace } from '@mdi/js' import { Icon } from '@mdi/react' import PDFViewer from '@Components/admin/PDFViewer' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/Index.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/Index.tsx index c372fdf47..a4033b90a 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/Index.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/Index.tsx @@ -13,7 +13,7 @@ import { } from '@mantine/core' import { useModals } from '@mantine/modals' import { showNotification } from '@mantine/notifications' -import { mdiKeyboardBackspace, mdiCheck, mdiPlus, mdiHexagonSlice6 } from '@mdi/js' +import { mdiCheck, mdiHexagonSlice6, mdiKeyboardBackspace, mdiPlus } from '@mdi/js' import { Icon } from '@mdi/react' import BloodBonusModel from '@Components/admin/BloodBonusModel' import ChallengeCreateModal from '@Components/admin/ChallengeCreateModal' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx index ec04afe5a..96b0838bc 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Flags.tsx @@ -2,22 +2,22 @@ import { FC, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Button, + Center, Chip, + Code, Divider, FileButton, Group, Input, + List, + Overlay, Progress, + ScrollArea, Stack, - TextInput, Text, + TextInput, Title, useMantineTheme, - ScrollArea, - Overlay, - Center, - Code, - List, } from '@mantine/core' import { useModals } from '@mantine/modals' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Index.tsx b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Index.tsx index c91639543..3e49741b4 100644 --- a/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Index.tsx +++ b/src/GZCTF/ClientApp/src/pages/admin/games/[id]/challenges/[chalId]/Index.tsx @@ -2,17 +2,17 @@ import { FC, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Button, - Text, - Stack, + Grid, Group, Input, NumberInput, Select, Slider, + Stack, + Switch, + Text, Textarea, TextInput, - Grid, - Switch, Title, } from '@mantine/core' import { useModals } from '@mantine/modals' @@ -34,14 +34,14 @@ import { SwitchLabel } from '@Components/admin/SwitchLabel' import WithGameEditTab from '@Components/admin/WithGameEditTab' import { showErrorNotification } from '@Utils/ApiErrorHandler' import { - ChallengeTypeItem, - ChallengeTypeLabelMap, ChallengeTagItem, ChallengeTagLabelMap, + ChallengeTypeItem, + ChallengeTypeLabelMap, } from '@Utils/Shared' import { OnceSWRConfig } from '@Utils/useConfig' import { useEditChallenge } from '@Utils/useEdit' -import api, { ChallengeUpdateModel, ChallengeTag, ChallengeType, FileType } from '@Api' +import api, { ChallengeTag, ChallengeType, ChallengeUpdateModel, FileType } from '@Api' const GameChallengeEdit: FC = () => { const navigate = useNavigate() diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/Index.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/Index.tsx index 1fc08d2b3..842b93b7f 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/Index.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/Index.tsx @@ -1,17 +1,17 @@ import { FC, useEffect, useState } from 'react' import { Link, useNavigate, useParams } from 'react-router-dom' import { + Alert, + Anchor, + BackgroundImage, + Badge, Button, + Center, Container, Group, Stack, Text, Title, - Center, - Alert, - Badge, - BackgroundImage, - Anchor, } from '@mantine/core' import { useScrollIntoView } from '@mantine/hooks' import { useModals } from '@mantine/modals' diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx index 018ee6db0..6c964f46d 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx @@ -2,21 +2,21 @@ import dayjs from 'dayjs' import { FC, useEffect, useState } from 'react' import { useParams } from 'react-router-dom' import { - Center, - ScrollArea, - Stack, - Text, - Title, - Group, Accordion, - useMantineTheme, - Box, Avatar, Badge, + Box, + Center, + Group, Input, - Switch, Paper, + ScrollArea, + Stack, + Switch, Table, + Text, + Title, + useMantineTheme, } from '@mantine/core' import { useLocalStorage } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Events.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Events.tsx index 654893f59..11e921adb 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Events.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Events.tsx @@ -2,28 +2,28 @@ import dayjs from 'dayjs' import React, { FC, useEffect, useRef, useState } from 'react' import { useParams } from 'react-router-dom' import { - Group, - Text, - useMantineTheme, ActionIcon, + Card, + Group, + Input, ScrollArea, Stack, - Card, Switch, - Input, + Text, + useMantineTheme, } from '@mantine/core' import { useLocalStorage } from '@mantine/hooks' import { showNotification } from '@mantine/notifications' import { - mdiFlag, - mdiLightningBolt, - mdiToggleSwitchOutline, - mdiToggleSwitchOffOutline, - mdiExclamationThick, mdiArrowLeftBold, mdiArrowRightBold, mdiCheck, mdiClose, + mdiExclamationThick, + mdiFlag, + mdiLightningBolt, + mdiToggleSwitchOffOutline, + mdiToggleSwitchOutline, } from '@mdi/js' import { Icon } from '@mdi/react' import * as signalR from '@microsoft/signalr' diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Submissions.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Submissions.tsx index 3a846094c..178d3e1b1 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Submissions.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Submissions.tsx @@ -2,17 +2,17 @@ import dayjs from 'dayjs' import { FC, useEffect, useRef, useState } from 'react' import { useParams } from 'react-router-dom' import { - Group, - SegmentedControl, ActionIcon, + Badge, + Group, + Input, Paper, - Table, ScrollArea, - useMantineTheme, - Input, - Tooltip, - Badge, + SegmentedControl, + Table, Text, + Tooltip, + useMantineTheme, } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Traffic.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Traffic.tsx index 4cb64ea74..b9a15d828 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Traffic.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Traffic.tsx @@ -2,23 +2,23 @@ import dayjs from 'dayjs' import { CSSProperties, FC, useState } from 'react' import { useParams } from 'react-router-dom' import { - Group, + ActionIcon, + Center, + Divider, Grid, + Group, Paper, - Text, - Divider, rem, - ActionIcon, - Tooltip, - Center, Stack, + Text, Title, + Tooltip, } from '@mantine/core' import { showNotification } from '@mantine/notifications' import { mdiClose, mdiDownloadMultiple } from '@mdi/js' import Icon from '@mdi/react' import ScrollSelect from '@Components/ScrollSelect' -import { ChallengeItem, TeamItem, FileItem } from '@Components/TrafficItems' +import { ChallengeItem, FileItem, TeamItem } from '@Components/TrafficItems' import WithGameMonitorTab from '@Components/WithGameMonitor' import { useTooltipStyles } from '@Utils/ThemeOverride' import api, { FileRecord } from '@Api' diff --git a/src/GZCTF/ClientApp/src/pages/posts/[postId]/Index.tsx b/src/GZCTF/ClientApp/src/pages/posts/[postId]/Index.tsx index 1533bab1e..1ea48c6fd 100644 --- a/src/GZCTF/ClientApp/src/pages/posts/[postId]/Index.tsx +++ b/src/GZCTF/ClientApp/src/pages/posts/[postId]/Index.tsx @@ -1,8 +1,8 @@ import dayjs from 'dayjs' import LocalizedFormat from 'dayjs/plugin/localizedFormat' import { FC, useEffect } from 'react' -import { useParams, useNavigate } from 'react-router-dom' -import { Avatar, Container, Divider, Stack, Title, Text, Group, Button } from '@mantine/core' +import { useNavigate, useParams } from 'react-router-dom' +import { Avatar, Button, Container, Divider, Group, Stack, Text, Title } from '@mantine/core' import { useScrollIntoView } from '@mantine/hooks' import { mdiPencilOutline } from '@mdi/js' import { Icon } from '@mdi/react' diff --git a/src/GZCTF/ClientApp/src/pages/posts/[postId]/edit.tsx b/src/GZCTF/ClientApp/src/pages/posts/[postId]/edit.tsx index 87580c4d0..ebcf9008a 100644 --- a/src/GZCTF/ClientApp/src/pages/posts/[postId]/edit.tsx +++ b/src/GZCTF/ClientApp/src/pages/posts/[postId]/edit.tsx @@ -1,14 +1,14 @@ import { FC, useEffect, useState } from 'react' -import { useParams, useNavigate } from 'react-router' +import { useNavigate, useParams } from 'react-router' import { + Button, + Group, + MultiSelect, Stack, + Text, + Textarea, TextInput, Title, - Textarea, - MultiSelect, - Group, - Text, - Button, useMantineTheme, } from '@mantine/core' import { useModals } from '@mantine/modals' diff --git a/src/GZCTF/ClientApp/src/utils/Shared.tsx b/src/GZCTF/ClientApp/src/utils/Shared.tsx index 555be4389..9d1efeace 100644 --- a/src/GZCTF/ClientApp/src/utils/Shared.tsx +++ b/src/GZCTF/ClientApp/src/utils/Shared.tsx @@ -247,11 +247,10 @@ const BonusLabelNameMap = new Map([ ]) export class BloodBonus { - private val: number = (50 << 20) + (30 << 10) + 10 + static default = new BloodBonus() private static mask = 0x3ff private static base = 1000 - - static default = new BloodBonus() + private val: number = (50 << 20) + (30 << 10) + 10 constructor(val?: number) { this.val = val ?? this.val @@ -261,6 +260,11 @@ export class BloodBonus { return this.val } + static fromBonus(first: number, second: number, third: number) { + const value = (first << 20) + (second << 10) + third + return new BloodBonus(value) + } + getBonusNum(type: SubmissionType) { if (type === SubmissionType.FirstBlood) return (this.val >> 20) & BloodBonus.mask if (type === SubmissionType.SecondBlood) return (this.val >> 10) & BloodBonus.mask @@ -292,11 +296,6 @@ export class BloodBonus { }) ) } - - static fromBonus(first: number, second: number, third: number) { - const value = (first << 20) + (second << 10) + third - return new BloodBonus(value) - } } export const TaskStatusColorMap = new Map([ diff --git a/src/GZCTF/ClientApp/src/utils/ThemeOverride.ts b/src/GZCTF/ClientApp/src/utils/ThemeOverride.ts index a565dee30..afa488e8d 100644 --- a/src/GZCTF/ClientApp/src/utils/ThemeOverride.ts +++ b/src/GZCTF/ClientApp/src/utils/ThemeOverride.ts @@ -1,4 +1,4 @@ -import { createStyles, keyframes, MantineThemeOverride, useMantineTheme, rem } from '@mantine/core' +import { createStyles, keyframes, MantineThemeOverride, rem, useMantineTheme } from '@mantine/core' import { useMediaQuery } from '@mantine/hooks' export const ThemeOverride: MantineThemeOverride = { @@ -106,7 +106,12 @@ export const useTableStyles = createStyles((theme) => ({ fontFamily: theme.fontFamilyMonospace, }, fade: { - animation: `${keyframes`0% {opacity:0;} 100% {opacity:1;}`} 0.5s linear`, + animation: `${keyframes`0% { + opacity: 0; + } + 100% { + opacity: 1; + }`} 0.5s linear`, }, table: { '& thead tr th': { @@ -329,7 +334,12 @@ export const useLogoStyles = createStyles((theme) => ({ color: theme.colorScheme === 'dark' ? theme.colors.gray[2] : theme.colors.dark[4], }, blink: { - animation: `${keyframes`0%, 100% {opacity:0;} 50% {opacity:1;}`} 1s infinite steps(1,start)`, + animation: `${keyframes`0%, 100% { + opacity: 0; + } + 50% { + opacity: 1; + }`} 1s infinite steps(1,start)`, }, watermark: { position: 'absolute', diff --git a/src/GZCTF/ClientApp/tsconfig.json b/src/GZCTF/ClientApp/tsconfig.json index 06a123712..dbcdb9b06 100644 --- a/src/GZCTF/ClientApp/tsconfig.json +++ b/src/GZCTF/ClientApp/tsconfig.json @@ -1,8 +1,14 @@ { "compilerOptions": { "target": "esnext", - "lib": ["dom", "dom.iterable", "esnext"], - "types": ["vite/client"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "types": [ + "vite/client" + ], "allowJs": false, "skipLibCheck": true, "strict": true, @@ -18,13 +24,29 @@ "allowSyntheticDefaultImports": true, "baseUrl": ".", "paths": { - "@Api": ["src/Api.ts"], - "@App": ["src/App"], - "@Components/*": ["src/components/*"], - "@Pages/*": ["src/pages/*"], - "@Utils/*": ["src/utils/*"] + "@Api": [ + "src/Api.ts" + ], + "@App": [ + "src/App" + ], + "@Components/*": [ + "src/components/*" + ], + "@Pages/*": [ + "src/pages/*" + ], + "@Utils/*": [ + "src/utils/*" + ] } }, - "include": ["vite.config.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "include": [ + "vite.config.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] } diff --git a/src/GZCTF/ClientApp/vite.config.ts b/src/GZCTF/ClientApp/vite.config.ts index f3bc76f0e..a42c0f0e6 100644 --- a/src/GZCTF/ClientApp/vite.config.ts +++ b/src/GZCTF/ClientApp/vite.config.ts @@ -1,12 +1,12 @@ import eslintPlugin from '@nabla/vite-plugin-eslint' import react from '@vitejs/plugin-react' -import { defineConfig, loadEnv } from 'vite' +import {defineConfig, loadEnv} from 'vite' import Pages from 'vite-plugin-pages' import prismjs from 'vite-plugin-prismjs' import webfontDownload from 'vite-plugin-webfont-dl' import tsconfigPaths from 'vite-tsconfig-paths' -export default defineConfig(({ mode }) => { +export default defineConfig(({mode}) => { const env = loadEnv(mode, process.cwd()) const TARGET = env.VITE_BACKEND_URL ?? 'http://localhost:5000' @@ -18,7 +18,7 @@ export default defineConfig(({ mode }) => { '/api': TARGET, '/swagger': TARGET, '/assets': TARGET, - '/hub': { target: TARGET.replace('http', 'ws'), ws: true }, + '/hub': {target: TARGET.replace('http', 'ws'), ws: true}, }, }, preview: { @@ -46,7 +46,7 @@ export default defineConfig(({ mode }) => { 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,400;0,500;1,400&display=swap', ]), Pages({ - dirs: [{ dir: 'src/pages', baseRoute: '' }], + dirs: [{dir: 'src/pages', baseRoute: ''}], }), tsconfigPaths(), prismjs({ diff --git a/src/GZCTF/Controllers/AccountController.cs b/src/GZCTF/Controllers/AccountController.cs index 1cb963a4b..ef7bb3a16 100644 --- a/src/GZCTF/Controllers/AccountController.cs +++ b/src/GZCTF/Controllers/AccountController.cs @@ -5,11 +5,11 @@ using GZCTF.Models.Request.Account; using GZCTF.Repositories.Interface; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.Extensions.Options; +using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; namespace GZCTF.Controllers; @@ -51,25 +51,20 @@ public async Task Register([FromBody] RegisterModel model, Cancel if (accountPolicy.Value.UseCaptcha && !await captcha.VerifyAsync(model, HttpContext, token)) return BadRequest(new RequestResponse("验证码校验失败")); - var mailDomain = model.Email!.Split('@')[1]; + var mailDomain = model.Email.Split('@')[1]; if (!string.IsNullOrWhiteSpace(accountPolicy.Value.EmailDomainList) && accountPolicy.Value.EmailDomainList.Split(',').All(d => d != mailDomain)) return BadRequest(new RequestResponse($"可用邮箱后缀:{accountPolicy.Value.EmailDomainList}")); - var user = new UserInfo - { - UserName = model.UserName, - Email = model.Email, - Role = Role.User - }; + var user = new UserInfo { UserName = model.UserName, Email = model.Email, Role = Role.User }; user.UpdateByHttpContext(HttpContext); - var result = await userManager.CreateAsync(user, model.Password); + IdentityResult result = await userManager.CreateAsync(user, model.Password); if (!result.Succeeded) { - var current = await userManager.FindByEmailAsync(model.Email); + UserInfo? current = await userManager.FindByEmailAsync(model.Email); if (current is null) return BadRequest(new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); @@ -94,25 +89,26 @@ public async Task Register([FromBody] RegisterModel model, Cancel { logger.Log("用户成功注册,待审核", user, TaskStatus.Success); return Ok(new RequestResponse("注册成功,等待管理员审核", - RegisterStatus.AdminConfirmationRequired, StatusCodes.Status200OK)); + RegisterStatus.AdminConfirmationRequired, StatusCodes.Status200OK)); } logger.Log("发送用户邮箱验证邮件", user, TaskStatus.Pending); var rToken = Codec.Base64.Encode(await userManager.GenerateEmailConfirmationTokenAsync(user)); + var link = GetEmailLink("verify", rToken, model.Email); + if (environment.IsDevelopment()) { - logger.Log($"http://{HttpContext.Request.Host}/account/verify?token={rToken}&email={Codec.Base64.Encode(model.Email)}", user, TaskStatus.Pending, LogLevel.Debug); + logger.Log(link, user, TaskStatus.Pending, LogLevel.Debug); } else { - if (!mailSender.SendConfirmEmailUrl(user.UserName, user.Email, - $"https://{HttpContext.Request.Host}/account/verify?token={rToken}&email={Codec.Base64.Encode(model.Email)}")) + if (!mailSender.SendConfirmEmailUrl(user.UserName, user.Email, link)) return BadRequest(new RequestResponse("邮件无法发送,请联系管理员")); } return Ok(new RequestResponse("注册成功,等待邮箱验证", - RegisterStatus.EmailConfirmationRequired, StatusCodes.Status200OK)); + RegisterStatus.EmailConfirmationRequired, StatusCodes.Status200OK)); } /// @@ -136,7 +132,7 @@ public async Task Recovery([FromBody] RecoveryModel model, Cancel if (accountPolicy.Value.UseCaptcha && !await captcha.VerifyAsync(model, HttpContext, token)) return BadRequest(new RequestResponse("验证码校验失败")); - var user = await userManager.FindByEmailAsync(model.Email!); + UserInfo? user = await userManager.FindByEmailAsync(model.Email!); if (user is null) return NotFound(new RequestResponse("用户不存在", StatusCodes.Status404NotFound)); @@ -149,15 +145,15 @@ public async Task Recovery([FromBody] RecoveryModel model, Cancel logger.Log("发送用户密码重置邮件", HttpContext, TaskStatus.Pending); var rToken = Codec.Base64.Encode(await userManager.GeneratePasswordResetTokenAsync(user)); + var link = GetEmailLink("reset", rToken, model.Email); if (environment.IsDevelopment()) { - logger.Log($"http://{HttpContext.Request.Host}/account/reset?token={rToken}&email={Codec.Base64.Encode(model.Email)}", user, TaskStatus.Pending, LogLevel.Debug); + logger.Log(link, user, TaskStatus.Pending, LogLevel.Debug); } else { - if (!mailSender.SendResetPasswordUrl(user.UserName, user.Email, - $"https://{HttpContext.Request.Host}/account/reset?token={rToken}&email={Codec.Base64.Encode(model.Email)}")) + if (!mailSender.SendResetPasswordUrl(user.UserName, user.Email, link)) return BadRequest(new RequestResponse("邮件无法发送,请联系管理员")); } @@ -179,13 +175,14 @@ public async Task Recovery([FromBody] RecoveryModel model, Cancel [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task PasswordReset([FromBody] PasswordResetModel model) { - var user = await userManager.FindByEmailAsync(Codec.Base64.Decode(model.Email)); + UserInfo? user = await userManager.FindByEmailAsync(Codec.Base64.Decode(model.Email)); if (user is null) return BadRequest(new RequestResponse("无效的邮件地址")); user.UpdateByHttpContext(HttpContext); - var result = await userManager.ResetPasswordAsync(user, Codec.Base64.Decode(model.RToken), model.Password); + IdentityResult result = + await userManager.ResetPasswordAsync(user, Codec.Base64.Decode(model.RToken), model.Password); if (!result.Succeeded) return BadRequest(new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); @@ -211,12 +208,12 @@ public async Task PasswordReset([FromBody] PasswordResetModel mod [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] public async Task Verify([FromBody] AccountVerifyModel model) { - var user = await userManager.FindByEmailAsync(Codec.Base64.Decode(model.Email)); + UserInfo? user = await userManager.FindByEmailAsync(Codec.Base64.Decode(model.Email)); if (user is null || user.EmailConfirmed) return BadRequest(new RequestResponse("无效的邮件地址")); - var result = await userManager.ConfirmEmailAsync(user, Codec.Base64.Decode(model.Token)); + IdentityResult result = await userManager.ConfirmEmailAsync(user, Codec.Base64.Decode(model.Token)); if (!result.Succeeded) return Unauthorized(new RequestResponse("邮箱验证失败", StatusCodes.Status401Unauthorized)); @@ -256,7 +253,7 @@ public async Task LogIn([FromBody] LoginModel model, Cancellation if (accountPolicy.Value.UseCaptcha && !await captcha.VerifyAsync(model, HttpContext, token)) return BadRequest(new RequestResponse("验证码校验失败")); - var user = await userManager.FindByNameAsync(model.UserName); + UserInfo? user = await userManager.FindByNameAsync(model.UserName); user ??= await userManager.FindByEmailAsync(model.UserName); if (user is null) @@ -270,7 +267,7 @@ public async Task LogIn([FromBody] LoginModel model, Cancellation await signInManager.SignOutAsync(); - var result = await signInManager.PasswordSignInAsync(user, model.Password, true, false); + SignInResult result = await signInManager.PasswordSignInAsync(user, model.Password, true, false); if (!result.Succeeded) return Unauthorized(new RequestResponse("用户名或密码错误", StatusCodes.Status401Unauthorized)); @@ -314,17 +311,17 @@ public async Task LogOut() [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task Update([FromBody] ProfileUpdateModel model) { - var user = await userManager.GetUserAsync(User); - var oname = user!.UserName; + UserInfo? user = await userManager.GetUserAsync(User); + var oldName = user!.UserName; user.UpdateUserInfo(model); - var result = await userManager.UpdateAsync(user); + IdentityResult result = await userManager.UpdateAsync(user); if (!result.Succeeded) return BadRequest(new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); - if (oname != user.UserName) - logger.Log($"用户更新:{oname} => {model.UserName}", user, TaskStatus.Success); + if (oldName != user.UserName) + logger.Log($"用户更新:{oldName} => {model.UserName}", user, TaskStatus.Success); return Ok(); } @@ -345,8 +342,8 @@ public async Task Update([FromBody] ProfileUpdateModel model) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] public async Task ChangePassword([FromBody] PasswordChangeModel model) { - var user = await userManager.GetUserAsync(User); - var result = await userManager.ChangePasswordAsync(user!, model.Old, model.New); + UserInfo? user = await userManager.GetUserAsync(User); + IdentityResult result = await userManager.ChangePasswordAsync(user!, model.Old, model.New); if (!result.Succeeded) return BadRequest(new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); @@ -377,7 +374,7 @@ public async Task ChangeEmail([FromBody] MailChangeModel model) if (await userManager.FindByEmailAsync(model.NewMail) is not null) return BadRequest(new RequestResponse("邮箱已经被占用")); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); if (!accountPolicy.Value.EmailConfirmationRequired) return BadRequest(new RequestResponse("请联系管理员修改邮箱", false)); @@ -385,15 +382,15 @@ public async Task ChangeEmail([FromBody] MailChangeModel model) logger.Log("发送用户邮箱更改邮件", user, TaskStatus.Pending); var token = Codec.Base64.Encode(await userManager.GenerateChangeEmailTokenAsync(user!, model.NewMail)); + var link = GetEmailLink("confirm", token, model.NewMail); if (environment.IsDevelopment()) { - logger.Log($"http://{HttpContext.Request.Host}/account/confirm?token={token}&email={Codec.Base64.Encode(model.NewMail)}", user, TaskStatus.Pending, LogLevel.Debug); + logger.Log(link, user, TaskStatus.Pending, LogLevel.Debug); } else { - if (!mailSender.SendConfirmEmailUrl(user!.UserName, user.Email, - $"https://{HttpContext.Request.Host}/account/confirm?token={token}&email={Codec.Base64.Encode(model.NewMail)}")) + if (!mailSender.SendChangeEmailUrl(user!.UserName, model.NewMail, link)) return BadRequest(new RequestResponse("邮件无法发送,请联系管理员")); } @@ -418,8 +415,9 @@ public async Task ChangeEmail([FromBody] MailChangeModel model) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] public async Task MailChangeConfirm([FromBody] AccountVerifyModel model) { - var user = await userManager.GetUserAsync(User); - var result = await userManager.ChangeEmailAsync(user!, Codec.Base64.Decode(model.Email), Codec.Base64.Decode(model.Token)); + UserInfo? user = await userManager.GetUserAsync(User); + IdentityResult result = await userManager.ChangeEmailAsync(user!, Codec.Base64.Decode(model.Email), + Codec.Base64.Decode(model.Token)); if (!result.Succeeded) return BadRequest(new RequestResponse("无效邮箱")); @@ -444,7 +442,7 @@ public async Task MailChangeConfirm([FromBody] AccountVerifyModel [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task Profile() { - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); return Ok(ProfileUserInfoModel.FromUserInfo(user!)); } @@ -471,18 +469,18 @@ public async Task Avatar(IFormFile file, CancellationToken token) if (file.Length > 3 * 1024 * 1024) return BadRequest(new RequestResponse("文件过大")); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); if (user!.AvatarHash is not null) await fileService.DeleteFileByHash(user.AvatarHash, token); - var avatar = await fileService.CreateOrUpdateImage(file, "avatar", 300, token); + LocalFile? avatar = await fileService.CreateOrUpdateImage(file, "avatar", 300, token); if (avatar is null) return BadRequest(new RequestResponse("用户头像更新失败")); user.AvatarHash = avatar.Hash; - var result = await userManager.UpdateAsync(user); + IdentityResult result = await userManager.UpdateAsync(user); if (result != IdentityResult.Success) return BadRequest(new RequestResponse("用户更新失败")); @@ -491,4 +489,8 @@ public async Task Avatar(IFormFile file, CancellationToken token) return Ok(avatar.Url()); } -} + + string GetEmailLink(string action, string token, string? email) + => $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/account/{action}?" + + $"token={token}&email={Codec.Base64.Encode(email)}"; +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/AdminController.cs b/src/GZCTF/Controllers/AdminController.cs index 27246d86a..5e69bc644 100644 --- a/src/GZCTF/Controllers/AdminController.cs +++ b/src/GZCTF/Controllers/AdminController.cs @@ -1,4 +1,6 @@ -using System.Net.Mime; +using System.Diagnostics.CodeAnalysis; +using System.Net.Mime; +using System.Reflection; using GZCTF.Extensions; using GZCTF.Middlewares; using GZCTF.Models.Internal; @@ -7,10 +9,10 @@ using GZCTF.Models.Request.Info; using GZCTF.Repositories.Interface; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Options; namespace GZCTF.Controllers; @@ -75,7 +77,7 @@ public IActionResult GetConfigs() [ProducesResponseType(StatusCodes.Status200OK)] public async Task UpdateConfigs([FromBody] ConfigEditModel model, CancellationToken token) { - foreach (var prop in typeof(ConfigEditModel).GetProperties()) + foreach (PropertyInfo prop in typeof(ConfigEditModel).GetProperties()) { var value = prop.GetValue(model); if (value is not null) @@ -96,11 +98,12 @@ public async Task UpdateConfigs([FromBody] ConfigEditModel model, /// 禁止访问 [HttpGet("Users")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task Users([FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) - => Ok((await ( + public async Task Users([FromQuery] int count = 100, [FromQuery] int skip = 0, + CancellationToken token = default) => + Ok((await ( from user in userManager.Users.OrderBy(e => e.Id).Skip(skip).Take(count) select UserInfoModel.FromUserInfo(user) - ).ToArrayAsync(token)).ToResponse(await userManager.Users.CountAsync(token))); + ).ToArrayAsync(token)).ToResponse(await userManager.Users.CountAsync(token))); /// /// 批量添加用户 @@ -117,16 +120,16 @@ select UserInfoModel.FromUserInfo(user) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task AddUsers([FromBody] UserCreateModel[] model, CancellationToken token = default) { - var currentUser = await userManager.GetUserAsync(User); - var trans = await teamRepository.BeginTransactionAsync(token); + UserInfo? currentUser = await userManager.GetUserAsync(User); + IDbContextTransaction trans = await teamRepository.BeginTransactionAsync(token); try { var users = new List<(UserInfo, string?)>(model.Length); - foreach (var user in model) + foreach (UserCreateModel user in model) { var userInfo = user.ToUserInfo(); - var result = await userManager.CreateAsync(userInfo, user.Password); + IdentityResult result = await userManager.CreateAsync(userInfo, user.Password); if (!result.Succeeded) { @@ -140,7 +143,8 @@ public async Task AddUsers([FromBody] UserCreateModel[] model, Ca break; default: await trans.RollbackAsync(token); - return BadRequest(new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); + return BadRequest( + new RequestResponse(result.Errors.FirstOrDefault()?.Description ?? "未知错误")); } if (userInfo is not null) @@ -161,12 +165,12 @@ public async Task AddUsers([FromBody] UserCreateModel[] model, Ca } var teams = new List(); - foreach (var (user, teamName) in users) + foreach ((UserInfo user, var teamName) in users) { if (teamName is null) continue; - var team = teams.Find(team => team.Name == teamName); + Team? team = teams.Find(team => team.Name == teamName); if (team is null) { team = await teamRepository.CreateTeam(new(teamName), user, token); @@ -203,8 +207,8 @@ public async Task AddUsers([FromBody] UserCreateModel[] model, Ca /// 禁止访问 [HttpPost("Users/Search")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task SearchUsers([FromQuery] string hint, CancellationToken token = default) - => Ok((await ( + public async Task SearchUsers([FromQuery] string hint, CancellationToken token = default) => + Ok((await ( from user in userManager.Users .Where(item => EF.Functions.Like(item.UserName!, $"%{hint}%") || @@ -215,7 +219,7 @@ from user in userManager.Users ) .OrderBy(e => e.Id).Take(30) select UserInfoModel.FromUserInfo(user) - ).ToArrayAsync(token)).ToResponse()); + ).ToArrayAsync(token)).ToResponse()); /// /// 获取全部队伍信息 @@ -228,10 +232,11 @@ select UserInfoModel.FromUserInfo(user) /// 禁止访问 [HttpGet("Teams")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task Teams([FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) - => Ok((await teamRepository.GetTeams(count, skip, token)) - .Select(team => TeamInfoModel.FromTeam(team)) - .ToResponse(await teamRepository.CountAsync(token))); + public async Task Teams([FromQuery] int count = 100, [FromQuery] int skip = 0, + CancellationToken token = default) => + Ok((await teamRepository.GetTeams(count, skip, token)) + .Select(team => TeamInfoModel.FromTeam(team)) + .ToResponse(await teamRepository.CountAsync(token))); /// /// 搜索队伍 @@ -244,10 +249,10 @@ public async Task Teams([FromQuery] int count = 100, [FromQuery] /// 禁止访问 [HttpPost("Teams/Search")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task SearchTeams([FromQuery] string hint, CancellationToken token = default) - => Ok((await teamRepository.SearchTeams(hint, token)) - .Select(team => TeamInfoModel.FromTeam(team)) - .ToResponse()); + public async Task SearchTeams([FromQuery] string hint, CancellationToken token = default) => + Ok((await teamRepository.SearchTeams(hint, token)) + .Select(team => TeamInfoModel.FromTeam(team)) + .ToResponse()); /// /// 修改队伍信息 @@ -259,12 +264,13 @@ public async Task SearchTeams([FromQuery] string hint, Cancellati /// 未授权用户 /// 禁止访问 /// 队伍未找到 - [HttpPut("Teams/{id}")] + [HttpPut("Teams/{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task UpdateTeam([FromRoute] int id, [FromBody] AdminTeamModel model, CancellationToken token = default) + public async Task UpdateTeam([FromRoute] int id, [FromBody] AdminTeamModel model, + CancellationToken token = default) { - var team = await teamRepository.GetTeamById(id, token); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); @@ -290,7 +296,7 @@ public async Task UpdateTeam([FromRoute] int id, [FromBody] Admin [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task UpdateUserInfo(string userid, [FromBody] AdminUserInfoModel model) { - var user = await userManager.FindByIdAsync(userid); + UserInfo? user = await userManager.FindByIdAsync(userid); if (user is null) return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); @@ -311,12 +317,12 @@ public async Task UpdateUserInfo(string userid, [FromBody] AdminU /// 未授权用户 /// 禁止访问 /// 用户未找到 - [HttpDelete("Users/{userid}/Password")] + [HttpDelete("Users/{userid:guid}/Password")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task ResetPassword(string userid) { - var user = await userManager.FindByIdAsync(userid); + UserInfo? user = await userManager.FindByIdAsync(userid); if (user is null) return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); @@ -338,12 +344,12 @@ public async Task ResetPassword(string userid) /// 未授权用户 /// 禁止访问 /// 用户未找到 - [HttpDelete("Users/{userid}")] + [HttpDelete("Users/{userid:guid}")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DeleteUser(string userid, CancellationToken token = default) { - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); if (user!.Id == userid) return BadRequest(new RequestResponse("不可以删除自己")); @@ -371,12 +377,12 @@ public async Task DeleteUser(string userid, CancellationToken tok /// 未授权用户 /// 禁止访问 /// 用户未找到 - [HttpDelete("Teams/{id}")] + [HttpDelete("Teams/{id:int}")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DeleteTeam(int id, CancellationToken token = default) { - var team = await teamRepository.GetTeamById(id, token); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); @@ -395,12 +401,12 @@ public async Task DeleteTeam(int id, CancellationToken token = de /// 用户对象 /// 未授权用户 /// 禁止访问 - [HttpGet("Users/{userid}")] + [HttpGet("Users/{userid:guid}")] [ProducesResponseType(typeof(ProfileUserInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task UserInfo(string userid) { - var user = await userManager.FindByIdAsync(userid); + UserInfo? user = await userManager.FindByIdAsync(userid); if (user is null) return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); @@ -419,8 +425,9 @@ public async Task UserInfo(string userid) /// 禁止访问 [HttpGet("Logs")] [ProducesResponseType(typeof(LogMessageModel[]), StatusCodes.Status200OK)] - public async Task Logs([FromQuery] string? level = "All", [FromQuery] int count = 50, [FromQuery] int skip = 0, CancellationToken token = default) - => Ok(await logRepository.GetLogs(skip, count, level, token)); + public async Task Logs([FromQuery] string? level = "All", [FromQuery] int count = 50, + [FromQuery] int skip = 0, CancellationToken token = default) => + Ok(await logRepository.GetLogs(skip, count, level, token)); /// /// 更新参与状态 @@ -432,12 +439,13 @@ public async Task Logs([FromQuery] string? level = "All", [FromQu /// 未授权用户 /// 禁止访问 /// 参与对象未找到 - [HttpPut("Participation/{id}/{status}")] + [HttpPut("Participation/{id:int}/{status}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Participation(int id, ParticipationStatus status, CancellationToken token = default) + public async Task Participation(int id, ParticipationStatus status, + CancellationToken token = default) { - var participation = await participationRepository.GetParticipationById(id, token); + Participation? participation = await participationRepository.GetParticipationById(id, token); if (participation is null) return NotFound(new RequestResponse("参与状态未找到", StatusCodes.Status404NotFound)); @@ -457,12 +465,12 @@ public async Task Participation(int id, ParticipationStatus statu /// 未授权用户 /// 禁止访问 /// 比赛未找到 - [HttpGet("Writeups/{id}")] + [HttpGet("Writeups/{id:int}")] [ProducesResponseType(typeof(WriteupInfoModel[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task Writeups(int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -480,19 +488,19 @@ public async Task Writeups(int id, CancellationToken token = defa /// 未授权用户 /// 禁止访问 /// 比赛未找到 - [HttpGet("Writeups/{id}/All")] + [HttpGet("Writeups/{id:int}/All")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DownloadAllWriteups(int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var wps = await participationRepository.GetWriteups(game, token); + WriteupInfoModel[] wps = await participationRepository.GetWriteups(game, token); var filename = $"Writeups-{game.Title}-{DateTimeOffset.UtcNow:yyyyMMdd-HH.mm.ssZ}"; - var stream = await Codec.ZipFilesAsync(wps.Select(p => p.File), FilePath.Uploads, filename, token); + Stream stream = await Codec.ZipFilesAsync(wps.Select(p => p.File), FilePath.Uploads, filename, token); stream.Seek(0, SeekOrigin.Begin); return File(stream, "application/zip", $"{filename}.zip"); @@ -509,8 +517,8 @@ public async Task DownloadAllWriteups(int id, CancellationToken t /// 禁止访问 [HttpGet("Instances")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task Instances(CancellationToken token = default) - => Ok(new ArrayResponse(await containerRepository.GetContainerInstances(token))); + public async Task Instances(CancellationToken token = default) => + Ok(new ArrayResponse(await containerRepository.GetContainerInstances(token))); /// /// 删除容器实例 @@ -527,17 +535,17 @@ public async Task Instances(CancellationToken token = default) [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] + [SuppressMessage("ReSharper", "RouteTemplates.ParameterTypeCanBeMadeStricter")] public async Task DestroyInstance(string id, CancellationToken token = default) { - var container = await containerRepository.GetContainerById(id, token); + Container? container = await containerRepository.GetContainerById(id, token); if (container is null) return NotFound(new RequestResponse("容器实例未找到", StatusCodes.Status404NotFound)); if (await instanceRepository.DestroyContainer(container, token)) return Ok(); - else - return BadRequest(new RequestResponse("容器实例销毁失败")); + return BadRequest(new RequestResponse("容器实例销毁失败")); } /// @@ -551,6 +559,7 @@ public async Task DestroyInstance(string id, CancellationToken to /// 禁止访问 [HttpGet("Files")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task Files([FromQuery] int count = 50, [FromQuery] int skip = 0, CancellationToken token = default) - => Ok(new ArrayResponse(await fileService.GetFiles(count, skip, token))); -} + public async Task Files([FromQuery] int count = 50, [FromQuery] int skip = 0, + CancellationToken token = default) => + Ok(new ArrayResponse(await fileService.GetFiles(count, skip, token))); +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/AssetsController.cs b/src/GZCTF/Controllers/AssetsController.cs index 247ebdb39..9998b628c 100644 --- a/src/GZCTF/Controllers/AssetsController.cs +++ b/src/GZCTF/Controllers/AssetsController.cs @@ -2,7 +2,6 @@ using System.Net.Mime; using GZCTF.Middlewares; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; @@ -16,7 +15,7 @@ namespace GZCTF.Controllers; [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public class AssetsController(IFileRepository fileService, ILogger logger) : ControllerBase { - private readonly FileExtensionContentTypeProvider _extProvider = new(); + readonly FileExtensionContentTypeProvider _extProvider = new(); /// /// 获取文件接口 @@ -38,20 +37,17 @@ public IActionResult GetFile([RegularExpression("[0-9a-f]{64}")] string hash, st if (!System.IO.File.Exists(path)) { - var ip = HttpContext.Connection?.RemoteIpAddress?.ToString() ?? "0.0.0.0"; + var ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "0.0.0.0"; logger.Log($"尝试获取不存在的文件 [{hash[..8]}] {filename}", ip, TaskStatus.NotFound, LogLevel.Warning); return NotFound(new RequestResponse("文件不存在", StatusCodes.Status404NotFound)); } - if (!_extProvider.TryGetContentType(filename, out string? contentType)) + if (!_extProvider.TryGetContentType(filename, out var contentType)) contentType = MediaTypeNames.Application.Octet; HttpContext.Response.Headers.CacheControl = $"public, max-age={60 * 60 * 24 * 7}"; - return new PhysicalFileResult(path, contentType) - { - FileDownloadName = filename, - }; + return new PhysicalFileResult(path, contentType) { FileDownloadName = filename }; } /// @@ -71,20 +67,21 @@ public IActionResult GetFile([RegularExpression("[0-9a-f]{64}")] string hash, st [HttpPost("api/[controller]")] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] - public async Task Upload(List files, [FromQuery] string? filename, CancellationToken token) + public async Task Upload(List files, [FromQuery] string? filename, + CancellationToken token) { try { List results = new(); - foreach (var file in files) - { + foreach (IFormFile file in files) if (file.Length > 0) { - var res = await fileService.CreateOrUpdateFile(file, filename, token); - logger.SystemLog($"更新文件 [{res.Hash[..8]}] {filename ?? file.FileName} @ {file.Length} bytes", TaskStatus.Success, LogLevel.Debug); + LocalFile res = await fileService.CreateOrUpdateFile(file, filename, token); + logger.SystemLog($"更新文件 [{res.Hash[..8]}] {filename ?? file.FileName} @ {file.Length} bytes", + TaskStatus.Success, LogLevel.Debug); results.Add(res); } - } + return Ok(results); } catch (Exception ex) @@ -113,7 +110,7 @@ public async Task Upload(List files, [FromQuery] strin [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task Delete(string hash, CancellationToken token) { - var result = await fileService.DeleteFileByHash(hash, token); + TaskStatus result = await fileService.DeleteFileByHash(hash, token); logger.SystemLog($"删除文件 [{hash[..8]}]...", result, LogLevel.Information); @@ -124,4 +121,4 @@ public async Task Delete(string hash, CancellationToken token) _ => BadRequest(new RequestResponse("文件删除失败")) }; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/EditController.cs b/src/GZCTF/Controllers/EditController.cs index 0740e427b..7a972bfc4 100644 --- a/src/GZCTF/Controllers/EditController.cs +++ b/src/GZCTF/Controllers/EditController.cs @@ -5,9 +5,8 @@ using GZCTF.Models.Request.Game; using GZCTF.Models.Request.Info; using GZCTF.Repositories.Interface; -using GZCTF.Services; +using GZCTF.Services.Cache; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -47,8 +46,8 @@ public class EditController( [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] public async Task AddPost([FromBody] PostEditModel model, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var res = await postRepository.CreatePost(new Post().Update(model, user!), token); + UserInfo? user = await userManager.GetUserAsync(User); + Post res = await postRepository.CreatePost(new Post().Update(model, user!), token); return Ok(res.Id); } @@ -68,12 +67,12 @@ public async Task AddPost([FromBody] PostEditModel model, Cancell [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task UpdatePost(string id, [FromBody] PostEditModel model, CancellationToken token) { - var post = await postRepository.GetPostById(id, token); + Post? post = await postRepository.GetPostById(id, token); if (post is null) return NotFound(new RequestResponse("文章未找到", StatusCodes.Status404NotFound)); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); await postRepository.UpdatePost(post.Update(model, user!), token); @@ -90,12 +89,12 @@ public async Task UpdatePost(string id, [FromBody] PostEditModel /// /// 成功删除文章 /// 未找到文章 - [HttpDelete("Posts/{id}")] + [HttpDelete("Posts/{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DeletePost(string id, CancellationToken token) { - var post = await postRepository.GetPostById(id, token); + Post? post = await postRepository.GetPostById(id, token); if (post is null) return NotFound(new RequestResponse("文章未找到", StatusCodes.Status404NotFound)); @@ -119,7 +118,7 @@ public async Task DeletePost(string id, CancellationToken token) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task AddGame([FromBody] GameInfoModel model, CancellationToken token) { - var game = await gameRepository.CreateGame(new Game().Update(model), token); + Game? game = await gameRepository.CreateGame(new Game().Update(model), token); if (game is null) return BadRequest(new RequestResponse("比赛创建失败")); @@ -141,8 +140,8 @@ public async Task AddGame([FromBody] GameInfoModel model, Cancell /// 成功获取比赛列表 [HttpGet("Games")] [ProducesResponseType(typeof(ArrayResponse), StatusCodes.Status200OK)] - public async Task GetGames([FromQuery] int count, [FromQuery] int skip, CancellationToken token) - => Ok((await gameRepository.GetGames(count, skip, token)) + public async Task GetGames([FromQuery] int count, [FromQuery] int skip, CancellationToken token) => + Ok((await gameRepository.GetGames(count, skip, token)) .Select(GameInfoModel.FromGame) .ToResponse(await gameRepository.CountAsync(token))); @@ -155,12 +154,12 @@ public async Task GetGames([FromQuery] int count, [FromQuery] int /// /// /// 成功获取比赛 - [HttpGet("Games/{id}")] + [HttpGet("Games/{id:int}")] [ProducesResponseType(typeof(GameInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetGame([FromRoute] int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -177,12 +176,12 @@ public async Task GetGame([FromRoute] int id, CancellationToken t /// /// /// 成功获取比赛哈希加盐 - [HttpGet("Games/{id}/TeamHashSalt")] + [HttpGet("Games/{id:int}/TeamHashSalt")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetTeamHashSalt([FromRoute] int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -202,12 +201,13 @@ public async Task GetTeamHashSalt([FromRoute] int id, Cancellatio /// /// /// 成功修改比赛 - [HttpPut("Games/{id}")] + [HttpPut("Games/{id:int}")] [ProducesResponseType(typeof(GameInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task UpdateGame([FromRoute] int id, [FromBody] GameInfoModel model, CancellationToken token) + public async Task UpdateGame([FromRoute] int id, [FromBody] GameInfoModel model, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -229,13 +229,13 @@ public async Task UpdateGame([FromRoute] int id, [FromBody] GameI /// /// /// 成功删除比赛 - [HttpDelete("Games/{id}")] + [HttpDelete("Games/{id:int}")] [ProducesResponseType(typeof(GameInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DeleteGame([FromRoute] int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -257,12 +257,12 @@ public async Task DeleteGame([FromRoute] int id, CancellationToke /// /// /// 成功删除比赛 WriteUps - [HttpDelete("Games/{id}/WriteUps")] + [HttpDelete("Games/{id:int}/WriteUps")] [ProducesResponseType(typeof(GameInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task DeleteGameWriteUps([FromRoute] int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -281,7 +281,7 @@ public async Task DeleteGameWriteUps([FromRoute] int id, Cancella /// 比赛头图URL /// 非法请求 /// 未授权用户 - [HttpPut("Games/{id}/Poster")] + [HttpPut("Games/{id:int}/Poster")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] @@ -293,12 +293,12 @@ public async Task UpdateGamePoster([FromRoute] int id, IFormFile if (file.Length > 3 * 1024 * 1024) return BadRequest(new RequestResponse("文件过大")); - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var poster = await fileService.CreateOrUpdateImage(file, "poster", 0, token); + LocalFile? poster = await fileService.CreateOrUpdateImage(file, "poster", 0, token); if (poster is null) return BadRequest(new RequestResponse("文件创建失败")); @@ -320,23 +320,19 @@ public async Task UpdateGamePoster([FromRoute] int id, IFormFile /// 通知内容 /// /// 成功添加比赛通知 - [HttpPost("Games/{id}/Notices")] + [HttpPost("Games/{id:int}/Notices")] [ProducesResponseType(typeof(GameNotice), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task AddGameNotice([FromRoute] int id, [FromBody] GameNoticeModel model, CancellationToken token) + public async Task AddGameNotice([FromRoute] int id, [FromBody] GameNoticeModel model, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var res = await gameNoticeRepository.AddNotice(new() - { - Content = model.Content, - GameId = game.Id, - Type = NoticeType.Normal, - PublishTimeUTC = DateTimeOffset.UtcNow - }, token); + GameNotice res = await gameNoticeRepository.AddNotice( + new() { Content = model.Content, GameId = game.Id, Type = NoticeType.Normal, PublishTimeUTC = DateTimeOffset.UtcNow }, token); return Ok(res); } @@ -350,12 +346,12 @@ public async Task AddGameNotice([FromRoute] int id, [FromBody] Ga /// 比赛Id /// /// 成功获取比赛通知 - [HttpGet("Games/{id}/Notices")] + [HttpGet("Games/{id:int}/Notices")] [ProducesResponseType(typeof(GameNotice[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetGameNotices([FromRoute] int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -374,12 +370,13 @@ public async Task GetGameNotices([FromRoute] int id, Cancellation /// 通知内容 /// /// 成功更新通知 - [HttpPut("Games/{id}/Notices/{noticeId}")] + [HttpPut("Games/{id:int}/Notices/{noticeId:int}")] [ProducesResponseType(typeof(GameNotice), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task UpdateGameNotice([FromRoute] int id, [FromRoute] int noticeId, [FromBody] GameNoticeModel model, CancellationToken token = default) + public async Task UpdateGameNotice([FromRoute] int id, [FromRoute] int noticeId, + [FromBody] GameNoticeModel model, CancellationToken token = default) { - var notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); + GameNotice? notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); if (notice is null) return NotFound(new RequestResponse("通知未找到", StatusCodes.Status404NotFound)); @@ -402,12 +399,13 @@ public async Task UpdateGameNotice([FromRoute] int id, [FromRoute /// /// 成功删除文章 /// 未找到文章 - [HttpDelete("Games/{id}/Notices/{noticeId}")] + [HttpDelete("Games/{id:int}/Notices/{noticeId:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task DeleteGameNotice([FromRoute] int id, [FromRoute] int noticeId, CancellationToken token) + public async Task DeleteGameNotice([FromRoute] int id, [FromRoute] int noticeId, + CancellationToken token) { - var notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); + GameNotice? notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); if (notice is null) return NotFound(new RequestResponse("通知未找到", StatusCodes.Status404NotFound)); @@ -430,22 +428,19 @@ public async Task DeleteGameNotice([FromRoute] int id, [FromRoute /// /// /// 成功添加比赛题目 - [HttpPost("Games/{id}/Challenges")] + [HttpPost("Games/{id:int}/Challenges")] [ProducesResponseType(typeof(ChallengeEditDetailModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task AddGameChallenge([FromRoute] int id, [FromBody] ChallengeInfoModel model, CancellationToken token) + public async Task AddGameChallenge([FromRoute] int id, [FromBody] ChallengeInfoModel model, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var res = await challengeRepository.CreateChallenge(game, new Challenge() - { - Title = model.Title, - Type = model.Type, - Tag = model.Tag - }, token); + Challenge res = await challengeRepository.CreateChallenge(game, + new Challenge { Title = model.Title, Type = model.Type, Tag = model.Tag }, token); return Ok(ChallengeEditDetailModel.FromChallenge(res)); } @@ -459,10 +454,10 @@ public async Task AddGameChallenge([FromRoute] int id, [FromBody] /// 比赛Id /// /// 成功获取比赛题目 - [HttpGet("Games/{id}/Challenges")] + [HttpGet("Games/{id:int}/Challenges")] [ProducesResponseType(typeof(ChallengeInfoModel[]), StatusCodes.Status200OK)] - public async Task GetGameChallenges([FromRoute] int id, CancellationToken token) - => Ok((await challengeRepository.GetChallenges(id, token)).Select(ChallengeInfoModel.FromChallenge)); + public async Task GetGameChallenges([FromRoute] int id, CancellationToken token) => + Ok((await challengeRepository.GetChallenges(id, token)).Select(ChallengeInfoModel.FromChallenge)); /// /// 获取比赛题目 @@ -474,17 +469,17 @@ public async Task GetGameChallenges([FromRoute] int id, Cancellat /// 题目Id /// /// 成功添加比赛题目 - [HttpGet("Games/{id}/Challenges/{cId}")] + [HttpGet("Games/{id:int}/Challenges/{cId:int}")] [ProducesResponseType(typeof(ChallengeEditDetailModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetGameChallenge([FromRoute] int id, [FromRoute] int cId, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var res = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -503,17 +498,18 @@ public async Task GetGameChallenge([FromRoute] int id, [FromRoute /// 题目信息 /// /// 成功添加比赛题目 - [HttpPut("Games/{id}/Challenges/{cId}")] + [HttpPut("Games/{id:int}/Challenges/{cId:int}")] [ProducesResponseType(typeof(ChallengeEditDetailModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task UpdateGameChallenge([FromRoute] int id, [FromRoute] int cId, [FromBody] ChallengeUpdateModel model, CancellationToken token) + public async Task UpdateGameChallenge([FromRoute] int id, [FromRoute] int cId, + [FromBody] ChallengeUpdateModel model, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var res = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -528,9 +524,10 @@ public async Task UpdateGameChallenge([FromRoute] int id, [FromRo if (model.FileName is not null && string.IsNullOrWhiteSpace(model.FileName)) return BadRequest(new RequestResponse("动态附件名不可为空")); - bool hintUpdated = model.IsHintUpdated(res.Hints?.GetSetHashCode()); + var hintUpdated = model.IsHintUpdated(res.Hints?.GetSetHashCode()); - if (!string.IsNullOrWhiteSpace(model.FlagTemplate) && res.Type == ChallengeType.DynamicContainer && !model.IsValidFlagTemplate()) + if (!string.IsNullOrWhiteSpace(model.FlagTemplate) && res.Type == ChallengeType.DynamicContainer && + !model.IsValidFlagTemplate()) return BadRequest(new RequestResponse("flag 复杂度不足,请考虑添加队伍哈希或增加长度")); res.Update(model); @@ -541,27 +538,17 @@ public async Task UpdateGameChallenge([FromRoute] int id, [FromRo await challengeRepository.EnsureInstances(res, game, token); if (game.IsActive) - { - await gameNoticeRepository.AddNotice(new() - { - Game = game, - Type = NoticeType.NewChallenge, - Content = $"新增了题目 「{res.Title}」", - }, token); - } + await gameNoticeRepository.AddNotice( + new() { Game = game, Type = NoticeType.NewChallenge, Content = $"新增了题目 「{res.Title}」" }, token); } else + { await challengeRepository.SaveAsync(token); + } if (game.IsActive && res.IsEnabled && hintUpdated) - { - await gameNoticeRepository.AddNotice(new() - { - Game = game, - Type = NoticeType.NewHint, - Content = $"「{res.Title}」 更新了提示", - }, token); - } + await gameNoticeRepository.AddNotice( + new() { Game = game, Type = NoticeType.NewHint, Content = $"「{res.Title}」 更新了提示" }, token); // always flush scoreboard await cacheHelper.FlushScoreboardCache(game.Id, token); @@ -579,17 +566,18 @@ await gameNoticeRepository.AddNotice(new() /// 题目Id /// /// 成功开启比赛题目容器 - [HttpPost("Games/{id}/Challenges/{cId}/Container")] + [HttpPost("Games/{id:int}/Challenges/{cId:int}/Container")] [ProducesResponseType(typeof(ContainerInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task CreateTestContainer([FromRoute] int id, [FromRoute] int cId, CancellationToken token) + public async Task CreateTestContainer([FromRoute] int id, [FromRoute] int cId, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var challenge = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -600,19 +588,20 @@ public async Task CreateTestContainer([FromRoute] int id, [FromRo if (challenge.ContainerImage is null || challenge.ContainerExposePort is null) return BadRequest(new RequestResponse("容器配置错误")); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); - var container = await containerService.CreateContainerAsync(new() - { - TeamId = "admin", - UserId = user!.Id, - Flag = challenge.Type.IsDynamic() ? challenge.GenerateTestFlag() : null, - Image = challenge.ContainerImage, - CPUCount = challenge.CPUCount ?? 1, - MemoryLimit = challenge.MemoryLimit ?? 64, - StorageLimit = challenge.StorageLimit ?? 256, - ExposedPort = challenge.ContainerExposePort ?? throw new ArgumentException("创建容器时遇到无效的端口"), - }, token); + Container? container = await containerService.CreateContainerAsync( + new() + { + TeamId = "admin", + UserId = user!.Id, + Flag = challenge.Type.IsDynamic() ? challenge.GenerateTestFlag() : null, + Image = challenge.ContainerImage, + CPUCount = challenge.CPUCount ?? 1, + MemoryLimit = challenge.MemoryLimit ?? 64, + StorageLimit = challenge.StorageLimit ?? 256, + ExposedPort = challenge.ContainerExposePort ?? throw new ArgumentException("创建容器时遇到无效的端口") + }, token); if (container is null) return BadRequest(new RequestResponse("容器创建失败")); @@ -635,17 +624,18 @@ public async Task CreateTestContainer([FromRoute] int id, [FromRo /// 题目Id /// /// 成功添加比赛题目 - [HttpDelete("Games/{id}/Challenges/{cId}/Container")] + [HttpDelete("Games/{id:int}/Challenges/{cId:int}/Container")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task DestroyTestContainer([FromRoute] int id, [FromRoute] int cId, CancellationToken token) + public async Task DestroyTestContainer([FromRoute] int id, [FromRoute] int cId, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var challenge = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -669,17 +659,18 @@ public async Task DestroyTestContainer([FromRoute] int id, [FromR /// 题目Id /// /// 成功添加比赛题目 - [HttpDelete("Games/{id}/Challenges/{cId}")] + [HttpDelete("Games/{id:int}/Challenges/{cId:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task RemoveGameChallenge([FromRoute] int id, [FromRoute] int cId, CancellationToken token) + public async Task RemoveGameChallenge([FromRoute] int id, [FromRoute] int cId, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var res = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -703,17 +694,18 @@ public async Task RemoveGameChallenge([FromRoute] int id, [FromRo /// /// /// 成功添加比赛题目数量 - [HttpPost("Games/{id}/Challenges/{cId}/Attachment")] + [HttpPost("Games/{id:int}/Challenges/{cId:int}/Attachment")] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task UpdateAttachment([FromRoute] int id, [FromRoute] int cId, [FromBody] AttachmentCreateModel model, CancellationToken token) + public async Task UpdateAttachment([FromRoute] int id, [FromRoute] int cId, + [FromBody] AttachmentCreateModel model, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var challenge = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -737,17 +729,18 @@ public async Task UpdateAttachment([FromRoute] int id, [FromRoute /// /// /// 成功添加比赛题目数量 - [HttpPost("Games/{id}/Challenges/{cId}/Flags")] + [HttpPost("Games/{id:int}/Challenges/{cId:int}/Flags")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task AddFlags([FromRoute] int id, [FromRoute] int cId, [FromBody] FlagCreateModel[] models, CancellationToken token) + public async Task AddFlags([FromRoute] int id, [FromRoute] int cId, + [FromBody] FlagCreateModel[] models, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var challenge = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -768,21 +761,22 @@ public async Task AddFlags([FromRoute] int id, [FromRoute] int cI /// Flag ID /// /// 成功添加比赛题目 - [HttpDelete("Games/{id}/Challenges/{cId}/Flags/{fId}")] + [HttpDelete("Games/{id:int}/Challenges/{cId:int}/Flags/{fId:int}")] [ProducesResponseType(typeof(TaskStatus), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task RemoveFlag([FromRoute] int id, [FromRoute] int cId, [FromRoute] int fId, CancellationToken token) + public async Task RemoveFlag([FromRoute] int id, [FromRoute] int cId, [FromRoute] int fId, + CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var challenge = await challengeRepository.GetChallenge(id, cId, true, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); return Ok(await challengeRepository.RemoveFlag(challenge, fId, token)); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/GameController.cs b/src/GZCTF/Controllers/GameController.cs index a0a6e2309..4b060a5d3 100644 --- a/src/GZCTF/Controllers/GameController.cs +++ b/src/GZCTF/Controllers/GameController.cs @@ -1,12 +1,11 @@ -using System.Net.Mime; +using System.Diagnostics.CodeAnalysis; +using System.Net.Mime; using System.Security.Claims; using System.Threading.Channels; using GZCTF.Middlewares; using GZCTF.Models.Request.Admin; -using GZCTF.Models.Request.Edit; using GZCTF.Models.Request.Game; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; @@ -49,8 +48,7 @@ public class GameController( /// 成功获取比赛信息 [HttpGet] [ProducesResponseType(typeof(BasicGameInfoModel[]), StatusCodes.Status200OK)] - public async Task Games(CancellationToken token) - => Ok(await gameRepository.GetBasicGameInfo(10, 0, token)); + public async Task Games(CancellationToken token) => Ok(await gameRepository.GetBasicGameInfo(10, 0, token)); /// /// 获取比赛详细信息 @@ -62,12 +60,12 @@ public async Task Games(CancellationToken token) /// /// 成功获取比赛信息 /// 比赛未找到 - [HttpGet("{id}")] + [HttpGet("{id:int}")] [ProducesResponseType(typeof(DetailedGameInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task Games(int id, CancellationToken token) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -75,7 +73,7 @@ public async Task Games(int id, CancellationToken token) var count = await participationRepository.GetParticipationCount(context.Game, token); return Ok(DetailedGameInfoModel.FromGame(context.Game, count) - .WithParticipation(context.Participation)); + .WithParticipation(context.Participation)); } /// @@ -91,13 +89,13 @@ public async Task Games(int id, CancellationToken token) /// 无权操作或操作无效 /// 比赛未找到 [RequireUser] - [HttpPost("{id}")] + [HttpPost("{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task JoinGame(int id, [FromBody] GameJoinModel model, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -111,8 +109,8 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model if (game.Organizations is { Count: > 0 } && game.Organizations.All(o => o != model.Organization)) return BadRequest(new RequestResponse("无效的参赛单位")); - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(model.TeamId, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(model.TeamId, token); if (team is null) return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); @@ -128,19 +126,13 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model await participationRepository.RemoveUserParticipations(user!, game, token); // 根据队伍获取报名信息 - var part = await participationRepository.GetParticipation(team, game, token); + Participation? part = await participationRepository.GetParticipation(team, game, token); // 如果队伍未报名 if (part is null) { // 创建新的队伍参与对象,不添加三元组 - part = new() - { - Game = game, - Team = team, - Organization = model.Organization, - Token = gameRepository.GetToken(game, team) - }; + part = new() { Game = game, Team = team, Organization = model.Organization, Token = gameRepository.GetToken(game, team) }; participationRepository.Add(part); } @@ -161,7 +153,7 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model if (game.AcceptWithoutReview) await participationRepository.UpdateParticipationStatus(part, ParticipationStatus.Accepted, token); - logger.Log($"[{team!.Name}] 成功报名了比赛 [{game.Title}]", user, TaskStatus.Success); + logger.Log($"[{team.Name}] 成功报名了比赛 [{game.Title}]", user, TaskStatus.Success); return Ok(); } @@ -178,20 +170,20 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model /// 无权操作或操作无效 /// 比赛未找到 [RequireUser] - [HttpDelete("{id}")] + [HttpDelete("{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task LeaveGame(int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); - var part = await participationRepository.GetParticipation(user!, game, token); + Participation? part = await participationRepository.GetParticipation(user!, game, token); if (part is null || part.Members.All(u => u.UserId != user!.Id)) return BadRequest(new RequestResponse("无法退出未报名的比赛")); @@ -221,12 +213,12 @@ public async Task LeaveGame(int id, CancellationToken token) /// /// 成功获取比赛信息 /// 比赛未找到 - [HttpGet("{id}/Scoreboard")] + [HttpGet("{id:int}/Scoreboard")] [ProducesResponseType(typeof(ScoreboardModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task Scoreboard([FromRoute] int id, CancellationToken token) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -249,12 +241,13 @@ public async Task Scoreboard([FromRoute] int id, CancellationToke /// /// 成功获取比赛通知 /// 比赛未找到 - [HttpGet("{id}/Notices")] + [HttpGet("{id:int}/Notices")] [ProducesResponseType(typeof(GameNotice[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Notices([FromRoute] int id, [FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) + public async Task Notices([FromRoute] int id, [FromQuery] int count = 100, [FromQuery] int skip = 0, + CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -279,12 +272,13 @@ public async Task Notices([FromRoute] int id, [FromQuery] int cou /// 成功获取比赛事件 /// 比赛未找到 [RequireMonitor] - [HttpGet("{id}/Events")] + [HttpGet("{id:int}/Events")] [ProducesResponseType(typeof(GameEvent[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Events([FromRoute] int id, [FromQuery] bool hideContainer = false, [FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) + public async Task Events([FromRoute] int id, [FromQuery] bool hideContainer = false, + [FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -309,12 +303,13 @@ public async Task Events([FromRoute] int id, [FromQuery] bool hid /// 成功获取比赛提交 /// 比赛未找到 [RequireMonitor] - [HttpGet("{id}/Submissions")] + [HttpGet("{id:int}/Submissions")] [ProducesResponseType(typeof(Submission[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Submissions([FromRoute] int id, [FromQuery] AnswerResult? type = null, [FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) + public async Task Submissions([FromRoute] int id, [FromQuery] AnswerResult? type = null, + [FromQuery] int count = 100, [FromQuery] int skip = 0, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -336,12 +331,12 @@ public async Task Submissions([FromRoute] int id, [FromQuery] Ans /// 成功获取比赛作弊数据 /// 比赛未找到 [RequireMonitor] - [HttpGet("{id}/CheatInfo")] + [HttpGet("{id:int}/CheatInfo")] [ProducesResponseType(typeof(CheatInfoModel[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task CheatInfo([FromRoute] int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); @@ -364,10 +359,10 @@ public async Task CheatInfo([FromRoute] int id, CancellationToken /// 成功获取题目列表 /// 未找到相关捕获信息 [RequireMonitor] - [HttpGet("Games/{id}/Captures")] + [HttpGet("Games/{id:int}/Captures")] [ProducesResponseType(typeof(ChallengeTrafficModel[]), StatusCodes.Status200OK)] - public async Task GetChallengesWithTrafficCapturing([FromRoute] int id, CancellationToken token) - => Ok((await challengeRepository.GetChallengesWithTrafficCapturing(id, token)) + public async Task GetChallengesWithTrafficCapturing([FromRoute] int id, CancellationToken token) => + Ok((await challengeRepository.GetChallengesWithTrafficCapturing(id, token)) .Select(ChallengeTrafficModel.FromChallenge)); /// @@ -381,24 +376,24 @@ public async Task GetChallengesWithTrafficCapturing([FromRoute] i /// 成功获取文件列表 /// 未找到相关捕获信息 [RequireMonitor] - [HttpGet("Captures/{challengeId}")] + [HttpGet("Captures/{challengeId:int}")] [ProducesResponseType(typeof(TeamTrafficModel[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetChallengeTraffic([FromRoute] int challengeId, CancellationToken token) { - var filePath = $"{FilePath.Capture}/{challengeId}"; + var filePath = $"{FilePath.Capture}/{challengeId:int}"; if (!Path.Exists(filePath)) return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); - var participationIds = await GetDirNamesAsInt(filePath); + List participationIds = await GetDirNamesAsInt(filePath); if (participationIds.Count == 0) return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); - var participations = await participationRepository.GetParticipationsByIds(participationIds, token); + Participation[] participation = await participationRepository.GetParticipationsByIds(participationIds, token); - return Ok(participations.Select(p => TeamTrafficModel.FromParticipation(p, challengeId))); + return Ok(participation.Select(p => TeamTrafficModel.FromParticipation(p, challengeId))); } /// @@ -412,17 +407,17 @@ public async Task GetChallengeTraffic([FromRoute] int challengeId /// 成功获取文件列表 /// 未找到相关捕获信息 [RequireMonitor] - [HttpGet("Captures/{challengeId}/{partId}")] + [HttpGet("Captures/{challengeId:int}/{partId:int}")] [ProducesResponseType(typeof(FileRecord[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int partId) { - var filePath = $"{FilePath.Capture}/{challengeId}/{partId}"; + var filePath = $"{FilePath.Capture}/{challengeId:int}/{partId:int}"; if (!Path.Exists(filePath)) return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); - return Ok(FilePath.GetFileRecords(filePath, out long _)); + return Ok(FilePath.GetFileRecords(filePath, out var _)); } /// @@ -437,18 +432,19 @@ public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int /// 成功获取文件 /// 未找到相关捕获信息 [RequireMonitor] - [HttpGet("Captures/{challengeId}/{partId}/All")] + [HttpGet("Captures/{challengeId:int}/{partId:int}/All")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task GetTeamTrafficZip([FromRoute] int challengeId, [FromRoute] int partId, CancellationToken token) + public async Task GetTeamTrafficZip([FromRoute] int challengeId, [FromRoute] int partId, + CancellationToken token) { - var filePath = $"{FilePath.Capture}/{challengeId}/{partId}"; + var filePath = $"{FilePath.Capture}/{challengeId:int}/{partId:int}"; if (!Path.Exists(filePath)) return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); - var filename = $"Capture-{challengeId}-{partId}-{DateTimeOffset.UtcNow:yyyyMMdd-HH.mm.ssZ}"; - var stream = await Codec.ZipFilesAsync(filePath, filename, token); + var filename = $"Capture-{challengeId:int}-{partId:int}-{DateTimeOffset.UtcNow:yyyyMMdd-HH.mm.ssZ}"; + Stream stream = await Codec.ZipFilesAsync(filePath, filename, token); stream.Seek(0, SeekOrigin.Begin); return File(stream, "application/zip", $"{filename}.zip"); @@ -466,23 +462,21 @@ public async Task GetTeamTrafficZip([FromRoute] int challengeId, /// 成功获取文件 /// 未找到相关捕获信息 [RequireMonitor] - [HttpGet("Captures/{challengeId}/{partId}/{filename}")] + [HttpGet("Captures/{challengeId:int}/{partId:int}/{filename}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int partId, [FromRoute] string filename) + public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int partId, + [FromRoute] string filename) { try { var file = Path.GetFileName(filename); - var path = Path.GetFullPath(Path.Combine(FilePath.Capture, $"{challengeId}/{partId}", file)); + var path = Path.GetFullPath(Path.Combine(FilePath.Capture, $"{challengeId:int}/{partId:int}", file)); if (Path.GetExtension(file) != ".pcap" || !Path.Exists(path)) return NotFound(new RequestResponse("未找到相关捕获信息")); - return new PhysicalFileResult(path, MediaTypeNames.Application.Octet) - { - FileDownloadName = file - }; + return new PhysicalFileResult(path, MediaTypeNames.Application.Octet) { FileDownloadName = file }; } catch { @@ -502,23 +496,23 @@ public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int /// 操作无效 /// 比赛未找到 [RequireUser] - [HttpGet("{id}/Details")] + [HttpGet("{id:int}/Details")] [ProducesResponseType(typeof(GameDetailModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task ChallengesWithTeamInfo([FromRoute] int id, CancellationToken token) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Result is not null) return context.Result; - var scoreboard = await gameRepository.GetScoreboard(context.Game!, token); + ScoreboardModel scoreboard = await gameRepository.GetScoreboard(context.Game!, token); - var boarditem = scoreboard.Items.FirstOrDefault(i => i.Id == context.Participation!.TeamId); + ScoreboardItem? boardItem = scoreboard.Items.FirstOrDefault(i => i.Id == context.Participation!.TeamId); // make sure team info is not null - boarditem ??= new ScoreboardItem() + boardItem ??= new ScoreboardItem { Avatar = context.Participation!.Team.AvatarUrl, SolvedCount = 0, @@ -527,9 +521,9 @@ public async Task ChallengesWithTeamInfo([FromRoute] int id, Canc Id = context.Participation!.TeamId }; - return Ok(new GameDetailModel() + return Ok(new GameDetailModel { - ScoreboardItem = boarditem, + ScoreboardItem = boardItem, TeamToken = context.Participation!.Token, Challenges = scoreboard.Challenges, WriteupDeadline = context.Game!.WriteupDeadline @@ -548,19 +542,19 @@ public async Task ChallengesWithTeamInfo([FromRoute] int id, Canc /// 操作无效 /// 比赛未找到 [RequireAdmin] - [HttpGet("{id}/Participations")] + [HttpGet("{id:int}/Participations")] [ProducesResponseType(typeof(ParticipationInfoModel[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Participations([FromRoute] int id, CancellationToken token = default) + public async Task Participation([FromRoute] int id, CancellationToken token = default) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Game is null) return NotFound(new RequestResponse("比赛未找到")); return Ok((await participationRepository.GetParticipations(context.Game!, token)) - .Select(ParticipationInfoModel.FromParticipation)); + .Select(ParticipationInfoModel.FromParticipation)); } /// @@ -575,13 +569,14 @@ public async Task Participations([FromRoute] int id, Cancellation /// 操作无效 /// 比赛未找到 [RequireMonitor] - [HttpGet("{id}/ScoreboardSheet")] + [HttpGet("{id:int}/ScoreboardSheet")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] + [SuppressMessage("ReSharper", "StringLiteralTypo")] public async Task ScoreboardSheet([FromRoute] int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到")); @@ -591,8 +586,8 @@ public async Task ScoreboardSheet([FromRoute] int id, Cancellatio try { - var scoreboard = await gameRepository.GetScoreboardWithMembers(game, token); - var stream = ExcelHelper.GetScoreboardExcel(scoreboard, game); + ScoreboardModel scoreboard = await gameRepository.GetScoreboardWithMembers(game, token); + MemoryStream stream = ExcelHelper.GetScoreboardExcel(scoreboard, game); stream.Seek(0, SeekOrigin.Begin); return File(stream, @@ -619,13 +614,14 @@ public async Task ScoreboardSheet([FromRoute] int id, Cancellatio /// 操作无效 /// 比赛未找到 [RequireMonitor] - [HttpGet("{id}/SubmissionSheet")] + [HttpGet("{id:int}/SubmissionSheet")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] + [SuppressMessage("ReSharper", "StringLiteralTypo")] public async Task SubmissionSheet([FromRoute] int id, CancellationToken token = default) { - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return NotFound(new RequestResponse("比赛未找到")); @@ -633,14 +629,14 @@ public async Task SubmissionSheet([FromRoute] int id, Cancellatio if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); - var submissions = await submissionRepository.GetSubmissions(game, count: 0, token: token); + Submission[] submissions = await submissionRepository.GetSubmissions(game, count: 0, token: token); - var stream = ExcelHelper.GetSubmissionExcel(submissions); + MemoryStream stream = ExcelHelper.GetSubmissionExcel(submissions); stream.Seek(0, SeekOrigin.Begin); return File(stream, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - $"{game.Title}_Submissions_{DateTimeOffset.Now:yyyyMMddHHmmss}.xlsx"); + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"{game.Title}_Submissions_{DateTimeOffset.Now:yyyyMMddHHmmss}.xlsx"); } /// @@ -656,21 +652,22 @@ public async Task SubmissionSheet([FromRoute] int id, Cancellatio /// 操作无效 /// 比赛未找到 [RequireUser] - [HttpGet("{id}/Challenges/{challengeId}")] + [HttpGet("{id:int}/Challenges/{challengeId:int}")] [ProducesResponseType(typeof(ChallengeDetailModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task GetChallenge([FromRoute] int id, [FromRoute] int challengeId, CancellationToken token) + public async Task GetChallenge([FromRoute] int id, [FromRoute] int challengeId, + CancellationToken token) { if (id <= 0 || challengeId <= 0) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Result is not null) return context.Result; - var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); + Instance? instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) return NotFound(new RequestResponse("题目未找到或动态附件分配失败", StatusCodes.Status404NotFound)); @@ -692,14 +689,15 @@ public async Task GetChallenge([FromRoute] int id, [FromRoute] in /// 操作无效 /// 比赛未找到 [RequireUser] - [HttpPost("{id}/Challenges/{challengeId}")] + [HttpPost("{id:int}/Challenges/{challengeId:int}")] [EnableRateLimiting(nameof(RateLimiter.LimitPolicy.Submit))] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Submit([FromRoute] int id, [FromRoute] int challengeId, [FromBody] FlagSubmitModel model, CancellationToken token) + public async Task Submit([FromRoute] int id, [FromRoute] int challengeId, + [FromBody] FlagSubmitModel model, CancellationToken token) { - var context = await GetContextInfo(id, challengeId, false, token: token); + ContextInfo context = await GetContextInfo(id, challengeId, token: token); if (context.Result is not null) return context.Result; @@ -713,7 +711,7 @@ public async Task Submit([FromRoute] int id, [FromRoute] int chal Team = context.Participation!.Team, Participation = context.Participation!, Status = AnswerResult.FlagSubmitted, - SubmitTimeUTC = DateTimeOffset.UtcNow, + SubmitTimeUTC = DateTimeOffset.UtcNow }; submission = await submissionRepository.AddSubmission(submission, token); @@ -737,14 +735,15 @@ public async Task Submit([FromRoute] int id, [FromRoute] int chal /// 成功获取比赛提交状态 /// 提交未找到 [RequireUser] - [HttpGet("{id}/Challenges/{challengeId}/Status/{submitId}")] + [HttpGet("{id:int}/Challenges/{challengeId:int}/Status/{submitId:int}")] [ProducesResponseType(typeof(AnswerResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task Status([FromRoute] int id, [FromRoute] int challengeId, [FromRoute] int submitId, CancellationToken token) + public async Task Status([FromRoute] int id, [FromRoute] int challengeId, [FromRoute] int submitId, + CancellationToken token) { var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); - var submission = await submissionRepository.GetSubmission(id, challengeId, userId!, submitId, token); + Submission? submission = await submissionRepository.GetSubmission(id, challengeId, userId!, submitId, token); if (submission is null) return NotFound(new RequestResponse("提交未找到", StatusCodes.Status404NotFound)); @@ -752,7 +751,7 @@ public async Task Status([FromRoute] int id, [FromRoute] int chal return Ok(submission.Status switch { AnswerResult.CheatDetected => AnswerResult.WrongAnswer, - var x => x, + var x => x }); } @@ -768,13 +767,13 @@ public async Task Status([FromRoute] int id, [FromRoute] int chal /// 提交不符合要求 /// 比赛未找到 [RequireUser] - [HttpGet("{id}/Writeup")] + [HttpGet("{id:int}/Writeup")] [ProducesResponseType(typeof(BasicWriteupInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task GetWriteup([FromRoute] int id, CancellationToken token) { - var context = await GetContextInfo(id, denyAfterEnded: false, token: token); + ContextInfo context = await GetContextInfo(id, denyAfterEnded: false, token: token); if (context.Result is not null) return context.Result; @@ -795,7 +794,7 @@ public async Task GetWriteup([FromRoute] int id, CancellationToke /// 提交不符合要求 /// 比赛未找到 [RequireUser] - [HttpPost("{id}/Writeup")] + [HttpPost("{id:int}/Writeup")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] @@ -810,29 +809,25 @@ public async Task SubmitWriteup([FromRoute] int id, IFormFile fil if (file.ContentType != "application/pdf" || Path.GetExtension(file.FileName) != ".pdf") return BadRequest(new RequestResponse("请上传 pdf 文件")); - var context = await GetContextInfo(id, denyAfterEnded: false, token: token); + ContextInfo context = await GetContextInfo(id, denyAfterEnded: false, token: token); if (context.Result is not null) return context.Result; - var game = context.Game!; - var part = context.Participation!; - var team = part.Team; + Game game = context.Game!; + Participation part = context.Participation!; + Team team = part.Team; if (DateTimeOffset.UtcNow > game.WriteupDeadline) return BadRequest(new RequestResponse("提交截止时间已过")); - var wp = context.Participation!.Writeup; + LocalFile? wp = context.Participation!.Writeup; if (wp is not null) await fileService.DeleteFile(wp, token); - wp = await fileService.CreateOrUpdateFile(file, $"Writeup-{game.Id}-{team.Id}-{DateTimeOffset.Now:yyyyMMdd-HH.mm.ssZ}.pdf", token); - - if (wp is null) - return BadRequest(new RequestResponse("保存文件失败")); - - part.Writeup = wp; + part.Writeup = await fileService.CreateOrUpdateFile(file, + $"Writeup-{game.Id}-{team.Id}-{DateTimeOffset.Now:yyyyMMdd-HH.mm.ssZ}.pdf", token); await participationRepository.SaveAsync(token); @@ -854,20 +849,21 @@ public async Task SubmitWriteup([FromRoute] int id, IFormFile fil /// 题目未找到 /// 题目不可创建容器 [RequireUser] - [HttpPost("{id}/Container/{challengeId}")] + [HttpPost("{id:int}/Container/{challengeId:int}")] [EnableRateLimiting(nameof(RateLimiter.LimitPolicy.Container))] [ProducesResponseType(typeof(ContainerInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status429TooManyRequests)] - public async Task CreateContainer([FromRoute] int id, [FromRoute] int challengeId, CancellationToken token) + public async Task CreateContainer([FromRoute] int id, [FromRoute] int challengeId, + CancellationToken token) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Result is not null) return context.Result; - var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); + Instance? instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -889,13 +885,15 @@ public async Task CreateContainer([FromRoute] int id, [FromRoute] await containerRepository.RemoveContainer(instance.Container, token); } - return await instanceRepository.CreateContainer(instance, context.Participation!.Team, context.User!, context.Game!.ContainerCountLimit, token) switch - { - null or (TaskStatus.Failed, null) => BadRequest(new RequestResponse("题目创建容器失败")), - (TaskStatus.Denied, null) => BadRequest(new RequestResponse($"队伍容器数目不能超过 {context.Game.ContainerCountLimit}")), - (TaskStatus.Success, var x) => Ok(ContainerInfoModel.FromContainer(x!)), - _ => throw new NotImplementedException(), - }; + return await instanceRepository.CreateContainer(instance, context.Participation!.Team, context.User!, + context.Game!.ContainerCountLimit, token) switch + { + null or (TaskStatus.Failed, null) => BadRequest(new RequestResponse("题目创建容器失败")), + (TaskStatus.Denied, null) => BadRequest( + new RequestResponse($"队伍容器数目不能超过 {context.Game.ContainerCountLimit}")), + (TaskStatus.Success, var x) => Ok(ContainerInfoModel.FromContainer(x!)), + _ => throw new NotImplementedException() + }; } /// @@ -911,19 +909,20 @@ null or (TaskStatus.Failed, null) => BadRequest(new RequestResponse("题目创 /// 题目未找到 /// 容器未创建或无法延期 [RequireUser] - [HttpPost("{id}/Container/{challengeId}/Prolong")] + [HttpPost("{id:int}/Container/{challengeId:int}/Prolong")] [EnableRateLimiting(nameof(RateLimiter.LimitPolicy.Container))] [ProducesResponseType(typeof(ContainerInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] - public async Task ProlongContainer([FromRoute] int id, [FromRoute] int challengeId, CancellationToken token) + public async Task ProlongContainer([FromRoute] int id, [FromRoute] int challengeId, + CancellationToken token) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Result is not null) return context.Result; - var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); + Instance? instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -955,20 +954,21 @@ public async Task ProlongContainer([FromRoute] int id, [FromRoute /// 题目未找到 /// 题目不可创建容器 [RequireUser] - [HttpDelete("{id}/Container/{challengeId}")] + [HttpDelete("{id:int}/Container/{challengeId:int}")] [EnableRateLimiting(nameof(RateLimiter.LimitPolicy.Container))] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status429TooManyRequests)] - public async Task DeleteContainer([FromRoute] int id, [FromRoute] int challengeId, CancellationToken token) + public async Task DeleteContainer([FromRoute] int id, [FromRoute] int challengeId, + CancellationToken token) { - var context = await GetContextInfo(id, token: token); + ContextInfo context = await GetContextInfo(id, token: token); if (context.Result is not null) return context.Result; - var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); + Instance? instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); @@ -992,47 +992,31 @@ public async Task DeleteContainer([FromRoute] int id, [FromRoute] instance.LastContainerOperation = DateTimeOffset.UtcNow; - await gameEventRepository.AddEvent(new() - { - Type = EventType.ContainerDestroy, - GameId = context.Game!.Id, - TeamId = context.Participation!.TeamId, - UserId = context.User!.Id, - Content = $"{instance.Challenge.Title}#{instance.Challenge.Id} 销毁容器实例" - }, token); + await gameEventRepository.AddEvent( + new() + { + Type = EventType.ContainerDestroy, + GameId = context.Game!.Id, + TeamId = context.Participation!.TeamId, + UserId = context.User!.Id, + Content = $"{instance.Challenge.Title}#{instance.Challenge.Id} 销毁容器实例" + }, token); - logger.Log($"{context.Participation!.Team.Name} 销毁题目 {instance.Challenge.Title} 的容器实例 [{destroyId}]", context.User, TaskStatus.Success); + logger.Log($"{context.Participation!.Team.Name} 销毁题目 {instance.Challenge.Title} 的容器实例 [{destroyId}]", + context.User, TaskStatus.Success); return Ok(); } - private class ContextInfo - { - public Game? Game = default!; - public UserInfo? User = default!; - public Challenge? Challenge = default!; - public Participation? Participation = default!; - public IActionResult? Result = null; - - public ContextInfo WithResult(IActionResult res) - { - Result = res; - return this; - } - }; - - private async Task GetContextInfo(int id, int challengeId = 0, bool withFlag = false, bool denyAfterEnded = true, CancellationToken token = default) + async Task GetContextInfo(int id, int challengeId = 0, bool withFlag = false, + bool denyAfterEnded = true, CancellationToken token = default) { - ContextInfo res = new() - { - User = await userManager.GetUserAsync(User), - Game = await gameRepository.GetGameById(id, token) - }; + ContextInfo res = new() { User = await userManager.GetUserAsync(User), Game = await gameRepository.GetGameById(id, token) }; if (res.Game is null) return res.WithResult(NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound))); - var part = await participationRepository.GetParticipation(res.User!, res.Game, token); + Participation? part = await participationRepository.GetParticipation(res.User!, res.Game, token); if (part is null) return res.WithResult(BadRequest(new RequestResponse("您尚未参赛"))); @@ -1050,7 +1034,7 @@ private async Task GetContextInfo(int id, int challengeId = 0, bool if (challengeId > 0) { - var challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token); + Challenge? challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token); if (challenge is null) return res.WithResult(NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound))); @@ -1061,7 +1045,7 @@ private async Task GetContextInfo(int id, int challengeId = 0, bool return res; } - private static Task> GetDirNamesAsInt(string dir) + static Task> GetDirNamesAsInt(string dir) { if (!Directory.Exists(dir)) return Task.FromResult(new List()); @@ -1072,4 +1056,19 @@ private static Task> GetDirNamesAsInt(string dir) return int.TryParse(name, out var res) ? res : -1; }).Where(d => d > 0).ToList()); } -} + + class ContextInfo + { + public Challenge? Challenge; + public Game? Game; + public Participation? Participation; + public IActionResult? Result; + public UserInfo? User; + + public ContextInfo WithResult(IActionResult res) + { + Result = res; + return this; + } + } +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/InfoController.cs b/src/GZCTF/Controllers/InfoController.cs index 5e60fbfc8..d98243ab9 100644 --- a/src/GZCTF/Controllers/InfoController.cs +++ b/src/GZCTF/Controllers/InfoController.cs @@ -2,7 +2,6 @@ using GZCTF.Models.Internal; using GZCTF.Models.Request.Info; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -18,7 +17,6 @@ public class InfoController(ICaptchaExtension captcha, IOptionsSnapshot globalConfig, IOptionsSnapshot accountPolicy) : ControllerBase { - /// /// 获取最新文章 /// @@ -29,8 +27,8 @@ public class InfoController(ICaptchaExtension captcha, /// 成功获取文章 [HttpGet("Posts/Latest")] [ProducesResponseType(typeof(PostInfoModel[]), StatusCodes.Status200OK)] - public async Task GetLatestPosts(CancellationToken token) - => Ok((await postRepository.GetPosts(token)).Take(20).Select(PostInfoModel.FromPost)); + public async Task GetLatestPosts(CancellationToken token) => + Ok((await postRepository.GetPosts(token)).Take(20).Select(PostInfoModel.FromPost)); /// /// 获取全部文章 @@ -42,8 +40,7 @@ public async Task GetLatestPosts(CancellationToken token) /// 成功获取文章 [HttpGet("Posts")] [ProducesResponseType(typeof(PostInfoModel[]), StatusCodes.Status200OK)] - public async Task GetPosts(CancellationToken token) - => Ok((await postRepository.GetPosts(token)).Select(PostInfoModel.FromPost)); + public async Task GetPosts(CancellationToken token) => Ok((await postRepository.GetPosts(token)).Select(PostInfoModel.FromPost)); /// /// 获取文章详情 @@ -60,7 +57,7 @@ public async Task GetPosts(CancellationToken token) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task GetPost(string id, CancellationToken token) { - var post = await postRepository.GetPostByIdFromCache(id, token); + Post? post = await postRepository.GetPostByIdFromCache(id, token); if (post is null) return NotFound(new RequestResponse("文章不存在", StatusCodes.Status404NotFound)); @@ -88,6 +85,5 @@ public async Task GetPost(string id, CancellationToken token) /// 成功获取 Captcha 配置 [HttpGet("Captcha")] [ProducesResponseType(typeof(ClientCaptchaInfoModel), StatusCodes.Status200OK)] - public IActionResult GetClientCaptchaInfo() - => Ok(accountPolicy.Value.UseCaptcha ? captcha.ClientInfo() : new ClientCaptchaInfoModel()); -} + public IActionResult GetClientCaptchaInfo() => Ok(accountPolicy.Value.UseCaptcha ? captcha.ClientInfo() : new ClientCaptchaInfoModel()); +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/ProxyController.cs b/src/GZCTF/Controllers/ProxyController.cs index 1a52b59c2..7ad99d716 100644 --- a/src/GZCTF/Controllers/ProxyController.cs +++ b/src/GZCTF/Controllers/ProxyController.cs @@ -1,10 +1,12 @@ -using System.Net; +using System.Diagnostics.CodeAnalysis; +using System.Net; using System.Net.Sockets; using System.Net.WebSockets; +using System.Text.Encodings.Web; using System.Text.Json; using GZCTF.Models.Internal; using GZCTF.Repositories.Interface; -using GZCTF.Utils; +using GZCTF.Services.Cache; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; @@ -19,15 +21,16 @@ namespace GZCTF.Controllers; public class ProxyController(ILogger logger, IDistributedCache cache, IOptions provider, IContainerRepository containerRepository) : ControllerBase { - private readonly bool _enablePlatformProxy = provider.Value.PortMappingType == ContainerPortMappingType.PlatformProxy; - private readonly bool _enableTrafficCapture = provider.Value.EnableTrafficCapture; - private const int BUFFER_SIZE = 1024 * 4; - private const uint CONNECTION_LIMIT = 64; - private readonly JsonSerializerOptions _JsonOptions = new() - { - Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - WriteIndented = true, - }; + const int BufferSize = 1024 * 4; + const uint ConnectionLimit = 64; + readonly bool _enablePlatformProxy = provider.Value.PortMappingType == ContainerPortMappingType.PlatformProxy; + readonly bool _enableTrafficCapture = provider.Value.EnableTrafficCapture; + + readonly JsonSerializerOptions _jsonOptions = new() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true }; + + readonly DistributedCacheEntryOptions _storeOption = new() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(10) }; + + readonly DistributedCacheEntryOptions _validOption = new() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) }; /// /// 采用 websocket 代理 TCP 流量 @@ -54,17 +57,17 @@ public async Task ProxyForInstance(string id, CancellationToken t if (!await IncrementConnectionCount(id)) return BadRequest(new RequestResponse("容器连接数已达上限")); - var container = await containerRepository.GetContainerWithInstanceById(id, token); + Container? container = await containerRepository.GetContainerWithInstanceById(id, token); if (container is null || container.Instance is null || !container.IsProxy) return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); - var ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); + IPAddress? ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); if (ipAddress is null) return BadRequest(new RequestResponse("容器地址解析失败")); - var clientIp = HttpContext.Connection.RemoteIpAddress; + IPAddress? clientIp = HttpContext.Connection.RemoteIpAddress; var clientPort = HttpContext.Connection.RemotePort; if (clientIp is null) @@ -74,30 +77,22 @@ public async Task ProxyForInstance(string id, CancellationToken t byte[]? metadata = null; if (enable) - { - metadata = JsonSerializer.SerializeToUtf8Bytes(new - { - Challenge = container.Instance.Challenge.Title, - container.Instance.ChallengeId, - - Team = container.Instance.Participation.Team.Name, - container.Instance.Participation.TeamId, - - container.ContainerId, - container.Instance.FlagContext?.Flag - }, _JsonOptions); - } + metadata = JsonSerializer.SerializeToUtf8Bytes( + new + { + Challenge = container.Instance.Challenge.Title, + container.Instance.ChallengeId, + Team = container.Instance.Participation.Team.Name, + container.Instance.Participation.TeamId, + container.ContainerId, + container.Instance.FlagContext?.Flag + }, _jsonOptions); IPEndPoint client = new(clientIp, clientPort); IPEndPoint target = new(ipAddress, container.Port); - return await DoContainerProxy(id, client, target, metadata, new() - { - Source = client, - Dest = target, - EnableCapture = enable, - FilePath = container.TrafficPath(HttpContext.Connection.Id), - }, token); + return await DoContainerProxy(id, client, target, metadata, + new() { Source = client, Dest = target, EnableCapture = enable, FilePath = container.TrafficPath(HttpContext.Connection.Id) }, token); } /// @@ -111,6 +106,7 @@ public async Task ProxyForInstance(string id, CancellationToken t [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status418ImATeapot)] + [SuppressMessage("ReSharper", "RouteTemplates.ParameterTypeCanBeMadeStricter")] public async Task ProxyForNoInstance(string id, CancellationToken token = default) { if (!_enablePlatformProxy) @@ -122,17 +118,17 @@ public async Task ProxyForNoInstance(string id, CancellationToken if (!HttpContext.WebSockets.IsWebSocketRequest) return NoContent(); - var container = await containerRepository.GetContainerById(id, token); + Container? container = await containerRepository.GetContainerById(id, token); if (container is null || container.InstanceId != 0 || !container.IsProxy) return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); - var ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); + IPAddress? ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); if (ipAddress is null) return BadRequest(new RequestResponse("容器地址解析失败")); - var clientIp = HttpContext.Connection.RemoteIpAddress; + IPAddress? clientIp = HttpContext.Connection.RemoteIpAddress; var clientPort = HttpContext.Connection.RemotePort; if (clientIp is null) @@ -144,12 +140,12 @@ public async Task ProxyForNoInstance(string id, CancellationToken return await DoContainerProxy(id, client, target, null, new(), token); } - internal async Task DoContainerProxy(string id, IPEndPoint client, IPEndPoint target, - byte[]? metadata, CapturableNetworkStreamOptions options, CancellationToken token = default) + async Task DoContainerProxy(string id, IPEndPoint client, IPEndPoint target, + byte[]? metadata, RecordableNetworkStreamOptions options, CancellationToken token = default) { using var socket = new Socket(target.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - CapturableNetworkStream? stream; + RecordableNetworkStream? stream; try { await socket.ConnectAsync(target, token); @@ -157,23 +153,25 @@ internal async Task DoContainerProxy(string id, IPEndPoint client if (!socket.Connected) throw new SocketException((int)SocketError.NotConnected); - stream = new CapturableNetworkStream(socket, metadata, options); + stream = new RecordableNetworkStream(socket, metadata, options); } catch (SocketException e) { - logger.SystemLog($"容器连接失败({e.SocketErrorCode}),可能正在启动中或请检查网络配置 -> {target.Address}:{target.Port}", TaskStatus.Failed, LogLevel.Debug); + logger.SystemLog($"容器连接失败({e.SocketErrorCode}),可能正在启动中或请检查网络配置 -> {target.Address}:{target.Port}", + TaskStatus.Failed, LogLevel.Debug); return new JsonResult(new RequestResponse($"容器连接失败({e.SocketErrorCode})", StatusCodes.Status418ImATeapot)) { StatusCode = StatusCodes.Status418ImATeapot }; } - using var ws = await HttpContext.WebSockets.AcceptWebSocketAsync(); + using WebSocket ws = await HttpContext.WebSockets.AcceptWebSocketAsync(); try { var (tx, rx) = await RunProxy(stream, ws, token); - logger.SystemLog($"[{id}] {client.Address} -> {target.Address}:{target.Port}, tx {tx}, rx {rx}", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog($"[{id}] {client.Address} -> {target.Address}:{target.Port}, tx {tx}, rx {rx}", + TaskStatus.Success, LogLevel.Debug); } catch (Exception e) { @@ -195,22 +193,23 @@ internal async Task DoContainerProxy(string id, IPEndPoint client /// /// /// - internal static async Task<(ulong, ulong)> RunProxy(CapturableNetworkStream stream, WebSocket ws, CancellationToken token = default) + static async Task<(ulong, ulong)> RunProxy(RecordableNetworkStream stream, WebSocket ws, + CancellationToken token = default) { var cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(TimeSpan.FromMinutes(30)); - var ct = cts.Token; + CancellationToken ct = cts.Token; ulong tx = 0, rx = 0; - var sender = Task.Run(async () => + Task sender = Task.Run(async () => { - var buffer = new byte[BUFFER_SIZE]; + var buffer = new byte[BufferSize]; try { while (true) { - var status = await ws.ReceiveAsync(buffer, ct); + WebSocketReceiveResult status = await ws.ReceiveAsync(buffer, ct); if (status.CloseStatus.HasValue) break; if (status.Count > 0) @@ -221,13 +220,12 @@ internal async Task DoContainerProxy(string id, IPEndPoint client } } catch (TaskCanceledException) { } - catch (Exception) { throw; } finally { cts.Cancel(); } }, ct); - var receiver = Task.Run(async () => + Task receiver = Task.Run(async () => { - var buffer = new byte[BUFFER_SIZE]; + var buffer = new byte[BufferSize]; try { while (true) @@ -238,12 +236,12 @@ internal async Task DoContainerProxy(string id, IPEndPoint client await ws.CloseAsync(WebSocketCloseStatus.Empty, null, token); break; } + rx += (ulong)count; await ws.SendAsync(buffer.AsMemory(0, count), WebSocketMessageType.Binary, true, ct); } } catch (TaskCanceledException) { } - catch (Exception) { throw; } finally { cts.Cancel(); } }, ct); @@ -252,23 +250,13 @@ internal async Task DoContainerProxy(string id, IPEndPoint client return (tx, rx); } - private readonly DistributedCacheEntryOptions _validOption = new() - { - AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) - }; - - private readonly DistributedCacheEntryOptions _storeOption = new() - { - AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(10) - }; - /// /// 容器存在性校验 /// /// 容器 id /// /// - internal async Task ValidateContainer(string id, CancellationToken token = default) + async Task ValidateContainer(string id, CancellationToken token = default) { var key = CacheKey.ConnectionCount(id); var bytes = await cache.GetAsync(key, token); @@ -289,7 +277,7 @@ internal async Task ValidateContainer(string id, CancellationToken token = /// /// 容器 id /// - internal async Task IncrementConnectionCount(string id) + async Task IncrementConnectionCount(string id) { var key = CacheKey.ConnectionCount(id); var bytes = await cache.GetAsync(key); @@ -299,7 +287,7 @@ internal async Task IncrementConnectionCount(string id) var count = BitConverter.ToInt32(bytes); - if (count > CONNECTION_LIMIT) + if (count > ConnectionLimit) return false; await cache.SetAsync(key, BitConverter.GetBytes(count + 1), _storeOption); @@ -312,7 +300,7 @@ internal async Task IncrementConnectionCount(string id) /// /// 容器 id /// - internal async Task DecrementConnectionCount(string id) + async Task DecrementConnectionCount(string id) { var key = CacheKey.ConnectionCount(id); var bytes = await cache.GetAsync(key); @@ -323,12 +311,8 @@ internal async Task DecrementConnectionCount(string id) var count = BitConverter.ToInt32(bytes); if (count > 1) - { await cache.SetAsync(key, BitConverter.GetBytes(count - 1), _storeOption); - } else - { await cache.SetAsync(key, BitConverter.GetBytes(0), _validOption); - } } -} +} \ No newline at end of file diff --git a/src/GZCTF/Controllers/TeamController.cs b/src/GZCTF/Controllers/TeamController.cs index fffd8ed30..870c6d931 100644 --- a/src/GZCTF/Controllers/TeamController.cs +++ b/src/GZCTF/Controllers/TeamController.cs @@ -3,11 +3,11 @@ using GZCTF.Middlewares; using GZCTF.Models.Request.Info; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; namespace GZCTF.Controllers; @@ -17,7 +17,7 @@ namespace GZCTF.Controllers; [ApiController] [Route("api/[controller]")] [Produces(MediaTypeNames.Application.Json)] -public class TeamController(UserManager userManager, +public partial class TeamController(UserManager userManager, IFileRepository fileService, ILogger logger, ITeamRepository teamRepository, @@ -33,12 +33,12 @@ public class TeamController(UserManager userManager, /// /// 成功获取队伍信息 /// 队伍不存在 - [HttpGet("{id}")] + [HttpGet("{id:int}")] [ProducesResponseType(typeof(TeamInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task GetBasicInfo(int id, CancellationToken token) { - var team = await teamRepository.GetTeamById(id, token); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return NotFound(new RequestResponse("队伍不存在", StatusCodes.Status404NotFound)); @@ -61,7 +61,7 @@ public async Task GetBasicInfo(int id, CancellationToken token) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] public async Task GetTeamsInfo(CancellationToken token) { - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); return Ok((await teamRepository.GetUserTeams(user!, token)).Select(t => TeamInfoModel.FromTeam(t))); } @@ -85,9 +85,9 @@ public async Task GetTeamsInfo(CancellationToken token) [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task CreateTeam([FromBody] TeamUpdateModel model, CancellationToken token) { - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); - var teams = await teamRepository.GetUserTeams(user!, token); + Team[] teams = await teamRepository.GetUserTeams(user!, token); if (teams.Length > 1 && teams.Any(t => t.CaptainId == user!.Id)) return BadRequest(new RequestResponse("不允许创建多个队伍")); @@ -95,7 +95,7 @@ public async Task CreateTeam([FromBody] TeamUpdateModel model, Ca if (string.IsNullOrEmpty(model.Name)) return BadRequest(new RequestResponse("队伍名不能为空")); - var team = await teamRepository.CreateTeam(model, user!, token); + Team? team = await teamRepository.CreateTeam(model, user!, token); if (team is null) return BadRequest(new RequestResponse("队伍创建失败")); @@ -120,25 +120,23 @@ public async Task CreateTeam([FromBody] TeamUpdateModel model, Ca /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPut("{id}")] [RequireUser] + [HttpPut("{id:int}")] [ProducesResponseType(typeof(TeamInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] - public async Task UpdateTeam([FromRoute] int id, [FromBody] TeamUpdateModel model, CancellationToken token) + public async Task UpdateTeam([FromRoute] int id, [FromBody] TeamUpdateModel model, + CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; team.UpdateInfo(model); @@ -160,35 +158,33 @@ public async Task UpdateTeam([FromRoute] int id, [FromBody] TeamU /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPut("{id}/Transfer")] [RequireUser] + [HttpPut("{id:int}/Transfer")] [ProducesResponseType(typeof(TeamInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] - public async Task Transfer([FromRoute] int id, [FromBody] TeamTransferModel model, CancellationToken token) + public async Task Transfer([FromRoute] int id, [FromBody] TeamTransferModel model, + CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; if (team.Locked && await teamRepository.AnyActiveGame(team, token)) return BadRequest(new RequestResponse("队伍已锁定")); - var newCaptain = await userManager.Users.SingleOrDefaultAsync(u => u.Id == model.NewCaptainId, cancellationToken: token); + UserInfo? newCaptain = await userManager.Users.SingleOrDefaultAsync(u => u.Id == model.NewCaptainId, token); if (newCaptain is null) return BadRequest(new RequestResponse("移交的用户不存在")); - var newCaptainTeams = await teamRepository.GetUserTeams(newCaptain, token); + Team[] newCaptainTeams = await teamRepository.GetUserTeams(newCaptain, token); if (newCaptainTeams.Count(t => t.CaptainId == newCaptain.Id) >= 3) return BadRequest(new RequestResponse("被移交者所管理的队伍过多")); @@ -210,25 +206,22 @@ public async Task Transfer([FromRoute] int id, [FromBody] TeamTra /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpGet("{id}/Invite")] [RequireUser] + [HttpGet("{id:int}/Invite")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task InviteCode([FromRoute] int id, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; return Ok(team.InviteCode); } @@ -245,25 +238,22 @@ public async Task InviteCode([FromRoute] int id, CancellationToke /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPut("{id}/Invite")] [RequireUser] + [HttpPut("{id:int}/Invite")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task UpdateInviteToken([FromRoute] int id, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; team.UpdateInviteToken(); @@ -285,34 +275,31 @@ public async Task UpdateInviteToken([FromRoute] int id, Cancellat /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPost("{id}/Kick/{userid}")] [RequireUser] + [HttpPost("{id:int}/Kick/{userid}")] [ProducesResponseType(typeof(TeamInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task KickUser([FromRoute] int id, [FromRoute] string userid, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; - var trans = await teamRepository.BeginTransactionAsync(token); + IDbContextTransaction trans = await teamRepository.BeginTransactionAsync(token); try { if (team.Locked && await teamRepository.AnyActiveGame(team, token)) return BadRequest(new RequestResponse("队伍已锁定")); - var kickUser = team.Members.SingleOrDefault(m => m.Id == userid); + UserInfo? kickUser = team.Members.SingleOrDefault(m => m.Id == userid); if (kickUser is null) return BadRequest(new RequestResponse("用户不在队伍中")); @@ -332,6 +319,9 @@ public async Task KickUser([FromRoute] int id, [FromRoute] string } } + [GeneratedRegex(":\\d+:[0-9a-f]{32}")] + private static partial Regex InviteCodeRegex(); + /// /// 接受邀请 /// @@ -344,18 +334,18 @@ public async Task KickUser([FromRoute] int id, [FromRoute] string /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPost("Accept")] [RequireUser] + [HttpPost("Accept")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task Accept([FromBody] string code, CancellationToken cancelToken) { - if (!Regex.IsMatch(code, @":\d+:[0-9a-f]{32}")) + if (!InviteCodeRegex().IsMatch(code)) return BadRequest(new RequestResponse("Code 无效")); - var inviteCode = code[^32..]; + var inviteToken = code[^32..]; var preCode = code[..^33]; var lastColon = preCode.LastIndexOf(':'); @@ -364,22 +354,22 @@ public async Task Accept([FromBody] string code, CancellationToke return BadRequest(new RequestResponse($"队伍 Id 转换错误:{preCode[(lastColon + 1)..]}")); var teamName = preCode[..lastColon]; - var trans = await teamRepository.BeginTransactionAsync(cancelToken); + IDbContextTransaction trans = await teamRepository.BeginTransactionAsync(cancelToken); try { - var team = await teamRepository.GetTeamById(teamId, cancelToken); + Team? team = await teamRepository.GetTeamById(teamId, cancelToken); if (team is null) return BadRequest(new RequestResponse($"{teamName} 队伍未找到")); - if (team.InviteCode != code) + if (team.InviteToken != inviteToken) return BadRequest(new RequestResponse($"{teamName} 邀请无效")); if (team.Locked && await teamRepository.AnyActiveGame(team, cancelToken)) return BadRequest(new RequestResponse($"{teamName} 队伍已锁定")); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); if (team.Members.Any(m => m.Id == user!.Id)) return BadRequest(new RequestResponse("你已经加入此队伍,无需重复加入")); @@ -411,24 +401,24 @@ public async Task Accept([FromBody] string code, CancellationToke /// 队伍不存在 /// 未授权 /// 无权操作 - [HttpPost("{id}/Leave")] [RequireUser] + [HttpPost("{id:int}/Leave")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task Leave([FromRoute] int id, CancellationToken token) { - var trans = await teamRepository.BeginTransactionAsync(token); + IDbContextTransaction trans = await teamRepository.BeginTransactionAsync(token); try { - var team = await teamRepository.GetTeamById(id, token); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); - var user = await userManager.GetUserAsync(User); + UserInfo? user = await userManager.GetUserAsync(User); if (team.Members.All(m => m.Id != user!.Id)) return BadRequest(new RequestResponse("你不在此队伍中,无法离队")); @@ -460,25 +450,22 @@ public async Task Leave([FromRoute] int id, CancellationToken tok /// 用户头像URL /// 非法请求 /// 未授权用户 - [HttpPut("{id}/Avatar")] [RequireUser] + [HttpPut("{id:int}/Avatar")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task Avatar([FromRoute] int id, IFormFile file, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; if (file.Length == 0) return BadRequest(new RequestResponse("文件非法")); @@ -489,7 +476,7 @@ public async Task Avatar([FromRoute] int id, IFormFile file, Canc if (team.AvatarHash is not null) _ = await fileService.DeleteFileByHash(team.AvatarHash, token); - var avatar = await fileService.CreateOrUpdateImage(file, "avatar", 300, token); + LocalFile? avatar = await fileService.CreateOrUpdateImage(file, "avatar", 300, token); if (avatar is null) return BadRequest(new RequestResponse("队伍头像更新失败")); @@ -512,33 +499,30 @@ public async Task Avatar([FromRoute] int id, IFormFile file, Canc /// /// 成功获取队伍信息 /// 队伍不存在 - [HttpDelete("{id}")] [RequireUser] + [HttpDelete("{id:int}")] [ProducesResponseType(typeof(TeamInfoModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status403Forbidden)] public async Task DeleteTeam(int id, CancellationToken token) { - var user = await userManager.GetUserAsync(User); - var team = await teamRepository.GetTeamById(id, token); + UserInfo? user = await userManager.GetUserAsync(User); + Team? team = await teamRepository.GetTeamById(id, token); if (team is null) return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) - { - StatusCode = StatusCodes.Status403Forbidden - }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) { StatusCode = StatusCodes.Status403Forbidden }; if (team.Locked && await teamRepository.AnyActiveGame(team, token)) return BadRequest(new RequestResponse("队伍已锁定")); - await teamRepository.DeleteTeam(team!, token); + await teamRepository.DeleteTeam(team, token); - logger.Log($"删除队伍 {team!.Name}", user, TaskStatus.Success); + logger.Log($"删除队伍 {team.Name}", user, TaskStatus.Success); return Ok(); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Extensions/CacheExtensions.cs b/src/GZCTF/Extensions/CacheExtensions.cs index d12b760cf..129d83084 100644 --- a/src/GZCTF/Extensions/CacheExtensions.cs +++ b/src/GZCTF/Extensions/CacheExtensions.cs @@ -1,5 +1,4 @@ -using GZCTF.Utils; -using MemoryPack; +using MemoryPack; using Microsoft.Extensions.Caching.Distributed; namespace GZCTF.Extensions; @@ -27,7 +26,10 @@ public static async Task GetOrCreateAsync(this IDistributedCache cache, result = MemoryPackSerializer.Deserialize(value); } catch - { } + { + // ignored + } + if (result is not null) return result; } @@ -41,4 +43,4 @@ public static async Task GetOrCreateAsync(this IDistributedCache cache, return result; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Extensions/CaptchaExtension.cs b/src/GZCTF/Extensions/CaptchaExtension.cs index 76352587a..a83ada343 100644 --- a/src/GZCTF/Extensions/CaptchaExtension.cs +++ b/src/GZCTF/Extensions/CaptchaExtension.cs @@ -1,4 +1,5 @@ -using GZCTF.Models.Internal; +using System.Net; +using GZCTF.Models.Internal; using GZCTF.Models.Request.Info; using Microsoft.Extensions.Options; @@ -32,60 +33,60 @@ public class ModelWithCaptcha public class CaptchaExtensionBase(IOptions? options) : ICaptchaExtension { - protected readonly CaptchaConfig? _config = options?.Value; + protected readonly CaptchaConfig? Config = options?.Value; - public ClientCaptchaInfoModel ClientInfo() => new(_config); + public ClientCaptchaInfoModel ClientInfo() => new(Config); - public virtual Task VerifyAsync(ModelWithCaptcha model, HttpContext context, CancellationToken token = default) - => Task.FromResult(true); + public virtual Task VerifyAsync(ModelWithCaptcha model, HttpContext context, + CancellationToken token = default) => + Task.FromResult(true); } public sealed class GoogleRecaptchaExtension(IOptions? options) : CaptchaExtensionBase(options) { - private readonly HttpClient _httpClient = new(); + readonly HttpClient _httpClient = new(); - public override async Task VerifyAsync(ModelWithCaptcha model, HttpContext context, CancellationToken token = default) + public override async Task VerifyAsync(ModelWithCaptcha model, HttpContext context, + CancellationToken token = default) { - if (_config is null || string.IsNullOrWhiteSpace(_config.SecretKey)) + if (Config is null || string.IsNullOrWhiteSpace(Config.SecretKey)) return true; if (string.IsNullOrEmpty(model.Challenge) || context.Connection.RemoteIpAddress is null) return false; - var ip = context.Connection.RemoteIpAddress; - var api = _config.GoogleRecaptcha.VerifyAPIAddress; + IPAddress? ip = context.Connection.RemoteIpAddress; + var api = Config.GoogleRecaptcha.VerifyAPIAddress; - var result = await _httpClient.GetAsync($"{api}?secret={_config.SecretKey}&response={model.Challenge}&remoteip={ip}", token); + HttpResponseMessage result = + await _httpClient.GetAsync($"{api}?secret={Config.SecretKey}&response={model.Challenge}&remoteip={ip}", + token); var res = await result.Content.ReadFromJsonAsync(cancellationToken: token); - return res is not null && res.Success && res.Score >= _config.GoogleRecaptcha.RecaptchaThreshold; + return res is not null && res.Success && res.Score >= Config.GoogleRecaptcha.RecaptchaThreshold; } } public sealed class CloudflareTurnstile(IOptions? options) : CaptchaExtensionBase(options) { - private readonly HttpClient _httpClient = new(); + readonly HttpClient _httpClient = new(); - public override async Task VerifyAsync(ModelWithCaptcha model, HttpContext context, CancellationToken token = default) + public override async Task VerifyAsync(ModelWithCaptcha model, HttpContext context, + CancellationToken token = default) { - if (_config is null || string.IsNullOrWhiteSpace(_config.SecretKey)) + if (Config is null || string.IsNullOrWhiteSpace(Config.SecretKey)) return true; if (string.IsNullOrEmpty(model.Challenge) || context.Connection.RemoteIpAddress is null) return false; - var ip = context.Connection.RemoteIpAddress; + IPAddress? ip = context.Connection.RemoteIpAddress; - TurnstileRequestModel req = new() - { - Secret = _config.SecretKey, - Response = model.Challenge, - RemoteIP = ip.ToString() - }; + TurnstileRequestModel req = new() { Secret = Config.SecretKey, Response = model.Challenge, RemoteIp = ip.ToString() }; const string api = "https://challenges.cloudflare.com/turnstile/v0/siteverify"; - var result = await _httpClient.PostAsJsonAsync(api, req, token); + HttpResponseMessage result = await _httpClient.PostAsJsonAsync(api, req, token); var res = await result.Content.ReadFromJsonAsync(cancellationToken: token); return res is not null && res.Success; @@ -94,9 +95,10 @@ public override async Task VerifyAsync(ModelWithCaptcha model, HttpContext public static class CaptchaServiceExtension { - internal static IServiceCollection AddCaptchaService(this IServiceCollection services, ConfigurationManager configuration) + internal static IServiceCollection AddCaptchaService(this IServiceCollection services, + ConfigurationManager configuration) { - var config = configuration.GetSection(nameof(CaptchaConfig)).Get() ?? new(); + CaptchaConfig config = configuration.GetSection(nameof(CaptchaConfig)).Get() ?? new(); services.Configure(configuration.GetSection(nameof(CaptchaConfig))); @@ -104,7 +106,7 @@ internal static IServiceCollection AddCaptchaService(this IServiceCollection ser { CaptchaProvider.GoogleRecaptcha => services.AddSingleton(), CaptchaProvider.CloudflareTurnstile => services.AddSingleton(), - _ => services.AddSingleton(), + _ => services.AddSingleton() }; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Extensions/ConfigurationBuilderExtensions.cs b/src/GZCTF/Extensions/ConfigurationBuilderExtensions.cs index f467efb33..ac45578bd 100644 --- a/src/GZCTF/Extensions/ConfigurationBuilderExtensions.cs +++ b/src/GZCTF/Extensions/ConfigurationBuilderExtensions.cs @@ -5,6 +5,7 @@ namespace GZCTF.Extensions; public static class ConfigurationBuilderExtensions { - public static IConfigurationBuilder AddEntityConfiguration(this IConfigurationBuilder builder, Action optionsAction) - => builder.Add(new EntityConfigurationSource(optionsAction)); -} + public static IConfigurationBuilder AddEntityConfiguration(this IConfigurationBuilder builder, + Action optionsAction) => + builder.Add(new EntityConfigurationSource(optionsAction)); +} \ No newline at end of file diff --git a/src/GZCTF/Extensions/OtherExtensions.cs b/src/GZCTF/Extensions/OtherExtensions.cs index fd5dc328b..dc2bc7caa 100644 --- a/src/GZCTF/Extensions/OtherExtensions.cs +++ b/src/GZCTF/Extensions/OtherExtensions.cs @@ -1,23 +1,22 @@ using System.Net; -using GZCTF.Utils; namespace GZCTF.Extensions; public static class ListExtensions { - public static int GetSetHashCode(this IList list) - => list.Count + list.Distinct().Aggregate(0, (x, y) => x.GetHashCode() ^ y?.GetHashCode() ?? 0xdead); + public static int GetSetHashCode(this IList list) => + list.Count + list.Distinct().Aggregate(0, (x, y) => x.GetHashCode() ^ y?.GetHashCode() ?? 0xdead); } -public static class IQueryableExtensions +public static class QueryableExtensions { /// /// 如果 count 大于 0 则只获取部分 /// Warn: 可能造成恶意参数注入获取全部数据 /// /// - public static IQueryable TakeAllIfZero(this IQueryable items, int count = 100, int skip = 0) - => count switch + public static IQueryable TakeAllIfZero(this IQueryable items, int count = 100, int skip = 0) => + count switch { > 0 => items.Skip(skip).Take(count), _ => items @@ -26,8 +25,8 @@ public static IQueryable TakeAllIfZero(this IQueryable items, int count public static class ArrayExtensions { - public static ArrayResponse ToResponse(this IEnumerable array, int? tot = null) where T : class - => array switch + public static ArrayResponse ToResponse(this IEnumerable array, int? tot = null) where T : class => + array switch { null => new(Array.Empty()), T[] arr => new(arr, tot), @@ -37,10 +36,8 @@ public static ArrayResponse ToResponse(this IEnumerable array, int? tot public static class IPAddressExtensions { - public static IPAddress[] ResolveIP(this string? host) - { - return (!string.IsNullOrWhiteSpace(host)) + public static IEnumerable ResolveIP(this string? host) => + !string.IsNullOrWhiteSpace(host) ? Dns.GetHostAddresses(host) : Array.Empty(); - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Extensions/SignalRSinkExtension.cs b/src/GZCTF/Extensions/SignalRSinkExtension.cs index 405338cb2..b4474d21b 100644 --- a/src/GZCTF/Extensions/SignalRSinkExtension.cs +++ b/src/GZCTF/Extensions/SignalRSinkExtension.cs @@ -1,5 +1,5 @@ using GZCTF.Hubs; -using GZCTF.Hubs.Client; +using GZCTF.Hubs.Clients; using GZCTF.Models.Request.Admin; using Microsoft.AspNetCore.SignalR; using Serilog; @@ -11,14 +11,15 @@ namespace GZCTF.Extensions; public static class SignalRSinkExtension { - public static LoggerConfiguration SignalR(this LoggerSinkConfiguration loggerConfiguration, IServiceProvider serviceProvider) - => loggerConfiguration.Sink(new SignalRSink(serviceProvider)); + public static LoggerConfiguration SignalR(this LoggerSinkConfiguration loggerConfiguration, + IServiceProvider serviceProvider) => + loggerConfiguration.Sink(new SignalRSink(serviceProvider)); } public class SignalRSink : ILogEventSink { - private readonly IServiceProvider _serviceProvider; - private IHubContext? _hubContext; + readonly IServiceProvider _serviceProvider; + IHubContext? _hubContext; public SignalRSink(IServiceProvider serviceProvider) { @@ -30,7 +31,6 @@ public void Emit(LogEvent logEvent) _hubContext ??= _serviceProvider.GetRequiredService>(); if (logEvent.Level >= LogEventLevel.Information) - { try { _hubContext.Clients.All.ReceivedLog( @@ -45,7 +45,8 @@ public void Emit(LogEvent logEvent) }).Wait(); } catch - { } - } + { + // ignored + } } -} +} \ No newline at end of file diff --git a/src/GZCTF/GZCTF.csproj b/src/GZCTF/GZCTF.csproj index bdbd04e2d..529bccddc 100644 --- a/src/GZCTF/GZCTF.csproj +++ b/src/GZCTF/GZCTF.csproj @@ -1,142 +1,142 @@  - - net7.0 - 0.17.1 - GZ::CTF $(VITE_APP_GIT_NAME)-$(VITE_APP_GIT_SHA) build at $(VITE_APP_BUILD_TIMESTAMP) - enable - enable - true - Latest - false - ClientApp\ - $(DefaultItemExcludes);$(SpaRoot)node_modules\** - 291cc810-6142-49a5-8134-1175254665a9 - Linux - true - $(NoWarn);1591 - http://localhost:63000 - pnpm run dev --host - Debug;Release;GenAPI - 0.17.1 - 4 - preview - True - true - + + net7.0 + 0.17.1 + GZ::CTF $(VITE_APP_GIT_NAME)-$(VITE_APP_GIT_SHA) build at $(VITE_APP_BUILD_TIMESTAMP) + enable + enable + true + Latest + false + ClientApp\ + $(DefaultItemExcludes);$(SpaRoot)node_modules\** + 291cc810-6142-49a5-8134-1175254665a9 + Linux + true + $(NoWarn);1591 + http://localhost:63000 + pnpm run dev --host + Debug;Release;GenAPI + 0.17.1 + 4 + preview + True + true + - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + - - - PreserveNewest - PreserveNewest - - + + + PreserveNewest + PreserveNewest + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + - - - - + + + + - - - - - wwwroot\%(RecursiveDir)%(FileName)%(Extension) - PreserveNewest - true - - - + + + + + wwwroot\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + true + + + diff --git a/src/GZCTF/Hubs/AdminHub.cs b/src/GZCTF/Hubs/AdminHub.cs index 90aeadffc..07219653b 100644 --- a/src/GZCTF/Hubs/AdminHub.cs +++ b/src/GZCTF/Hubs/AdminHub.cs @@ -1,5 +1,4 @@ -using GZCTF.Hubs.Client; -using GZCTF.Utils; +using GZCTF.Hubs.Clients; using Microsoft.AspNetCore.SignalR; namespace GZCTF.Hubs; @@ -16,4 +15,4 @@ public override async Task OnConnectedAsync() await base.OnConnectedAsync(); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Hubs/Clients/IAdminClient.cs b/src/GZCTF/Hubs/Clients/IAdminClient.cs index c6d20c0e3..b18849e54 100644 --- a/src/GZCTF/Hubs/Clients/IAdminClient.cs +++ b/src/GZCTF/Hubs/Clients/IAdminClient.cs @@ -1,6 +1,6 @@ using GZCTF.Models.Request.Admin; -namespace GZCTF.Hubs.Client; +namespace GZCTF.Hubs.Clients; public interface IAdminClient { @@ -8,4 +8,4 @@ public interface IAdminClient /// 接收到广播日志信息 /// public Task ReceivedLog(LogMessageModel log); -} +} \ No newline at end of file diff --git a/src/GZCTF/Hubs/Clients/IMonitorClient.cs b/src/GZCTF/Hubs/Clients/IMonitorClient.cs index a4bdf7fca..66944465d 100644 --- a/src/GZCTF/Hubs/Clients/IMonitorClient.cs +++ b/src/GZCTF/Hubs/Clients/IMonitorClient.cs @@ -11,4 +11,4 @@ public interface IMonitorClient /// 接收到比赛提交信息 /// public Task ReceivedSubmissions(Submission submission); -} +} \ No newline at end of file diff --git a/src/GZCTF/Hubs/Clients/IUserClient.cs b/src/GZCTF/Hubs/Clients/IUserClient.cs index a3d96e598..bf861919d 100644 --- a/src/GZCTF/Hubs/Clients/IUserClient.cs +++ b/src/GZCTF/Hubs/Clients/IUserClient.cs @@ -6,4 +6,4 @@ public interface IUserClient /// 接收到比赛通知信息 /// public Task ReceivedGameNotice(GameNotice notice); -} +} \ No newline at end of file diff --git a/src/GZCTF/Hubs/MonitorHub.cs b/src/GZCTF/Hubs/MonitorHub.cs index 9995d5dc2..2754472d1 100644 --- a/src/GZCTF/Hubs/MonitorHub.cs +++ b/src/GZCTF/Hubs/MonitorHub.cs @@ -1,6 +1,5 @@ using GZCTF.Hubs.Clients; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Primitives; @@ -10,19 +9,19 @@ public class MonitorHub : Hub { public override async Task OnConnectedAsync() { - var context = Context.GetHttpContext(); + HttpContext? context = Context.GetHttpContext(); if (context is null || !await HubHelper.HasMonitor(context) || !context.Request.Query.TryGetValue("game", out StringValues gameId) - || !int.TryParse(gameId, out int gameNumId)) + || !int.TryParse(gameId, out var gameNumId)) { Context.Abort(); return; } var gameRepository = context.RequestServices.GetRequiredService(); - var game = await gameRepository.GetGameById(gameNumId); + Game? game = await gameRepository.GetGameById(gameNumId); if (game is null) { @@ -34,4 +33,4 @@ public override async Task OnConnectedAsync() await Groups.AddToGroupAsync(Context.ConnectionId, $"Game_{gameNumId}"); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Hubs/UserHub.cs b/src/GZCTF/Hubs/UserHub.cs index 246aa59b9..079e81e6e 100644 --- a/src/GZCTF/Hubs/UserHub.cs +++ b/src/GZCTF/Hubs/UserHub.cs @@ -1,6 +1,5 @@ using GZCTF.Hubs.Clients; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Primitives; @@ -10,19 +9,19 @@ public class UserHub : Hub { public override async Task OnConnectedAsync() { - var context = Context.GetHttpContext(); + HttpContext? context = Context.GetHttpContext(); if (context is null || !await HubHelper.HasUser(context) || !context.Request.Query.TryGetValue("game", out StringValues gameId) - || !int.TryParse(gameId, out int gameNumId)) + || !int.TryParse(gameId, out var gameNumId)) { Context.Abort(); return; } var gameRepository = context.RequestServices.GetRequiredService(); - var game = await gameRepository.GetGameById(gameNumId); + Game? game = await gameRepository.GetGameById(gameNumId); if (game is null) { @@ -34,4 +33,4 @@ public override async Task OnConnectedAsync() await Groups.AddToGroupAsync(Context.ConnectionId, $"Game_{gameNumId}"); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Middlewares/PrivilegeAuthentication.cs b/src/GZCTF/Middlewares/PrivilegeAuthentication.cs index 1f212c913..e69ed6a62 100644 --- a/src/GZCTF/Middlewares/PrivilegeAuthentication.cs +++ b/src/GZCTF/Middlewares/PrivilegeAuthentication.cs @@ -1,5 +1,4 @@ using System.Security.Claims; -using GZCTF.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.EntityFrameworkCore; @@ -15,9 +14,6 @@ namespace GZCTF.Middlewares; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class RequirePrivilegeAttribute(Role privilege) : Attribute, IAsyncAuthorizationFilter { - public static IActionResult GetResult(string msg, int code) - => new JsonResult(new RequestResponse(msg, code)) { StatusCode = code }; - public static IActionResult RequireLoginResult => GetResult("请先登录", StatusCodes.Status401Unauthorized); public static IActionResult ForbiddenResult => GetResult("无权访问", StatusCodes.Status403Forbidden); @@ -30,7 +26,8 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) if (context.HttpContext.User.Identity?.IsAuthenticated is true) user = await dbcontext.Users.SingleOrDefaultAsync(u => u.Id == - context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)); + context.HttpContext.User.FindFirstValue(ClaimTypes + .NameIdentifier)); if (user is null) { @@ -52,6 +49,8 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) context.Result = ForbiddenResult; } } + + public static IActionResult GetResult(string msg, int code) => new JsonResult(new RequestResponse(msg, code)) { StatusCode = code }; } /// @@ -82,4 +81,4 @@ public class RequireAdminAttribute : RequirePrivilegeAttribute public RequireAdminAttribute() : base(Role.Admin) { } -} +} \ No newline at end of file diff --git a/src/GZCTF/Middlewares/RateLimiter.cs b/src/GZCTF/Middlewares/RateLimiter.cs index 1b4539398..fbcfe39ea 100644 --- a/src/GZCTF/Middlewares/RateLimiter.cs +++ b/src/GZCTF/Middlewares/RateLimiter.cs @@ -3,7 +3,6 @@ using System.Net.Mime; using System.Security.Claims; using System.Threading.RateLimiting; -using GZCTF.Utils; using Microsoft.AspNetCore.RateLimiting; namespace GZCTF.Middlewares; @@ -36,83 +35,83 @@ public enum LimitPolicy Submit } - public static RateLimiterOptions GetRateLimiterOptions() - => new RateLimiterOptions() - { - RejectionStatusCode = StatusCodes.Status429TooManyRequests, - GlobalLimiter = PartitionedRateLimiter.Create(context => + public static RateLimiterOptions GetRateLimiterOptions() => + new RateLimiterOptions { - string? userId = context?.User.FindFirstValue(ClaimTypes.NameIdentifier); - - if (userId is not null) + RejectionStatusCode = StatusCodes.Status429TooManyRequests, + GlobalLimiter = PartitionedRateLimiter.Create(context => { - return RateLimitPartition.GetSlidingWindowLimiter(userId, key => new() - { - PermitLimit = 150, - Window = TimeSpan.FromMinutes(1), - QueueLimit = 60, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - SegmentsPerWindow = 6, - }); - } + var userId = context?.User.FindFirstValue(ClaimTypes.NameIdentifier); + + if (userId is not null) + return RateLimitPartition.GetSlidingWindowLimiter(userId, + key => new() + { + PermitLimit = 150, + Window = TimeSpan.FromMinutes(1), + QueueLimit = 60, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + SegmentsPerWindow = 6 + }); - var address = context?.Connection?.RemoteIpAddress; + IPAddress? address = context?.Connection?.RemoteIpAddress; - if (address is null || IPAddress.IsLoopback(address)) - return RateLimitPartition.GetNoLimiter(IPAddress.Loopback.ToString()); + if (address is null || IPAddress.IsLoopback(address)) + return RateLimitPartition.GetNoLimiter(IPAddress.Loopback.ToString()); - return RateLimitPartition.GetSlidingWindowLimiter(address.ToString(), key => new() + return RateLimitPartition.GetSlidingWindowLimiter(address.ToString(), + key => new() + { + PermitLimit = 150, + Window = TimeSpan.FromMinutes(1), + QueueLimit = 60, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + SegmentsPerWindow = 6 + }); + }), + OnRejected = async (context, cancellationToken) => { - PermitLimit = 150, - Window = TimeSpan.FromMinutes(1), - QueueLimit = 60, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - SegmentsPerWindow = 6, - }); - }), - OnRejected = async (context, cancellationToken) => - { - context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; - context.HttpContext.Response.ContentType = MediaTypeNames.Application.Json; + context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.HttpContext.Response.ContentType = MediaTypeNames.Application.Json; - var afterSec = (int)TimeSpan.FromMinutes(1).TotalSeconds; + var afterSec = (int)TimeSpan.FromMinutes(1).TotalSeconds; - if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) - afterSec = (int)retryAfter.TotalSeconds; + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out TimeSpan retryAfter)) + afterSec = (int)retryAfter.TotalSeconds; - context.HttpContext.Response.Headers.RetryAfter = afterSec.ToString(NumberFormatInfo.InvariantInfo); - await context.HttpContext.Response.WriteAsJsonAsync( - new RequestResponse($"Too many requests, retry after {afterSec} seconds.", - StatusCodes.Status429TooManyRequests - ), cancellationToken); + context.HttpContext.Response.Headers.RetryAfter = afterSec.ToString(NumberFormatInfo.InvariantInfo); + await context.HttpContext.Response.WriteAsJsonAsync( + new RequestResponse($"Too many requests, retry after {afterSec} seconds.", + StatusCodes.Status429TooManyRequests + ), cancellationToken); + } } - } - .AddConcurrencyLimiter(nameof(LimitPolicy.Concurrency), options => - { - options.PermitLimit = 1; - options.QueueLimit = 20; - }) - .AddFixedWindowLimiter(nameof(LimitPolicy.Register), options => - { - options.PermitLimit = 20; - options.Window = TimeSpan.FromSeconds(150); - }) - .AddTokenBucketLimiter(nameof(LimitPolicy.Container), options => - { - options.TokenLimit = 120; - options.TokensPerPeriod = 30; - options.ReplenishmentPeriod = TimeSpan.FromSeconds(10); - }) - .AddTokenBucketLimiter(nameof(LimitPolicy.Submit), options => - { - options.TokenLimit = 60; - options.TokensPerPeriod = 30; - options.ReplenishmentPeriod = TimeSpan.FromSeconds(5); - }); + .AddConcurrencyLimiter(nameof(LimitPolicy.Concurrency), options => + { + options.PermitLimit = 1; + options.QueueLimit = 20; + }) + .AddFixedWindowLimiter(nameof(LimitPolicy.Register), options => + { + options.PermitLimit = 20; + options.Window = TimeSpan.FromSeconds(150); + }) + .AddTokenBucketLimiter(nameof(LimitPolicy.Container), options => + { + options.TokenLimit = 120; + options.TokensPerPeriod = 30; + options.ReplenishmentPeriod = TimeSpan.FromSeconds(10); + }) + .AddTokenBucketLimiter(nameof(LimitPolicy.Submit), options => + { + options.TokenLimit = 60; + options.TokensPerPeriod = 30; + options.ReplenishmentPeriod = TimeSpan.FromSeconds(5); + }); } public static class RateLimiterExtensions { - public static IApplicationBuilder UseConfiguredRateLimiter(this IApplicationBuilder builder) - => builder.UseRateLimiter(RateLimiter.GetRateLimiterOptions()); -} + public static IApplicationBuilder UseConfiguredRateLimiter(this IApplicationBuilder builder) => + builder.UseRateLimiter(RateLimiter.GetRateLimiterOptions()); +} \ No newline at end of file diff --git a/src/GZCTF/Migrations/20220905103212_InitDb.Designer.cs b/src/GZCTF/Migrations/20220905103212_InitDb.Designer.cs index a0d9d4ef5..8290c469c 100644 --- a/src/GZCTF/Migrations/20220905103212_InitDb.Designer.cs +++ b/src/GZCTF/Migrations/20220905103212_InitDb.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -278,7 +278,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -316,7 +316,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -344,7 +344,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -379,7 +379,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -406,7 +406,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -451,7 +451,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -485,7 +485,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -522,7 +522,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -575,7 +575,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -613,7 +613,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -868,20 +868,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -893,9 +893,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -903,14 +903,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -921,21 +921,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -946,9 +946,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -957,25 +957,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -990,15 +990,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1009,9 +1009,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1019,33 +1019,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1062,9 +1062,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1073,14 +1073,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { - b.HasOne("GZCTF.Models.Team", "ActiveTeam") + b.HasOne("GZCTF.Models.Data.Team", "ActiveTeam") .WithMany() .HasForeignKey("ActiveTeamId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Team", "OwnedTeam") + b.HasOne("GZCTF.Models.Data.Team", "OwnedTeam") .WithMany() .HasForeignKey("OwnedTeamId") .OnDelete(DeleteBehavior.SetNull); @@ -1101,7 +1101,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1110,7 +1110,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1125,7 +1125,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1134,7 +1134,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1143,20 +1143,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1165,12 +1165,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1183,19 +1183,19 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220907163829_AddUserParticipation.Designer.cs b/src/GZCTF/Migrations/20220907163829_AddUserParticipation.Designer.cs index ebb737c91..83582fbeb 100644 --- a/src/GZCTF/Migrations/20220907163829_AddUserParticipation.Designer.cs +++ b/src/GZCTF/Migrations/20220907163829_AddUserParticipation.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -278,7 +278,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -316,7 +316,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -344,7 +344,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -382,7 +382,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -409,7 +409,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -454,7 +454,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -488,7 +488,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -525,7 +525,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -578,7 +578,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -616,7 +616,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -714,7 +714,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -886,20 +886,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -911,9 +911,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -921,14 +921,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -939,21 +939,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -964,9 +964,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -975,25 +975,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1008,15 +1008,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1027,9 +1027,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1037,33 +1037,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1080,9 +1080,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1091,27 +1091,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1137,7 +1137,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1146,7 +1146,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1161,7 +1161,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1170,7 +1170,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1179,20 +1179,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1201,12 +1201,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1219,7 +1219,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1228,12 +1228,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220909041834_AddGameHidden.Designer.cs b/src/GZCTF/Migrations/20220909041834_AddGameHidden.Designer.cs index e065ce46e..fc703a6ec 100644 --- a/src/GZCTF/Migrations/20220909041834_AddGameHidden.Designer.cs +++ b/src/GZCTF/Migrations/20220909041834_AddGameHidden.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -281,7 +281,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -319,7 +319,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -347,7 +347,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -385,7 +385,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -412,7 +412,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -457,7 +457,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -491,7 +491,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -528,7 +528,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -581,7 +581,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -619,7 +619,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -717,7 +717,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -889,20 +889,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -914,9 +914,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -924,14 +924,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -942,21 +942,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -967,9 +967,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -978,25 +978,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1011,15 +1011,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1030,9 +1030,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1040,33 +1040,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1083,9 +1083,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1094,27 +1094,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1140,7 +1140,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1149,7 +1149,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1164,7 +1164,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1173,7 +1173,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1182,20 +1182,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1204,12 +1204,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1222,7 +1222,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1231,12 +1231,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220911143942_AddPracticeMode.Designer.cs b/src/GZCTF/Migrations/20220911143942_AddPracticeMode.Designer.cs index 691420ad4..5a62d30e3 100644 --- a/src/GZCTF/Migrations/20220911143942_AddPracticeMode.Designer.cs +++ b/src/GZCTF/Migrations/20220911143942_AddPracticeMode.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -284,7 +284,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -322,7 +322,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -350,7 +350,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -388,7 +388,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -415,7 +415,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -460,7 +460,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -494,7 +494,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -531,7 +531,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -584,7 +584,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -622,7 +622,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -720,7 +720,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -892,20 +892,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -917,9 +917,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -927,14 +927,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -945,21 +945,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -970,9 +970,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -981,25 +981,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1014,15 +1014,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1033,9 +1033,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1043,33 +1043,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1086,9 +1086,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1097,27 +1097,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1143,7 +1143,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1152,7 +1152,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1167,7 +1167,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1176,7 +1176,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1185,20 +1185,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1207,12 +1207,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1225,7 +1225,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1234,12 +1234,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220913083420_UpdateDataTypes.Designer.cs b/src/GZCTF/Migrations/20220913083420_UpdateDataTypes.Designer.cs index e5b9cd5ae..94f40d0d5 100644 --- a/src/GZCTF/Migrations/20220913083420_UpdateDataTypes.Designer.cs +++ b/src/GZCTF/Migrations/20220913083420_UpdateDataTypes.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -285,7 +285,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -323,7 +323,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -351,7 +351,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -389,7 +389,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -416,7 +416,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -461,7 +461,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -495,7 +495,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -532,7 +532,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -585,7 +585,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -624,7 +624,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -723,7 +723,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -895,20 +895,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -920,9 +920,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -930,14 +930,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -948,21 +948,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -973,9 +973,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -984,25 +984,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1017,15 +1017,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1036,9 +1036,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1046,33 +1046,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1089,9 +1089,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1100,27 +1100,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1146,7 +1146,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1155,7 +1155,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1170,7 +1170,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1179,7 +1179,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1188,20 +1188,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1210,12 +1210,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1228,7 +1228,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1237,12 +1237,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220913135843_AddDataProtectionKeys.Designer.cs b/src/GZCTF/Migrations/20220913135843_AddDataProtectionKeys.Designer.cs index 4a7f721fa..988c3d0ec 100644 --- a/src/GZCTF/Migrations/20220913135843_AddDataProtectionKeys.Designer.cs +++ b/src/GZCTF/Migrations/20220913135843_AddDataProtectionKeys.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -105,7 +105,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -153,7 +153,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -177,7 +177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -191,7 +191,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -285,7 +285,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -323,7 +323,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -351,7 +351,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -389,7 +389,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -416,7 +416,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -461,7 +461,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -495,7 +495,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -532,7 +532,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -585,7 +585,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -624,7 +624,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -723,7 +723,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -914,20 +914,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -939,9 +939,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -949,14 +949,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -967,21 +967,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -992,9 +992,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1003,25 +1003,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1036,15 +1036,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1055,9 +1055,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1065,33 +1065,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1108,9 +1108,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1119,27 +1119,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1165,7 +1165,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1174,7 +1174,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1189,7 +1189,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1198,7 +1198,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1207,20 +1207,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1229,12 +1229,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1247,7 +1247,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1256,12 +1256,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220918120342_AddPrivilegedContainer.Designer.cs b/src/GZCTF/Migrations/20220918120342_AddPrivilegedContainer.Designer.cs index dcd6b5e88..d66c433f1 100644 --- a/src/GZCTF/Migrations/20220918120342_AddPrivilegedContainer.Designer.cs +++ b/src/GZCTF/Migrations/20220918120342_AddPrivilegedContainer.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -108,7 +108,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -156,7 +156,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -180,7 +180,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -194,7 +194,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -224,7 +224,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -288,7 +288,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -326,7 +326,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -354,7 +354,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -392,7 +392,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -419,7 +419,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -464,7 +464,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -498,7 +498,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -535,7 +535,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -588,7 +588,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -627,7 +627,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -726,7 +726,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -917,20 +917,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -942,9 +942,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -952,14 +952,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -970,21 +970,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -995,9 +995,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1006,25 +1006,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1039,15 +1039,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1058,9 +1058,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1068,33 +1068,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1111,9 +1111,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1122,27 +1122,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1168,7 +1168,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1177,7 +1177,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1192,7 +1192,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1201,7 +1201,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1210,20 +1210,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1232,12 +1232,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1250,7 +1250,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1259,12 +1259,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220921174925_UniqueFlagId.Designer.cs b/src/GZCTF/Migrations/20220921174925_UniqueFlagId.Designer.cs index 1f45d6469..6f1e73cb1 100644 --- a/src/GZCTF/Migrations/20220921174925_UniqueFlagId.Designer.cs +++ b/src/GZCTF/Migrations/20220921174925_UniqueFlagId.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -108,7 +108,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -156,7 +156,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -180,7 +180,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -194,7 +194,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -224,7 +224,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -288,7 +288,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -326,7 +326,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -354,7 +354,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -393,7 +393,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -420,7 +420,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -465,7 +465,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -499,7 +499,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -536,7 +536,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -589,7 +589,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -628,7 +628,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -727,7 +727,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -919,20 +919,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -944,9 +944,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -954,14 +954,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -972,21 +972,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -997,9 +997,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1008,25 +1008,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1041,15 +1041,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1060,9 +1060,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1070,33 +1070,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1113,9 +1113,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1124,27 +1124,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1170,7 +1170,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1179,7 +1179,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1194,7 +1194,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1203,7 +1203,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1212,20 +1212,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1234,12 +1234,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1252,7 +1252,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1261,12 +1261,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20220929055922_StorageLimit.Designer.cs b/src/GZCTF/Migrations/20220929055922_StorageLimit.Designer.cs index 6005a1099..849e75c06 100644 --- a/src/GZCTF/Migrations/20220929055922_StorageLimit.Designer.cs +++ b/src/GZCTF/Migrations/20220929055922_StorageLimit.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -159,7 +159,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -183,7 +183,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -291,7 +291,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -329,7 +329,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -357,7 +357,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -396,7 +396,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -423,7 +423,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -468,7 +468,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -502,7 +502,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -539,7 +539,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -592,7 +592,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -631,7 +631,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -730,7 +730,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -922,20 +922,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -947,9 +947,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -957,14 +957,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -975,21 +975,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1000,9 +1000,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1011,25 +1011,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1044,15 +1044,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1063,9 +1063,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Team"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1073,33 +1073,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1116,9 +1116,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1127,27 +1127,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1173,7 +1173,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1182,7 +1182,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1197,7 +1197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1206,7 +1206,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1215,20 +1215,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1237,12 +1237,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1255,7 +1255,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1264,12 +1264,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221109175757_AddWriteupInfo.Designer.cs b/src/GZCTF/Migrations/20221109175757_AddWriteupInfo.Designer.cs index 800cc4fd2..53b619bcc 100644 --- a/src/GZCTF/Migrations/20221109175757_AddWriteupInfo.Designer.cs +++ b/src/GZCTF/Migrations/20221109175757_AddWriteupInfo.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -159,7 +159,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -183,7 +183,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -294,7 +294,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -332,7 +332,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -360,7 +360,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -399,7 +399,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -426,7 +426,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -471,7 +471,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -510,7 +510,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -547,7 +547,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -600,7 +600,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -639,7 +639,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -738,7 +738,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -930,20 +930,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -955,9 +955,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -965,14 +965,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -983,21 +983,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1008,9 +1008,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1019,25 +1019,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1052,21 +1052,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1077,9 +1077,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1087,33 +1087,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1130,9 +1130,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1141,27 +1141,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1187,7 +1187,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1196,7 +1196,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1211,7 +1211,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1220,7 +1220,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1229,20 +1229,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1251,12 +1251,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1269,7 +1269,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1278,12 +1278,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221109200305_AddFileSize.Designer.cs b/src/GZCTF/Migrations/20221109200305_AddFileSize.Designer.cs index e83c6cbd6..450aebc46 100644 --- a/src/GZCTF/Migrations/20221109200305_AddFileSize.Designer.cs +++ b/src/GZCTF/Migrations/20221109200305_AddFileSize.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -24,7 +24,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -159,7 +159,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -183,7 +183,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -294,7 +294,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -332,7 +332,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -360,7 +360,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -399,7 +399,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -432,7 +432,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -477,7 +477,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -516,7 +516,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -553,7 +553,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -606,7 +606,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -645,7 +645,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -744,7 +744,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -936,20 +936,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -961,9 +961,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -971,14 +971,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -989,21 +989,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1014,9 +1014,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1025,25 +1025,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1058,21 +1058,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1083,9 +1083,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1093,33 +1093,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1136,9 +1136,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1147,27 +1147,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1193,7 +1193,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1202,7 +1202,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1217,7 +1217,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1226,7 +1226,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1235,20 +1235,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1257,12 +1257,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1275,7 +1275,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1284,12 +1284,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221111044316_AddWriteupNote.Designer.cs b/src/GZCTF/Migrations/20221111044316_AddWriteupNote.Designer.cs index cf4e94488..7a324d5d0 100644 --- a/src/GZCTF/Migrations/20221111044316_AddWriteupNote.Designer.cs +++ b/src/GZCTF/Migrations/20221111044316_AddWriteupNote.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -112,7 +112,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -160,7 +160,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -184,7 +184,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -302,7 +302,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -341,7 +341,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -370,7 +370,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -409,7 +409,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -442,7 +442,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -487,7 +487,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -526,7 +526,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -563,7 +563,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -617,7 +617,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -656,7 +656,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -755,7 +755,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -947,20 +947,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -972,9 +972,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -982,14 +982,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1000,21 +1000,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1025,9 +1025,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1036,25 +1036,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1069,21 +1069,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1094,9 +1094,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1104,33 +1104,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1147,9 +1147,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1158,27 +1158,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1204,7 +1204,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1213,7 +1213,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1228,7 +1228,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1237,7 +1237,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1246,20 +1246,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1268,12 +1268,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1286,7 +1286,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1295,12 +1295,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221111075728_UpdateFileSizeType.Designer.cs b/src/GZCTF/Migrations/20221111075728_UpdateFileSizeType.Designer.cs index 4f204620a..90bbe66fc 100644 --- a/src/GZCTF/Migrations/20221111075728_UpdateFileSizeType.Designer.cs +++ b/src/GZCTF/Migrations/20221111075728_UpdateFileSizeType.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -112,7 +112,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -160,7 +160,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -184,7 +184,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -302,7 +302,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -341,7 +341,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -370,7 +370,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -409,7 +409,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -442,7 +442,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -487,7 +487,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -526,7 +526,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -563,7 +563,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -617,7 +617,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -656,7 +656,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -755,7 +755,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -947,20 +947,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -972,9 +972,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -982,14 +982,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1000,21 +1000,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1025,9 +1025,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1036,25 +1036,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1069,21 +1069,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1094,9 +1094,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Auther") + b.HasOne("GZCTF.Models.Data.UserInfo", "Auther") .WithMany() .HasForeignKey("AutherId") .OnDelete(DeleteBehavior.SetNull); @@ -1104,33 +1104,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Auther"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1147,9 +1147,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1158,27 +1158,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1204,7 +1204,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1213,7 +1213,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1228,7 +1228,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1237,7 +1237,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1246,20 +1246,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1268,12 +1268,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1286,7 +1286,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1295,12 +1295,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221116064912_FixModelTypo.Designer.cs b/src/GZCTF/Migrations/20221116064912_FixModelTypo.Designer.cs index 7c3d82b44..e7abb1286 100644 --- a/src/GZCTF/Migrations/20221116064912_FixModelTypo.Designer.cs +++ b/src/GZCTF/Migrations/20221116064912_FixModelTypo.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -112,7 +112,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -160,7 +160,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -184,7 +184,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -302,7 +302,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -341,7 +341,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -370,7 +370,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -409,7 +409,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -442,7 +442,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -487,7 +487,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -526,7 +526,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -563,7 +563,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -617,7 +617,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -656,7 +656,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -755,7 +755,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -947,20 +947,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -972,9 +972,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -982,14 +982,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1000,21 +1000,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1025,9 +1025,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1036,25 +1036,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1069,21 +1069,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1094,9 +1094,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1104,33 +1104,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1147,9 +1147,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1158,27 +1158,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1204,7 +1204,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1213,7 +1213,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1228,7 +1228,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1237,7 +1237,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1246,20 +1246,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1268,12 +1268,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1286,7 +1286,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1295,12 +1295,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20221127174109_AddBloodBonus.Designer.cs b/src/GZCTF/Migrations/20221127174109_AddBloodBonus.Designer.cs index 9723321bb..e7556ba3f 100644 --- a/src/GZCTF/Migrations/20221127174109_AddBloodBonus.Designer.cs +++ b/src/GZCTF/Migrations/20221127174109_AddBloodBonus.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -112,7 +112,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -160,7 +160,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -184,7 +184,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -197,7 +197,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -307,7 +307,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -346,7 +346,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -375,7 +375,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -414,7 +414,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -447,7 +447,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -492,7 +492,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -531,7 +531,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -568,7 +568,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -622,7 +622,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -661,7 +661,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -760,7 +760,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -952,20 +952,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -977,9 +977,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -987,14 +987,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1005,21 +1005,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1030,9 +1030,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1041,25 +1041,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1074,21 +1074,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1099,9 +1099,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1109,33 +1109,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1152,9 +1152,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1163,27 +1163,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1209,7 +1209,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1218,7 +1218,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1233,7 +1233,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1242,7 +1242,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1251,20 +1251,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1273,12 +1273,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1291,7 +1291,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1300,12 +1300,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20230418095639_AddConcurrencyStamp.Designer.cs b/src/GZCTF/Migrations/20230418095639_AddConcurrencyStamp.Designer.cs index 9fa22cbab..3017ffcbe 100644 --- a/src/GZCTF/Migrations/20230418095639_AddConcurrencyStamp.Designer.cs +++ b/src/GZCTF/Migrations/20230418095639_AddConcurrencyStamp.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -116,7 +116,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -164,7 +164,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -188,7 +188,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -201,7 +201,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -231,7 +231,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -311,7 +311,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -350,7 +350,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -379,7 +379,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -418,7 +418,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -451,7 +451,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -496,7 +496,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -535,7 +535,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -572,7 +572,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -626,7 +626,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -665,7 +665,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -764,7 +764,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -956,20 +956,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -981,9 +981,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -991,14 +991,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1009,21 +1009,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1034,9 +1034,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1045,25 +1045,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1078,21 +1078,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1103,9 +1103,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1113,33 +1113,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1156,9 +1156,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1167,27 +1167,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1213,7 +1213,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1222,7 +1222,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1237,7 +1237,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1246,7 +1246,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1255,20 +1255,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1277,12 +1277,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1295,7 +1295,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1304,12 +1304,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20230523115626_UpdateParticipationStatus.Designer.cs b/src/GZCTF/Migrations/20230523115626_UpdateParticipationStatus.Designer.cs index f821d7c4c..133aaabdf 100644 --- a/src/GZCTF/Migrations/20230523115626_UpdateParticipationStatus.Designer.cs +++ b/src/GZCTF/Migrations/20230523115626_UpdateParticipationStatus.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -116,7 +116,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -164,7 +164,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -188,7 +188,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -201,7 +201,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -231,7 +231,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -311,7 +311,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -350,7 +350,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -379,7 +379,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -418,7 +418,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -451,7 +451,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -496,7 +496,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -534,7 +534,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -571,7 +571,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -625,7 +625,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -664,7 +664,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -763,7 +763,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -955,20 +955,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -980,9 +980,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -990,14 +990,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1008,21 +1008,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1033,9 +1033,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1044,25 +1044,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1077,21 +1077,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1102,9 +1102,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1112,33 +1112,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1155,9 +1155,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1166,27 +1166,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1212,7 +1212,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1221,7 +1221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1236,7 +1236,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1245,7 +1245,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1254,20 +1254,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1276,12 +1276,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1294,7 +1294,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1303,12 +1303,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20230702191504_AddCheatInfo.Designer.cs b/src/GZCTF/Migrations/20230702191504_AddCheatInfo.Designer.cs index fb6509e6d..b0bbab490 100644 --- a/src/GZCTF/Migrations/20230702191504_AddCheatInfo.Designer.cs +++ b/src/GZCTF/Migrations/20230702191504_AddCheatInfo.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -116,7 +116,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -164,7 +164,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -188,7 +188,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.CheatInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("CheatInfo"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -234,7 +234,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -264,7 +264,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -344,7 +344,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -383,7 +383,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -412,7 +412,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -451,7 +451,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -484,7 +484,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -529,7 +529,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -569,7 +569,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -606,7 +606,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -660,7 +660,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -699,7 +699,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -798,7 +798,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -990,20 +990,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -1015,9 +1015,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -1025,27 +1025,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.CheatInfo", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SourceTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SourceTeam") .WithMany() .HasForeignKey("SourceTeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Submission", "Submission") + b.HasOne("GZCTF.Models.Data.Submission", "Submission") .WithMany() .HasForeignKey("SubmissionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SubmitTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SubmitTeam") .WithMany() .HasForeignKey("SubmitTeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1060,14 +1060,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("SubmitTeam"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1078,21 +1078,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1103,9 +1103,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1114,25 +1114,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1147,21 +1147,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1172,9 +1172,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1182,33 +1182,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1225,9 +1225,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1236,27 +1236,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1282,7 +1282,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1291,7 +1291,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1306,7 +1306,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1315,7 +1315,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1324,20 +1324,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1346,12 +1346,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1364,7 +1364,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1373,12 +1373,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/20230816021558_AddCaptureTraffic.Designer.cs b/src/GZCTF/Migrations/20230816021558_AddCaptureTraffic.Designer.cs index c6ed830c0..9f1444593 100644 --- a/src/GZCTF/Migrations/20230816021558_AddCaptureTraffic.Designer.cs +++ b/src/GZCTF/Migrations/20230816021558_AddCaptureTraffic.Designer.cs @@ -1,6 +1,6 @@ // using System; -using GZCTF.Models; +using GZCTF.Models.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -25,7 +25,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -116,7 +116,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Property("Id") .HasColumnType("text"); @@ -164,7 +164,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Containers"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -188,7 +188,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Attachments"); }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.CheatInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -221,7 +221,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("CheatInfo"); }); - modelBuilder.Entity("GZCTF.Models.Data.Config", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Config", b => { b.Property("ConfigKey") .HasColumnType("text"); @@ -234,7 +234,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -264,7 +264,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -344,7 +344,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -383,7 +383,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -412,7 +412,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -451,7 +451,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -484,7 +484,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -529,7 +529,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -569,7 +569,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -606,7 +606,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -660,7 +660,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -699,7 +699,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -798,7 +798,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -990,20 +990,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -1015,9 +1015,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.Attachment", b => { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") .WithMany() .HasForeignKey("LocalFileId") .OnDelete(DeleteBehavior.SetNull); @@ -1025,27 +1025,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("LocalFile"); }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.Data.CheatInfo", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SourceTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SourceTeam") .WithMany() .HasForeignKey("SourceTeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Submission", "Submission") + b.HasOne("GZCTF.Models.Data.Submission", "Submission") .WithMany() .HasForeignKey("SubmissionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SubmitTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SubmitTeam") .WithMany() .HasForeignKey("SubmitTeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1060,14 +1060,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("SubmitTeam"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1078,21 +1078,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1103,9 +1103,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1114,25 +1114,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1147,21 +1147,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1172,9 +1172,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1182,33 +1182,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1225,9 +1225,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1236,27 +1236,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1282,7 +1282,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1291,7 +1291,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1306,7 +1306,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1315,7 +1315,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1324,20 +1324,20 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1346,12 +1346,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1364,7 +1364,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1373,12 +1373,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Migrations/AppDbContextModelSnapshot.cs b/src/GZCTF/Migrations/AppDbContextModelSnapshot.cs index bca1a247a..989184e97 100644 --- a/src/GZCTF/Migrations/AppDbContextModelSnapshot.cs +++ b/src/GZCTF/Migrations/AppDbContextModelSnapshot.cs @@ -22,7 +22,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LocalFileId") + .HasColumnType("integer"); + + b.Property("RemoteUrl") + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("LocalFileId"); + + b.ToTable("Attachments"); + }); + + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -39,9 +63,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CPUCount") .HasColumnType("integer"); - b.Property("EnableTrafficCapture") - .HasColumnType("boolean"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("uuid"); @@ -59,6 +80,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Difficulty") .HasColumnType("double precision"); + b.Property("EnableTrafficCapture") + .HasColumnType("boolean"); + b.Property("FileName") .HasColumnType("text"); @@ -113,78 +137,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Challenges"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("ContainerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("ExpectStopAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IP") - .IsRequired() - .HasColumnType("text"); - - b.Property("Image") - .IsRequired() - .HasColumnType("text"); - - b.Property("InstanceId") - .HasColumnType("integer"); - - b.Property("IsProxy") - .HasColumnType("boolean"); - - b.Property("Port") - .HasColumnType("integer"); - - b.Property("PublicIP") - .HasColumnType("text"); - - b.Property("PublicPort") - .HasColumnType("integer"); - - b.Property("StartedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Status") - .HasColumnType("smallint"); - - b.HasKey("Id"); - - b.HasIndex("InstanceId"); - - b.ToTable("Containers"); - }); - - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("LocalFileId") - .HasColumnType("integer"); - - b.Property("RemoteUrl") - .HasColumnType("text"); - - b.Property("Type") - .HasColumnType("smallint"); - - b.HasKey("Id"); - - b.HasIndex("LocalFileId"); - - b.ToTable("Attachments"); - }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => { b.Property("Id") @@ -231,7 +183,55 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Configs"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ContainerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExpectStopAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("InstanceId") + .HasColumnType("integer"); + + b.Property("IP") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsProxy") + .HasColumnType("boolean"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("PublicIP") + .HasColumnType("text"); + + b.Property("PublicPort") + .HasColumnType("integer"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.ToTable("Containers"); + }); + + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -261,7 +261,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("FlagContexts"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -341,7 +341,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Games"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -380,7 +380,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("GameEvents"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -409,7 +409,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("GameNotices"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { b.Property("ChallengeId") .HasColumnType("integer"); @@ -448,7 +448,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Instances"); }); - modelBuilder.Entity("GZCTF.Models.LocalFile", b => + modelBuilder.Entity("GZCTF.Models.Data.LocalFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -481,7 +481,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Files"); }); - modelBuilder.Entity("GZCTF.Models.LogModel", b => + modelBuilder.Entity("GZCTF.Models.Data.LogModel", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -526,7 +526,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Logs"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -566,7 +566,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Participations"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { b.Property("Id") .HasMaxLength(8) @@ -603,7 +603,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Posts"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -657,7 +657,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -696,7 +696,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Property("Id") .HasColumnType("text"); @@ -795,7 +795,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { b.Property("GameId") .HasColumnType("integer"); @@ -987,20 +987,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("TeamUserInfo"); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => + { + b.HasOne("GZCTF.Models.Data.LocalFile", "LocalFile") + .WithMany() + .HasForeignKey("LocalFileId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("LocalFile"); + }); + + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Challenges") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "TestContainer") + b.HasOne("GZCTF.Models.Data.Container", "TestContainer") .WithMany() .HasForeignKey("TestContainerId") .OnDelete(DeleteBehavior.SetNull); @@ -1012,37 +1022,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("TestContainer"); }); - modelBuilder.Entity("GZCTF.Models.Data.Attachment", b => - { - b.HasOne("GZCTF.Models.LocalFile", "LocalFile") - .WithMany() - .HasForeignKey("LocalFileId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("LocalFile"); - }); - modelBuilder.Entity("GZCTF.Models.Data.CheatInfo", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SourceTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SourceTeam") .WithMany() .HasForeignKey("SourceTeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Submission", "Submission") + b.HasOne("GZCTF.Models.Data.Submission", "Submission") .WithMany() .HasForeignKey("SubmissionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "SubmitTeam") + b.HasOne("GZCTF.Models.Data.Participation", "SubmitTeam") .WithMany() .HasForeignKey("SubmitTeamId") .OnDelete(DeleteBehavior.Cascade) @@ -1057,14 +1057,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("SubmitTeam"); }); - modelBuilder.Entity("GZCTF.Models.FlagContext", b => + modelBuilder.Entity("GZCTF.Models.Data.FlagContext", b => { b.HasOne("GZCTF.Models.Data.Attachment", "Attachment") .WithMany() .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Flags") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) @@ -1075,21 +1075,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Challenge"); }); - modelBuilder.Entity("GZCTF.Models.GameEvent", b => + modelBuilder.Entity("GZCTF.Models.Data.GameEvent", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameEvents") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId"); @@ -1100,9 +1100,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.GameNotice", b => + modelBuilder.Entity("GZCTF.Models.Data.GameNotice", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("GameNotices") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) @@ -1111,25 +1111,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Game"); }); - modelBuilder.Entity("GZCTF.Models.Instance", b => + modelBuilder.Entity("GZCTF.Models.Data.Instance", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Instances") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Container", "Container") + b.HasOne("GZCTF.Models.Data.Container", "Container") .WithOne("Instance") - .HasForeignKey("GZCTF.Models.Instance", "ContainerId") + .HasForeignKey("GZCTF.Models.Data.Instance", "ContainerId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.FlagContext", "FlagContext") + b.HasOne("GZCTF.Models.Data.FlagContext", "FlagContext") .WithMany() .HasForeignKey("FlagId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Instances") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) @@ -1144,21 +1144,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Participation"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Participations") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany("Participations") .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.LocalFile", "Writeup") + b.HasOne("GZCTF.Models.Data.LocalFile", "Writeup") .WithMany() .HasForeignKey("WriteupId"); @@ -1169,9 +1169,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Writeup"); }); - modelBuilder.Entity("GZCTF.Models.Post", b => + modelBuilder.Entity("GZCTF.Models.Data.Post", b => { - b.HasOne("GZCTF.Models.UserInfo", "Author") + b.HasOne("GZCTF.Models.Data.UserInfo", "Author") .WithMany() .HasForeignKey("AuthorId") .OnDelete(DeleteBehavior.SetNull); @@ -1179,33 +1179,33 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Author"); }); - modelBuilder.Entity("GZCTF.Models.Submission", b => + modelBuilder.Entity("GZCTF.Models.Data.Submission", b => { - b.HasOne("GZCTF.Models.Challenge", "Challenge") + b.HasOne("GZCTF.Models.Data.Challenge", "Challenge") .WithMany("Submissions") .HasForeignKey("ChallengeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany("Submissions") .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Submissions") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany("Submissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.SetNull) @@ -1222,9 +1222,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { - b.HasOne("GZCTF.Models.UserInfo", "Captain") + b.HasOne("GZCTF.Models.Data.UserInfo", "Captain") .WithMany() .HasForeignKey("CaptainId") .OnDelete(DeleteBehavior.Cascade) @@ -1233,27 +1233,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Captain"); }); - modelBuilder.Entity("GZCTF.Models.UserParticipation", b => + modelBuilder.Entity("GZCTF.Models.Data.UserParticipation", b => { - b.HasOne("GZCTF.Models.Game", "Game") + b.HasOne("GZCTF.Models.Data.Game", "Game") .WithMany() .HasForeignKey("GameId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Participation", "Participation") + b.HasOne("GZCTF.Models.Data.Participation", "Participation") .WithMany("Members") .HasForeignKey("ParticipationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", "Team") + b.HasOne("GZCTF.Models.Data.Team", "Team") .WithMany() .HasForeignKey("TeamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", "User") + b.HasOne("GZCTF.Models.Data.UserInfo", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1279,7 +1279,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1288,7 +1288,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1303,7 +1303,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1312,7 +1312,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1321,20 +1321,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeamUserInfo", b => { - b.HasOne("GZCTF.Models.UserInfo", null) + b.HasOne("GZCTF.Models.Data.UserInfo", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GZCTF.Models.Team", null) + b.HasOne("GZCTF.Models.Data.Team", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("GZCTF.Models.Challenge", b => + modelBuilder.Entity("GZCTF.Models.Data.Challenge", b => { b.Navigation("Flags"); @@ -1343,12 +1343,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Container", b => + modelBuilder.Entity("GZCTF.Models.Data.Container", b => { b.Navigation("Instance"); }); - modelBuilder.Entity("GZCTF.Models.Game", b => + modelBuilder.Entity("GZCTF.Models.Data.Game", b => { b.Navigation("Challenges"); @@ -1361,7 +1361,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Participation", b => + modelBuilder.Entity("GZCTF.Models.Data.Participation", b => { b.Navigation("Instances"); @@ -1370,12 +1370,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Submissions"); }); - modelBuilder.Entity("GZCTF.Models.Team", b => + modelBuilder.Entity("GZCTF.Models.Data.Team", b => { b.Navigation("Participations"); }); - modelBuilder.Entity("GZCTF.Models.UserInfo", b => + modelBuilder.Entity("GZCTF.Models.Data.UserInfo", b => { b.Navigation("Submissions"); }); diff --git a/src/GZCTF/Models/AppDbContext.cs b/src/GZCTF/Models/AppDbContext.cs index 2133981a5..7d429bbfa 100644 --- a/src/GZCTF/Models/AppDbContext.cs +++ b/src/GZCTF/Models/AppDbContext.cs @@ -1,6 +1,4 @@ using System.Text.Json; -using GZCTF.Models.Data; -using GZCTF.Utils; using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; @@ -9,23 +7,9 @@ namespace GZCTF.Models; -public class AppDbContext(DbContextOptions options) : IdentityDbContext(options), IDataProtectionKeyContext +public class AppDbContext(DbContextOptions options) : + IdentityDbContext(options), IDataProtectionKeyContext { - private static ValueConverter GetJsonConverter() where T : class, new() - { - var options = new JsonSerializerOptions() { WriteIndented = false }; - return new ValueConverter( - v => JsonSerializer.Serialize(v ?? new(), options), - v => JsonSerializer.Deserialize(v, options) - ); - } - - private static ValueComparer GetEnumerableComparer() - where T : notnull - where TList : IEnumerable, new() - => new((c1, c2) => (c1 == null && c2 == null) || (c2 != null && c1 != null && c1.SequenceEqual(c2)), - c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))); - public DbSet Posts { get; set; } = default!; public DbSet Games { get; set; } = default!; public DbSet Teams { get; set; } = default!; @@ -45,14 +29,30 @@ private static ValueComparer GetEnumerableComparer() public DbSet UserParticipations { get; set; } = default!; public DbSet DataProtectionKeys { get; set; } = default!; + static ValueConverter GetJsonConverter() where T : class, new() + { + var options = new JsonSerializerOptions { WriteIndented = false }; + return new ValueConverter( + v => JsonSerializer.Serialize(v ?? new(), options), + v => JsonSerializer.Deserialize(v, options) + ); + } + + static ValueComparer GetEnumerableComparer() + where T : notnull + where TList : IEnumerable, new() => + new( + (c1, c2) => (c1 == null && c2 == null) || (c2 != null && c1 != null && c1.SequenceEqual(c2)), + c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))); + protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); - var listConverter = GetJsonConverter>(); - var setConverter = GetJsonConverter>(); - var listComparer = GetEnumerableComparer, string>(); - var setComparer = GetEnumerableComparer, string>(); + ValueConverter?, string> listConverter = GetJsonConverter>(); + ValueConverter?, string> setConverter = GetJsonConverter>(); + ValueComparer> listComparer = GetEnumerableComparer, string>(); + ValueComparer> setComparer = GetEnumerableComparer, string>(); builder.Entity(entity => { @@ -235,8 +235,8 @@ protected override void OnModelCreating(ModelBuilder builder) .SetValueComparer(listComparer); entity.HasMany(e => e.Flags) - .WithOne(e => e.Challenge) - .HasForeignKey(e => e.ChallengeId); + .WithOne(e => e.Challenge) + .HasForeignKey(e => e.ChallengeId); entity.HasMany(e => e.Submissions) .WithOne(e => e.Challenge) @@ -326,4 +326,4 @@ protected override void OnModelCreating(ModelBuilder builder) .HasForeignKey(e => e.SubmissionId); }); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Attachment.cs b/src/GZCTF/Models/Data/Attachment.cs index cd61c434a..5ba67a202 100644 --- a/src/GZCTF/Models/Data/Attachment.cs +++ b/src/GZCTF/Models/Data/Attachment.cs @@ -49,11 +49,12 @@ public class Attachment /// /// 附件访问链接 /// - public string? UrlWithName(string? filename = null) => Type switch - { - FileType.None => null, - FileType.Local => LocalFile?.Url(filename), - FileType.Remote => RemoteUrl, - _ => throw new ArgumentException(nameof(Type)) - }; -} + public string? UrlWithName(string? filename = null) => + Type switch + { + FileType.None => null, + FileType.Local => LocalFile?.Url(filename), + FileType.Remote => RemoteUrl, + _ => throw new ArgumentException(nameof(Type)) + }; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Challenge.cs b/src/GZCTF/Models/Data/Challenge.cs index 914f87589..037d8f53f 100644 --- a/src/GZCTF/Models/Data/Challenge.cs +++ b/src/GZCTF/Models/Data/Challenge.cs @@ -1,11 +1,9 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; -using GZCTF.Models.Data; using GZCTF.Models.Request.Edit; -using GZCTF.Utils; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class Challenge { @@ -29,7 +27,7 @@ public class Challenge /// /// 是否启用题目 /// - public bool IsEnabled { get; set; } = false; + public bool IsEnabled { get; set; } /// /// 题目标签 @@ -83,20 +81,20 @@ public class Challenge /// /// 是否需要记录访问流量 /// - public bool EnableTrafficCapture { get; set; } = false; + public bool EnableTrafficCapture { get; set; } /// /// 解决题目人数 /// [Required] - public int AcceptedCount { get; set; } = 0; + public int AcceptedCount { get; set; } /// /// 提交答案的数量 /// [Required] [JsonIgnore] - public int SubmissionCount { get; set; } = 0; + public int SubmissionCount { get; set; } /// /// 初始分数 @@ -134,64 +132,12 @@ public class Challenge /// [NotMapped] public int CurrentScore => - AcceptedCount <= 1 ? OriginalScore : (int)Math.Floor( - OriginalScore * (MinScoreRate + - (1.0 - MinScoreRate) * Math.Exp((1 - AcceptedCount) / Difficulty) - )); - - #region Db Relationship - - /// - /// 题目附件 Id - /// - public int? AttachmentId { get; set; } - - /// - /// 题目附件(动态附件存放于 FlagContext) - /// - public Attachment? Attachment { get; set; } - - /// - /// 测试容器 Id - /// - public string? TestContainerId { get; set; } - - /// - /// 测试容器 - /// - public Container? TestContainer { get; set; } - - /// - /// 题目对应的 Flag 列表 - /// - public List Flags { get; set; } = new(); - - /// - /// 提交 - /// - public List Submissions { get; set; } = new(); - - /// - /// 赛题实例 - /// - public List Instances { get; set; } = new(); - - /// - /// 激活赛题的队伍 - /// - public HashSet Teams { get; set; } = new(); - - /// - /// 比赛 Id - /// - public int GameId { get; set; } - - /// - /// 比赛对象 - /// - public Game Game { get; set; } = default!; - - #endregion Db Relationship + AcceptedCount <= 1 + ? OriginalScore + : (int)Math.Floor( + OriginalScore * (MinScoreRate + + (1.0 - MinScoreRate) * Math.Exp((1 - AcceptedCount) / Difficulty) + )); internal string GenerateFlag(Participation part) { @@ -258,8 +204,62 @@ internal Challenge Update(ChallengeUpdateModel model) // DynamicContainer only EnableTrafficCapture = Type == ChallengeType.DynamicContainer && - (model.EnableTrafficCapture ?? EnableTrafficCapture); + (model.EnableTrafficCapture ?? EnableTrafficCapture); return this; } -} + + #region Db Relationship + + /// + /// 题目附件 Id + /// + public int? AttachmentId { get; set; } + + /// + /// 题目附件(动态附件存放于 FlagContext) + /// + public Attachment? Attachment { get; set; } + + /// + /// 测试容器 Id + /// + public string? TestContainerId { get; set; } + + /// + /// 测试容器 + /// + public Container? TestContainer { get; set; } + + /// + /// 题目对应的 Flag 列表 + /// + public List Flags { get; set; } = new(); + + /// + /// 提交 + /// + public List Submissions { get; set; } = new(); + + /// + /// 赛题实例 + /// + public List Instances { get; set; } = new(); + + /// + /// 激活赛题的队伍 + /// + public HashSet Teams { get; set; } = new(); + + /// + /// 比赛 Id + /// + public int GameId { get; set; } + + /// + /// 比赛对象 + /// + public Game Game { get; set; } = default!; + + #endregion Db Relationship +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/CheatInfo.cs b/src/GZCTF/Models/Data/CheatInfo.cs index 779ab550c..f3f6ed1a2 100644 --- a/src/GZCTF/Models/Data/CheatInfo.cs +++ b/src/GZCTF/Models/Data/CheatInfo.cs @@ -55,4 +55,4 @@ public class CheatInfo public int SubmissionId { get; set; } #endregion Db Relationship -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Config.cs b/src/GZCTF/Models/Data/Config.cs index a72b89482..baa738247 100644 --- a/src/GZCTF/Models/Data/Config.cs +++ b/src/GZCTF/Models/Data/Config.cs @@ -8,16 +8,17 @@ namespace GZCTF.Models.Data; public record Config : IEquatable { public Config() { } + public Config(string key, string value) { ConfigKey = key; Value = value; } - public bool Equal(Config other) - => ConfigKey == other.ConfigKey; - [Key] public string ConfigKey { get; set; } = string.Empty; + public string? Value { get; set; } -} + + public bool Equal(Config other) => ConfigKey == other.ConfigKey; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Container.cs b/src/GZCTF/Models/Data/Container.cs index f986def17..8fc8c8e18 100644 --- a/src/GZCTF/Models/Data/Container.cs +++ b/src/GZCTF/Models/Data/Container.cs @@ -1,8 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using GZCTF.Utils; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class Container { @@ -43,7 +42,7 @@ public class Container /// 是否具备反向代理 /// [Required] - public bool IsProxy { get; set; } = false; + public bool IsProxy { get; set; } /// /// 本地 IP @@ -76,9 +75,11 @@ public class Container /// /// 容器实例流量捕获存储路径 /// - public string TrafficPath(string conn) => Instance is null ? string.Empty : - Path.Combine(FilePath.Capture, - $"{Instance.ChallengeId}/{Instance.ParticipationId}/{DateTimeOffset.Now:yyyyMMdd-HH.mm.ss}-{conn}.pcap"); + public string TrafficPath(string conn) => + Instance is null + ? string.Empty + : Path.Combine(FilePath.Capture, + $"{Instance.ChallengeId}/{Instance.ParticipationId}/{DateTimeOffset.Now:yyyyMMdd-HH.mm.ss}-{conn}.pcap"); #region Db Relationship @@ -93,4 +94,4 @@ public string TrafficPath(string conn) => Instance is null ? string.Empty : public int InstanceId { get; set; } #endregion Db Relationship -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/FlagContext.cs b/src/GZCTF/Models/Data/FlagContext.cs index 7fc22156a..5a32e165a 100644 --- a/src/GZCTF/Models/Data/FlagContext.cs +++ b/src/GZCTF/Models/Data/FlagContext.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; -using GZCTF.Models.Data; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class FlagContext { @@ -42,4 +41,4 @@ public class FlagContext public Challenge? Challenge { get; set; } #endregion Db Relationship -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Game.cs b/src/GZCTF/Models/Data/Game.cs index d27f86f9f..480a39997 100644 --- a/src/GZCTF/Models/Data/Game.cs +++ b/src/GZCTF/Models/Data/Game.cs @@ -2,14 +2,13 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; using GZCTF.Models.Request.Edit; -using GZCTF.Utils; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Encoders; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class Game { @@ -39,7 +38,7 @@ public class Game /// 是否隐藏 /// [Required] - public bool Hidden { get; set; } = false; + public bool Hidden { get; set; } /// /// 头图哈希 @@ -60,7 +59,7 @@ public class Game /// /// 报名队伍免审核 /// - public bool AcceptWithoutReview { get; set; } = false; + public bool AcceptWithoutReview { get; set; } /// /// 比赛邀请码 @@ -75,7 +74,7 @@ public class Game /// /// 队员数量限制, 0 为无上限 /// - public int TeamMemberCountLimit { get; set; } = 0; + public int TeamMemberCountLimit { get; set; } /// /// 队伍同时开启的容器数量限制 @@ -120,51 +119,6 @@ public class Game [JsonIgnore] public bool IsActive => StartTimeUTC <= DateTimeOffset.Now && DateTimeOffset.Now <= EndTimeUTC; - #region Db Relationship - - /// - /// 比赛事件 - /// - [JsonIgnore] - public List GameEvents { get; set; } = new(); - - /// - /// 比赛通知 - /// - [JsonIgnore] - public List GameNotices { get; set; } = new(); - - /// - /// 比赛题目 - /// - [JsonIgnore] - public List Challenges { get; set; } = new(); - - /// - /// 比赛提交 - /// - [JsonIgnore] - public List Submissions { get; set; } = new(); - - /// - /// 比赛队伍参赛对象 - /// - [JsonIgnore] - public HashSet Participations { get; set; } = new(); - - /// - /// 比赛队伍 - /// - [JsonIgnore] - public ICollection? Teams { get; set; } - - /// - /// 比赛是否为练习模式(比赛结束够依然可以进行大部分操作) - /// - public bool PracticeMode { get; set; } = true; - - #endregion Db Relationship - [NotMapped] public string? PosterUrl => PosterHash is null ? null : $"/assets/{PosterHash}/poster"; @@ -177,8 +131,8 @@ internal void GenerateKeyPair(byte[]? xorkey) Ed25519KeyPairGenerator kpg = new(); kpg.Init(new Ed25519KeyGenerationParameters(sr)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); - Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.Private; - Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.Public; + var privateKey = (Ed25519PrivateKeyParameters)kp.Private; + var publicKey = (Ed25519PublicKeyParameters)kp.Public; if (xorkey is null) PrivateKey = Base64.ToBase64String(privateKey.GetEncoded()); @@ -226,4 +180,49 @@ internal Game Update(GameInfoModel model) return this; } -} + + #region Db Relationship + + /// + /// 比赛事件 + /// + [JsonIgnore] + public List GameEvents { get; set; } = new(); + + /// + /// 比赛通知 + /// + [JsonIgnore] + public List GameNotices { get; set; } = new(); + + /// + /// 比赛题目 + /// + [JsonIgnore] + public List Challenges { get; set; } = new(); + + /// + /// 比赛提交 + /// + [JsonIgnore] + public List Submissions { get; set; } = new(); + + /// + /// 比赛队伍参赛对象 + /// + [JsonIgnore] + public HashSet Participations { get; set; } = new(); + + /// + /// 比赛队伍 + /// + [JsonIgnore] + public ICollection? Teams { get; set; } + + /// + /// 比赛是否为练习模式(比赛结束够依然可以进行大部分操作) + /// + public bool PracticeMode { get; set; } = true; + + #endregion Db Relationship +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/GameEvent.cs b/src/GZCTF/Models/Data/GameEvent.cs index 50fd44a75..cb1caa890 100644 --- a/src/GZCTF/Models/Data/GameEvent.cs +++ b/src/GZCTF/Models/Data/GameEvent.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; /// /// 比赛事件,记录但不会发往客户端。 @@ -62,13 +62,14 @@ public class GameEvent [JsonIgnore] public Game? Game { get; set; } - internal static GameEvent FromSubmission(Submission submission, SubmissionType type, AnswerResult ans) - => new() + internal static GameEvent FromSubmission(Submission submission, SubmissionType type, AnswerResult ans) => + new() { TeamId = submission.TeamId, UserId = submission.UserId, GameId = submission.GameId, Type = EventType.FlagSubmit, - Content = $"[{ans.ToShortString()}] {submission.Answer} {submission.Challenge.Title}#{submission.ChallengeId}" + Content = + $"[{ans.ToShortString()}] {submission.Answer} {submission.Challenge.Title}#{submission.ChallengeId}" }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/GameNotice.cs b/src/GZCTF/Models/Data/GameNotice.cs index 57d86aaff..95de546c7 100644 --- a/src/GZCTF/Models/Data/GameNotice.cs +++ b/src/GZCTF/Models/Data/GameNotice.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; using MemoryPack; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; /// /// 比赛通知,会发往客户端。 @@ -42,8 +42,8 @@ public partial class GameNotice [MemoryPackIgnore] public Game? Game { get; set; } - internal static GameNotice FromSubmission(Submission submission, SubmissionType type) - => new() + internal static GameNotice FromSubmission(Submission submission, SubmissionType type) => + new() { Type = type switch { @@ -55,4 +55,4 @@ internal static GameNotice FromSubmission(Submission submission, SubmissionType GameId = submission.GameId, Content = $"恭喜 {submission.Team.Name} 获得 「{submission.Challenge.Title}」 的{type.ToBloodString()}" }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Instance.cs b/src/GZCTF/Models/Data/Instance.cs index 38061442e..fbf265ee1 100644 --- a/src/GZCTF/Models/Data/Instance.cs +++ b/src/GZCTF/Models/Data/Instance.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; -using GZCTF.Models.Data; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class Instance { @@ -25,6 +24,20 @@ public class Instance /// public DateTimeOffset LastContainerOperation { get; set; } = DateTimeOffset.MinValue; + /// + /// 获取实例附件 + /// + internal Attachment? Attachment => Challenge.Type == ChallengeType.DynamicAttachment + ? FlagContext?.Attachment + : Challenge.Attachment; + + /// + /// 获取实例附件链接 + /// + internal string? AttachmentUrl => Challenge.Type == ChallengeType.DynamicAttachment + ? FlagContext?.Attachment?.UrlWithName(Challenge.FileName) + : Challenge.Attachment?.UrlWithName(); + #region Db Relationship public int? FlagId { get; set; } @@ -58,17 +71,4 @@ public class Instance public Participation Participation { get; set; } = default!; #endregion Db Relationship - - /// - /// 获取实例附件 - /// - internal Attachment? Attachment => Challenge.Type == ChallengeType.DynamicAttachment ? - FlagContext?.Attachment : Challenge.Attachment; - - /// - /// 获取实例附件链接 - /// - internal string? AttachmentUrl => Challenge.Type == ChallengeType.DynamicAttachment ? - FlagContext?.Attachment?.UrlWithName(Challenge.FileName) : - Challenge.Attachment?.UrlWithName(); -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/LocalFile.cs b/src/GZCTF/Models/Data/LocalFile.cs index 192ed1bae..98a716e6f 100644 --- a/src/GZCTF/Models/Data/LocalFile.cs +++ b/src/GZCTF/Models/Data/LocalFile.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; [Index(nameof(Hash))] public class LocalFile @@ -53,4 +53,4 @@ public class LocalFile /// 获取文件Url /// public string Url(string? filename = null) => $"/assets/{Hash}/{filename ?? Name}"; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/LogModel.cs b/src/GZCTF/Models/Data/LogModel.cs index 836f56bf1..8ef787131 100644 --- a/src/GZCTF/Models/Data/LogModel.cs +++ b/src/GZCTF/Models/Data/LogModel.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class LogModel { @@ -30,4 +30,4 @@ public class LogModel public string? Status { get; set; } public string? Exception { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Participation.cs b/src/GZCTF/Models/Data/Participation.cs index ba8750cb0..9d1d1e09d 100644 --- a/src/GZCTF/Models/Data/Participation.cs +++ b/src/GZCTF/Models/Data/Participation.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; /// /// 比赛参与信息 @@ -70,4 +70,4 @@ public class Participation public Team Team { get; set; } = default!; #endregion Db Relationship -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Post.cs b/src/GZCTF/Models/Data/Post.cs index e4d98204e..c288c9d97 100644 --- a/src/GZCTF/Models/Data/Post.cs +++ b/src/GZCTF/Models/Data/Post.cs @@ -1,9 +1,8 @@ using System.ComponentModel.DataAnnotations; using GZCTF.Models.Request.Edit; -using GZCTF.Utils; using MemoryPack; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; [MemoryPackable] public partial class Post @@ -34,7 +33,7 @@ public partial class Post /// 是否置顶 /// [Required] - public bool IsPinned { get; set; } = false; + public bool IsPinned { get; set; } /// /// 文章标签 @@ -72,4 +71,4 @@ internal Post Update(PostEditModel model, UserInfo user) } internal void UpdateKeyWithHash() => Id = $"{Title}:{UpdateTimeUTC:s}:{Guid.NewGuid()}".StrSHA256()[4..12]; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Submission.cs b/src/GZCTF/Models/Data/Submission.cs index 959030883..fa03a0b23 100644 --- a/src/GZCTF/Models/Data/Submission.cs +++ b/src/GZCTF/Models/Data/Submission.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; [Index(nameof(UserId))] public class Submission @@ -109,4 +109,4 @@ public class Submission public Challenge Challenge { get; set; } = default!; #endregion Db Relationship -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/Team.cs b/src/GZCTF/Models/Data/Team.cs index 5144da5de..1a9036cf7 100644 --- a/src/GZCTF/Models/Data/Team.cs +++ b/src/GZCTF/Models/Data/Team.cs @@ -2,9 +2,8 @@ using System.ComponentModel.DataAnnotations.Schema; using GZCTF.Models.Request.Admin; using GZCTF.Models.Request.Info; -using Microsoft.IdentityModel.Tokens; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; public class Team { @@ -33,7 +32,7 @@ public class Team /// /// 队伍是否为锁定状态 /// - public bool Locked { get; set; } = false; + public bool Locked { get; set; } /// /// 邀请 Token @@ -46,6 +45,24 @@ public class Team [NotMapped] public string InviteCode => $"{Name}:{Id}:{InviteToken}"; + [NotMapped] + public string? AvatarUrl => AvatarHash is null ? null : $"/assets/{AvatarHash}/avatar"; + + public void UpdateInviteToken() => InviteToken = Guid.NewGuid().ToString("N"); + + internal void UpdateInfo(TeamUpdateModel model) + { + Name = string.IsNullOrEmpty(model.Name) ? Name : model.Name; + Bio = model.Bio; + } + + internal void UpdateInfo(AdminTeamModel model) + { + Name = string.IsNullOrEmpty(model.Name) ? Name : model.Name; + Bio = string.IsNullOrEmpty(model.Bio) ? Bio : model.Bio; + Locked = model.Locked ?? Locked; + } + #region Db Relationship /// @@ -74,22 +91,4 @@ public class Team public HashSet Members { get; set; } = new(); #endregion Db Relationship - - [NotMapped] - public string? AvatarUrl => AvatarHash is null ? null : $"/assets/{AvatarHash}/avatar"; - - public void UpdateInviteToken() => InviteToken = Guid.NewGuid().ToString("N"); - - internal void UpdateInfo(TeamUpdateModel model) - { - Name = string.IsNullOrEmpty(model.Name) ? Name : model.Name; - Bio = model.Bio; - } - - internal void UpdateInfo(AdminTeamModel model) - { - Name = string.IsNullOrEmpty(model.Name) ? Name : model.Name; - Bio = string.IsNullOrEmpty(model.Bio) ? Bio : model.Bio; - Locked = model.Locked ?? Locked; - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/UserInfo.cs b/src/GZCTF/Models/Data/UserInfo.cs index 0e553c7ec..0c9ee1c1f 100644 --- a/src/GZCTF/Models/Data/UserInfo.cs +++ b/src/GZCTF/Models/Data/UserInfo.cs @@ -1,11 +1,12 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Net; using GZCTF.Models.Request.Account; using GZCTF.Models.Request.Admin; using MemoryPack; using Microsoft.AspNetCore.Identity; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; [MemoryPackable] public partial class UserInfo : IdentityUser @@ -57,27 +58,9 @@ public partial class UserInfo : IdentityUser [ProtectedPersonalData] public string StdNumber { get; set; } = string.Empty; - #region 数据库关系 - - /// - /// 头像哈希 - /// - [MaxLength(64)] - public string? AvatarHash { get; set; } - - /// - /// 个人提交记录 - /// - [MemoryPackIgnore] - public List Submissions { get; set; } = new(); - - /// - /// 参与的队伍 - /// + [NotMapped] [MemoryPackIgnore] - public List Teams { get; set; } = new(); - - #endregion 数据库关系 + public string? AvatarUrl => AvatarHash is null ? null : $"/assets/{AvatarHash}/avatar"; /// /// 通过Http请求更新用户最新访问时间和IP @@ -87,7 +70,7 @@ public void UpdateByHttpContext(HttpContext context) { LastVisitedUTC = DateTimeOffset.UtcNow; - var remoteAddress = context.Connection.RemoteIpAddress; + IPAddress? remoteAddress = context.Connection.RemoteIpAddress; if (remoteAddress is null) return; @@ -95,10 +78,6 @@ public void UpdateByHttpContext(HttpContext context) IP = remoteAddress.ToString(); } - [NotMapped] - [MemoryPackIgnore] - public string? AvatarUrl => AvatarHash is null ? null : $"/assets/{AvatarHash}/avatar"; - internal void UpdateUserInfo(AdminUserInfoModel model) { UserName = model.UserName ?? UserName; @@ -128,4 +107,26 @@ internal void UpdateUserInfo(ProfileUpdateModel model) RealName = model.RealName ?? RealName; StdNumber = model.StdNumber ?? StdNumber; } -} + + #region 数据库关系 + + /// + /// 头像哈希 + /// + [MaxLength(64)] + public string? AvatarHash { get; set; } + + /// + /// 个人提交记录 + /// + [MemoryPackIgnore] + public List Submissions { get; set; } = new(); + + /// + /// 参与的队伍 + /// + [MemoryPackIgnore] + public List Teams { get; set; } = new(); + + #endregion 数据库关系 +} \ No newline at end of file diff --git a/src/GZCTF/Models/Data/UserParticipation.cs b/src/GZCTF/Models/Data/UserParticipation.cs index f2c760151..a63ba3785 100644 --- a/src/GZCTF/Models/Data/UserParticipation.cs +++ b/src/GZCTF/Models/Data/UserParticipation.cs @@ -1,11 +1,16 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace GZCTF.Models; +namespace GZCTF.Models.Data; [Index(nameof(ParticipationId))] public class UserParticipation { + /// + /// 参赛对象 + /// + public Participation Participation = default!; + public UserParticipation() { } public UserParticipation(UserInfo user, Game game, Team team) @@ -53,9 +58,4 @@ public UserParticipation(UserInfo user, Game game, Team team) /// [Required] public int ParticipationId { get; set; } - - /// - /// 参赛对象 - /// - public Participation Participation = default!; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Internal/CaptchaModel.cs b/src/GZCTF/Models/Internal/CaptchaModel.cs index fa14c6d16..b6fc00274 100644 --- a/src/GZCTF/Models/Internal/CaptchaModel.cs +++ b/src/GZCTF/Models/Internal/CaptchaModel.cs @@ -1,5 +1,7 @@ using System.Text.Json.Serialization; +// ReSharper disable ClassNeverInstantiated.Global + namespace GZCTF.Models.Internal; /// @@ -31,14 +33,14 @@ public class TurnstileRequestModel [JsonPropertyName("response")] public string Response { get; set; } = string.Empty; + // ReSharper disable once StringLiteralTypo [JsonPropertyName("remoteip")] - public string RemoteIP { get; set; } = string.Empty; + public string RemoteIp { get; set; } = string.Empty; [JsonPropertyName("idempotency_key")] public string IdempotencyKey { get; set; } = string.Empty; } - /// /// Response Model from Cloudflare Turnstile Verify API /// @@ -58,4 +60,4 @@ public class TurnstileResponseModel [JsonPropertyName("error-codes")] public List ErrorCodes { get; set; } = new(); -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Internal/CheatCheckInfo.cs b/src/GZCTF/Models/Internal/CheatCheckInfo.cs index 41b3b8a91..8d5b70552 100644 --- a/src/GZCTF/Models/Internal/CheatCheckInfo.cs +++ b/src/GZCTF/Models/Internal/CheatCheckInfo.cs @@ -1,6 +1,4 @@ -using GZCTF.Models.Data; - -namespace GZCTF.Models.Internal; +namespace GZCTF.Models.Internal; public class CheatCheckInfo { @@ -29,8 +27,8 @@ public class CheatCheckInfo /// public string? Flag { get; set; } - internal static CheatCheckInfo FromCheatInfo(CheatInfo info) - => new() + internal static CheatCheckInfo FromCheatInfo(CheatInfo info) => + new() { Flag = info.Submission.Answer, AnswerResult = AnswerResult.CheatDetected, @@ -38,4 +36,4 @@ internal static CheatCheckInfo FromCheatInfo(CheatInfo info) SourceTeamName = info.SourceTeam.Team.Name, CheatUserName = info.Submission.UserName }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Internal/Configs.cs b/src/GZCTF/Models/Internal/Configs.cs index 5eccb797c..71846fdc6 100644 --- a/src/GZCTF/Models/Internal/Configs.cs +++ b/src/GZCTF/Models/Internal/Configs.cs @@ -4,6 +4,9 @@ using GZCTF.Extensions; using Microsoft.AspNetCore.HttpOverrides; +// ReSharper disable CollectionNeverUpdated.Global + + namespace GZCTF.Models.Internal; /// @@ -24,12 +27,12 @@ public class AccountPolicy /// /// 使用验证码校验 /// - public bool UseCaptcha { get; set; } = false; + public bool UseCaptcha { get; set; } /// /// 注册、更换邮箱、找回密码需要邮件确认 /// - public bool EmailConfirmationRequired { get; set; } = false; + public bool EmailConfirmationRequired { get; set; } /// /// 邮箱后缀域名,以逗号分割 @@ -45,7 +48,7 @@ public class GamePolicy /// /// 是否在达到数量限制时自动销毁最早的容器 /// - public bool AutoDestroyOnLimitReached { get; set; } = false; + public bool AutoDestroyOnLimitReached { get; set; } } /// @@ -101,14 +104,14 @@ public enum ContainerPortMappingType { Default, PlatformProxy, - Frp, + Frp } public class ContainerProvider { public ContainerProviderType Type { get; set; } = ContainerProviderType.Docker; public ContainerPortMappingType PortMappingType { get; set; } = ContainerPortMappingType.Default; - public bool EnableTrafficCapture { get; set; } = false; + public bool EnableTrafficCapture { get; set; } public string PublicEntry { get; set; } = string.Empty; @@ -180,30 +183,27 @@ public class ForwardedOptions : ForwardedHeadersOptions public void ToForwardedHeadersOptions(ForwardedHeadersOptions options) { // assign the same value to the base class via reflection - var type = typeof(ForwardedHeadersOptions); - var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); - foreach (var property in properties) + Type type = typeof(ForwardedHeadersOptions); + PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo property in properties) { // skip the properties that are not being set directly - if (property.Name == nameof(KnownNetworks) || - property.Name == nameof(KnownProxies)) + if (property.Name is nameof(KnownNetworks) or nameof(KnownProxies)) continue; property.SetValue(options, property.GetValue(this)); } - TrustedNetworks?.ForEach((network) => + TrustedNetworks?.ForEach(network => { // split the network into address and prefix length var parts = network.Split('/'); if (parts.Length == 2 && - IPAddress.TryParse(parts[0], out var prefix) && + IPAddress.TryParse(parts[0], out IPAddress? prefix) && int.TryParse(parts[1], out var prefixLength)) - { options.KnownNetworks.Add(new IPNetwork(prefix, prefixLength)); - } }); - TrustedProxies?.ForEach((proxy) => proxy.ResolveIP().ToList().ForEach((ip) => options.KnownProxies.Add(ip))); + TrustedProxies?.ForEach(proxy => proxy.ResolveIP().ToList().ForEach(ip => options.KnownProxies.Add(ip))); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Internal/ContainerConfig.cs b/src/GZCTF/Models/Internal/ContainerConfig.cs index 3caf52160..792f3e956 100644 --- a/src/GZCTF/Models/Internal/ContainerConfig.cs +++ b/src/GZCTF/Models/Internal/ContainerConfig.cs @@ -1,6 +1,4 @@ -using GZCTF.Utils; - -namespace GZCTF.Models.Internal; +namespace GZCTF.Models.Internal; public class ContainerConfig { @@ -40,7 +38,7 @@ public class ContainerConfig public int MemoryLimit { get; set; } = 64; /// - /// CPU 限制 (0.1 CPUs) + /// CPU 限制 (0.1 CPUs) /// public int CPUCount { get; set; } = 1; @@ -48,4 +46,4 @@ public class ContainerConfig /// 存储写入限制 /// public int StorageLimit { get; set; } = 256; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Internal/ContainerInfo.cs b/src/GZCTF/Models/Internal/ContainerInfo.cs index 1211aa184..e76748699 100644 --- a/src/GZCTF/Models/Internal/ContainerInfo.cs +++ b/src/GZCTF/Models/Internal/ContainerInfo.cs @@ -21,4 +21,4 @@ public class ContainerInfo /// 容器状态 /// public string State { get; set; } = default!; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/AccountVerifyModel.cs b/src/GZCTF/Models/Request/Account/AccountVerifyModel.cs index 5147333a4..7bb3e2513 100644 --- a/src/GZCTF/Models/Request/Account/AccountVerifyModel.cs +++ b/src/GZCTF/Models/Request/Account/AccountVerifyModel.cs @@ -18,4 +18,4 @@ public class AccountVerifyModel /// [Required(ErrorMessage = "邮箱是必需的")] public string? Email { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/LoginModel.cs b/src/GZCTF/Models/Request/Account/LoginModel.cs index 179bbd0e3..84f8f80a3 100644 --- a/src/GZCTF/Models/Request/Account/LoginModel.cs +++ b/src/GZCTF/Models/Request/Account/LoginModel.cs @@ -20,4 +20,4 @@ public class LoginModel : ModelWithCaptcha [Required] [MinLength(6, ErrorMessage = "密码过短")] public string Password { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/MailChangeModel.cs b/src/GZCTF/Models/Request/Account/MailChangeModel.cs index 12296e5a6..0eeb253e6 100644 --- a/src/GZCTF/Models/Request/Account/MailChangeModel.cs +++ b/src/GZCTF/Models/Request/Account/MailChangeModel.cs @@ -13,4 +13,4 @@ public class MailChangeModel [Required(ErrorMessage = "邮箱是必需的")] [EmailAddress(ErrorMessage = "邮箱地址无效")] public string NewMail { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/PasswordChangeModel.cs b/src/GZCTF/Models/Request/Account/PasswordChangeModel.cs index 3150c090e..dd2240ac4 100644 --- a/src/GZCTF/Models/Request/Account/PasswordChangeModel.cs +++ b/src/GZCTF/Models/Request/Account/PasswordChangeModel.cs @@ -20,4 +20,4 @@ public class PasswordChangeModel [Required(ErrorMessage = "新密码是必需的")] [MinLength(6, ErrorMessage = "新密码过短")] public string New { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/PasswordResetModel.cs b/src/GZCTF/Models/Request/Account/PasswordResetModel.cs index a9d92d4c5..19221c0e5 100644 --- a/src/GZCTF/Models/Request/Account/PasswordResetModel.cs +++ b/src/GZCTF/Models/Request/Account/PasswordResetModel.cs @@ -25,4 +25,4 @@ public class PasswordResetModel /// [Required(ErrorMessage = "Token是必需的")] public string? RToken { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/ProfileUpdateModel.cs b/src/GZCTF/Models/Request/Account/ProfileUpdateModel.cs index edfd295f5..b982f8ee8 100644 --- a/src/GZCTF/Models/Request/Account/ProfileUpdateModel.cs +++ b/src/GZCTF/Models/Request/Account/ProfileUpdateModel.cs @@ -37,4 +37,4 @@ public class ProfileUpdateModel /// [MaxLength(24, ErrorMessage = "学工号过长")] public string? StdNumber { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/ProfileUserInfoModel.cs b/src/GZCTF/Models/Request/Account/ProfileUserInfoModel.cs index b7d1ac413..1b50a0ad0 100644 --- a/src/GZCTF/Models/Request/Account/ProfileUserInfoModel.cs +++ b/src/GZCTF/Models/Request/Account/ProfileUserInfoModel.cs @@ -50,8 +50,8 @@ public class ProfileUserInfoModel /// public Role? Role { get; set; } - internal static ProfileUserInfoModel FromUserInfo(UserInfo user) - => new() + internal static ProfileUserInfoModel FromUserInfo(UserInfo user) => + new() { UserId = user.Id, Bio = user.Bio, @@ -63,4 +63,4 @@ internal static ProfileUserInfoModel FromUserInfo(UserInfo user) StdNumber = user.StdNumber, Role = user.Role }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/RecoveryModel.cs b/src/GZCTF/Models/Request/Account/RecoveryModel.cs index 8133152cf..0bfe99258 100644 --- a/src/GZCTF/Models/Request/Account/RecoveryModel.cs +++ b/src/GZCTF/Models/Request/Account/RecoveryModel.cs @@ -14,4 +14,4 @@ public class RecoveryModel : ModelWithCaptcha [Required(ErrorMessage = "邮箱是必需的")] [EmailAddress(ErrorMessage = "邮箱地址无效")] public string? Email { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Account/RegisterModel.cs b/src/GZCTF/Models/Request/Account/RegisterModel.cs index 477b87ae5..d1275b9e0 100644 --- a/src/GZCTF/Models/Request/Account/RegisterModel.cs +++ b/src/GZCTF/Models/Request/Account/RegisterModel.cs @@ -29,4 +29,4 @@ public class RegisterModel : ModelWithCaptcha [Required(ErrorMessage = "邮箱是必需的")] [EmailAddress(ErrorMessage = "邮箱地址无效")] public string Email { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/AdminTeamModel.cs b/src/GZCTF/Models/Request/Admin/AdminTeamModel.cs index 8d4a0dfee..f32dc61bf 100644 --- a/src/GZCTF/Models/Request/Admin/AdminTeamModel.cs +++ b/src/GZCTF/Models/Request/Admin/AdminTeamModel.cs @@ -23,4 +23,4 @@ public class AdminTeamModel /// 是否锁定 /// public bool? Locked { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/AdminUserInfoModel.cs b/src/GZCTF/Models/Request/Admin/AdminUserInfoModel.cs index 6ee8dd027..2279d5fec 100644 --- a/src/GZCTF/Models/Request/Admin/AdminUserInfoModel.cs +++ b/src/GZCTF/Models/Request/Admin/AdminUserInfoModel.cs @@ -53,4 +53,4 @@ public class AdminUserInfoModel /// 用户角色 /// public Role? Role { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/ConfigEditModel.cs b/src/GZCTF/Models/Request/Admin/ConfigEditModel.cs index bfc6affb8..2560a3229 100644 --- a/src/GZCTF/Models/Request/Admin/ConfigEditModel.cs +++ b/src/GZCTF/Models/Request/Admin/ConfigEditModel.cs @@ -21,4 +21,4 @@ public class ConfigEditModel /// 比赛策略 /// public GamePolicy? GamePolicy { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/ContainerInstanceModel.cs b/src/GZCTF/Models/Request/Admin/ContainerInstanceModel.cs index 0a3e781f1..34a7edf24 100644 --- a/src/GZCTF/Models/Request/Admin/ContainerInstanceModel.cs +++ b/src/GZCTF/Models/Request/Admin/ContainerInstanceModel.cs @@ -1,6 +1,4 @@ -using GZCTF.Utils; - -namespace GZCTF.Models.Request.Admin; +namespace GZCTF.Models.Request.Admin; /// /// 容器实例信息(Admin) @@ -10,12 +8,12 @@ public class ContainerInstanceModel /// /// 队伍 /// - public TeamModel? Team { get; set; } = default!; + public TeamModel? Team { get; set; } /// /// 题目 /// - public ChallengeModel? Challenge { get; set; } = default!; + public ChallengeModel? Challenge { get; set; } /// /// 容器镜像 @@ -54,10 +52,10 @@ public class ContainerInstanceModel internal static ContainerInstanceModel FromContainer(Container container) { - var team = container.Instance?.Participation?.Team; - var chal = container.Instance?.Challenge; + Team? team = container.Instance?.Participation?.Team; + Challenge? chal = container.Instance?.Challenge; - var model = new ContainerInstanceModel() + var model = new ContainerInstanceModel { Image = container.Image, ContainerGuid = container.Id, @@ -77,4 +75,4 @@ internal static ContainerInstanceModel FromContainer(Container container) return model; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/LogMessageModel.cs b/src/GZCTF/Models/Request/Admin/LogMessageModel.cs index 09c77e57c..bf2620d30 100644 --- a/src/GZCTF/Models/Request/Admin/LogMessageModel.cs +++ b/src/GZCTF/Models/Request/Admin/LogMessageModel.cs @@ -40,8 +40,8 @@ public class LogMessageModel [JsonPropertyName("status")] public string? Status { get; set; } - public static LogMessageModel FromLogModel(LogModel logInfo) - => new() + public static LogMessageModel FromLogModel(LogModel logInfo) => + new() { Time = logInfo.TimeUTC, Level = logInfo.Level, @@ -50,4 +50,4 @@ public static LogMessageModel FromLogModel(LogModel logInfo) Msg = logInfo.Message, Status = logInfo.Status }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/ParticipationInfoModel.cs b/src/GZCTF/Models/Request/Admin/ParticipationInfoModel.cs index f406ad8c1..d849cb007 100644 --- a/src/GZCTF/Models/Request/Admin/ParticipationInfoModel.cs +++ b/src/GZCTF/Models/Request/Admin/ParticipationInfoModel.cs @@ -30,8 +30,8 @@ public class ParticipationInfoModel /// public ParticipationStatus Status { get; set; } = ParticipationStatus.Pending; - internal static ParticipationInfoModel FromParticipation(Participation part) - => new() + internal static ParticipationInfoModel FromParticipation(Participation part) => + new() { Id = part.Id, Status = part.Status, @@ -39,4 +39,4 @@ internal static ParticipationInfoModel FromParticipation(Participation part) RegisteredMembers = part.Members.Select(m => m.UserId).ToArray(), Team = TeamWithDetailedUserInfo.FromTeam(part.Team) }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/TeamWithDetailedUserInfo.cs b/src/GZCTF/Models/Request/Admin/TeamWithDetailedUserInfo.cs index d466ed778..6af1f71d3 100644 --- a/src/GZCTF/Models/Request/Admin/TeamWithDetailedUserInfo.cs +++ b/src/GZCTF/Models/Request/Admin/TeamWithDetailedUserInfo.cs @@ -42,8 +42,8 @@ public class TeamWithDetailedUserInfo /// public ProfileUserInfoModel[]? Members { get; set; } - internal static TeamWithDetailedUserInfo FromTeam(Team team) - => new() + internal static TeamWithDetailedUserInfo FromTeam(Team team) => + new() { Id = team.Id, Name = team.Name, @@ -53,4 +53,4 @@ internal static TeamWithDetailedUserInfo FromTeam(Team team) CaptainId = team.CaptainId, Members = team.Members.Select(ProfileUserInfoModel.FromUserInfo).ToArray() }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/UserCreateModel.cs b/src/GZCTF/Models/Request/Admin/UserCreateModel.cs index 58d6f8119..28620a17e 100644 --- a/src/GZCTF/Models/Request/Admin/UserCreateModel.cs +++ b/src/GZCTF/Models/Request/Admin/UserCreateModel.cs @@ -53,14 +53,14 @@ public class UserCreateModel [MaxLength(15, ErrorMessage = "队伍名称过长")] public string? TeamName { get; set; } - internal UserInfo ToUserInfo() - => new() - { - Email = Email, - UserName = UserName, - RealName = RealName ?? "", - StdNumber = StdNumber ?? "", - PhoneNumber = Phone, - EmailConfirmed = true - }; -} + internal UserInfo ToUserInfo() => + new() + { + Email = Email, + UserName = UserName, + RealName = RealName ?? "", + StdNumber = StdNumber ?? "", + PhoneNumber = Phone, + EmailConfirmed = true + }; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/UserInfoModel.cs b/src/GZCTF/Models/Request/Admin/UserInfoModel.cs index 41642ee9c..c244a6866 100644 --- a/src/GZCTF/Models/Request/Admin/UserInfoModel.cs +++ b/src/GZCTF/Models/Request/Admin/UserInfoModel.cs @@ -70,8 +70,8 @@ public class UserInfoModel /// public bool? EmailConfirmed { get; set; } - internal static UserInfoModel FromUserInfo(UserInfo user) - => new() + internal static UserInfoModel FromUserInfo(UserInfo user) => + new() { Id = user.Id, IP = user.IP, @@ -87,4 +87,4 @@ internal static UserInfoModel FromUserInfo(UserInfo user) RegisterTimeUTC = user.RegisterTimeUTC, EmailConfirmed = user.EmailConfirmed }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Admin/WriteupInfoModel.cs b/src/GZCTF/Models/Request/Admin/WriteupInfoModel.cs index 9e6652d65..615eec9a7 100644 --- a/src/GZCTF/Models/Request/Admin/WriteupInfoModel.cs +++ b/src/GZCTF/Models/Request/Admin/WriteupInfoModel.cs @@ -34,13 +34,15 @@ public class WriteupInfoModel [JsonIgnore] public LocalFile File { get; set; } = default!; - internal static WriteupInfoModel? FromParticipation(Participation part) - => part.Writeup is null ? null : new() - { - Id = part.Id, - Team = TeamInfoModel.FromTeam(part.Team, false), - File = part.Writeup, - Url = part.Writeup.Url(), - UploadTimeUTC = part.Writeup.UploadTimeUTC - }; -} + internal static WriteupInfoModel? FromParticipation(Participation part) => + part.Writeup is null + ? null + : new() + { + Id = part.Id, + Team = TeamInfoModel.FromTeam(part.Team, false), + File = part.Writeup, + Url = part.Writeup.Url(), + UploadTimeUTC = part.Writeup.UploadTimeUTC + }; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/AttachmentCreateModel.cs b/src/GZCTF/Models/Request/Edit/AttachmentCreateModel.cs index 79cc75b7c..da8157d19 100644 --- a/src/GZCTF/Models/Request/Edit/AttachmentCreateModel.cs +++ b/src/GZCTF/Models/Request/Edit/AttachmentCreateModel.cs @@ -19,4 +19,4 @@ public class AttachmentCreateModel /// 文件 Url(远程文件) /// public string? RemoteUrl { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/ChallengeEditDetailModel.cs b/src/GZCTF/Models/Request/Edit/ChallengeEditDetailModel.cs index e391780fd..d7810d69a 100644 --- a/src/GZCTF/Models/Request/Edit/ChallengeEditDetailModel.cs +++ b/src/GZCTF/Models/Request/Edit/ChallengeEditDetailModel.cs @@ -1,5 +1,4 @@ using System.ComponentModel.DataAnnotations; -using GZCTF.Models.Data; using GZCTF.Models.Request.Game; namespace GZCTF.Models.Request.Edit; @@ -54,6 +53,62 @@ public class ChallengeEditDetailModel [Required] public bool IsEnabled { get; set; } + /// + /// 通过人数 + /// + [Required] + public int AcceptedCount { get; set; } + + /// + /// 统一文件名(仅用于动态附件) + /// + public string? FileName { get; set; } = string.Empty; + + /// + /// 题目附件(动态附件存放于 FlagInfoModel) + /// + public Attachment? Attachment { get; set; } + + /// + /// 测试容器 + /// + public ContainerInfoModel? TestContainer { get; set; } + + /// + /// 题目 Flag 信息 + /// + [Required] + public FlagInfoModel[] Flags { get; set; } = Array.Empty(); + + internal static ChallengeEditDetailModel FromChallenge(Challenge chal) => + new() + { + Id = chal.Id, + Title = chal.Title, + Content = chal.Content, + Tag = chal.Tag, + Type = chal.Type, + FlagTemplate = chal.FlagTemplate, + Hints = chal.Hints?.ToArray() ?? Array.Empty(), + IsEnabled = chal.IsEnabled, + ContainerImage = chal.ContainerImage, + MemoryLimit = chal.MemoryLimit, + CPUCount = chal.CPUCount, + StorageLimit = chal.StorageLimit, + ContainerExposePort = chal.ContainerExposePort, + EnableTrafficCapture = chal.EnableTrafficCapture, + OriginalScore = chal.OriginalScore, + MinScoreRate = chal.MinScoreRate, + Difficulty = chal.Difficulty, + FileName = chal.FileName, + AcceptedCount = chal.AcceptedCount, + Attachment = chal.Attachment, + TestContainer = chal.TestContainer is null ? null : ContainerInfoModel.FromContainer(chal.TestContainer), + Flags = (from flag in chal.Flags + select FlagInfoModel.FromFlagContext(flag)) + .ToArray() + }; + #region Container /// @@ -69,7 +124,7 @@ public class ChallengeEditDetailModel public int? MemoryLimit { get; set; } = 64; /// - /// CPU 限制 (0.1 CPUs) + /// CPU 限制 (0.1 CPUs) /// [Required] public int? CPUCount { get; set; } = 1; @@ -115,61 +170,4 @@ public class ChallengeEditDetailModel public double Difficulty { get; set; } = 3; #endregion Score - - /// - /// 通过人数 - /// - [Required] - public int AcceptedCount { get; set; } = 0; - - /// - /// 统一文件名(仅用于动态附件) - /// - public string? FileName { get; set; } = string.Empty; - - /// - /// 题目附件(动态附件存放于 FlagInfoModel) - /// - public Attachment? Attachment { get; set; } - - /// - /// 测试容器 - /// - public ContainerInfoModel? TestContainer { get; set; } - - /// - /// 题目 Flag 信息 - /// - [Required] - public FlagInfoModel[] Flags { get; set; } = Array.Empty(); - - internal static ChallengeEditDetailModel FromChallenge(Challenge chal) - => new() - { - Id = chal.Id, - Title = chal.Title, - Content = chal.Content, - Tag = chal.Tag, - Type = chal.Type, - FlagTemplate = chal.FlagTemplate, - Hints = chal.Hints?.ToArray() ?? Array.Empty(), - IsEnabled = chal.IsEnabled, - ContainerImage = chal.ContainerImage, - MemoryLimit = chal.MemoryLimit, - CPUCount = chal.CPUCount, - StorageLimit = chal.StorageLimit, - ContainerExposePort = chal.ContainerExposePort, - EnableTrafficCapture = chal.EnableTrafficCapture, - OriginalScore = chal.OriginalScore, - MinScoreRate = chal.MinScoreRate, - Difficulty = chal.Difficulty, - FileName = chal.FileName, - AcceptedCount = chal.AcceptedCount, - Attachment = chal.Attachment, - TestContainer = chal.TestContainer is null ? null : - ContainerInfoModel.FromContainer(chal.TestContainer), - Flags = (from flag in chal.Flags - select FlagInfoModel.FromFlagContext(flag)) - .ToArray() - }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/ChallengeInfoModel.cs b/src/GZCTF/Models/Request/Edit/ChallengeInfoModel.cs index 2da49f57c..7a345e1fb 100644 --- a/src/GZCTF/Models/Request/Edit/ChallengeInfoModel.cs +++ b/src/GZCTF/Models/Request/Edit/ChallengeInfoModel.cs @@ -32,7 +32,7 @@ public class ChallengeInfoModel /// /// 是否启用题目 /// - public bool IsEnabled { get; set; } = false; + public bool IsEnabled { get; set; } /// /// 题目分值 @@ -42,15 +42,15 @@ public class ChallengeInfoModel /// /// 最低分值 /// - public int MinScore { get; set; } = 0; + public int MinScore { get; set; } /// /// 最初分值 /// public int OriginalScore { get; set; } = 500; - internal static ChallengeInfoModel FromChallenge(Challenge challenge) - => new() + internal static ChallengeInfoModel FromChallenge(Challenge challenge) => + new() { Id = challenge.Id, Title = challenge.Title, @@ -61,4 +61,4 @@ internal static ChallengeInfoModel FromChallenge(Challenge challenge) OriginalScore = challenge.OriginalScore, IsEnabled = challenge.IsEnabled }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/ChallengeUpdateModel.cs b/src/GZCTF/Models/Request/Edit/ChallengeUpdateModel.cs index 2426df43e..6950086a6 100644 --- a/src/GZCTF/Models/Request/Edit/ChallengeUpdateModel.cs +++ b/src/GZCTF/Models/Request/Edit/ChallengeUpdateModel.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using GZCTF.Extensions; -using GZCTF.Utils; namespace GZCTF.Models.Request.Edit; @@ -41,6 +40,34 @@ public class ChallengeUpdateModel /// public bool? IsEnabled { get; set; } + /// + /// 统一文件名 + /// + public string? FileName { get; set; } + + /// + /// 提示是否存在更新 + /// + /// 原有哈希 + /// + internal bool IsHintUpdated(int? originalHash) => + Hints is not null && Hints.Count > 0 && + Hints.GetSetHashCode() != originalHash; + + /// + /// 是否为有效的 Flag 模板 + /// + /// + internal bool IsValidFlagTemplate() + { + if (string.IsNullOrWhiteSpace(FlagTemplate)) + return false; + + return FlagTemplate.Contains("[GUID]") || + FlagTemplate.Contains("[TEAM_HASH]") || + Codec.Leet.LeetEntropy(FlagTemplate) >= 32.0; + } + #region Container /// @@ -97,32 +124,4 @@ public class ChallengeUpdateModel public double? Difficulty { get; set; } #endregion Score - - /// - /// 统一文件名 - /// - public string? FileName { get; set; } - - /// - /// 提示是否存在更新 - /// - /// 原有哈希 - /// - internal bool IsHintUpdated(int? originalHash) - => Hints is not null && Hints.Count > 0 && - Hints.GetSetHashCode() != originalHash; - - /// - /// 是否为有效的 Flag 模板 - /// - /// - internal bool IsValidFlagTemplate() - { - if (string.IsNullOrWhiteSpace(FlagTemplate)) - return false; - - return FlagTemplate.Contains("[GUID]") || - FlagTemplate.Contains("[TEAM_HASH]") || - Codec.Leet.LeetEntropy(FlagTemplate) >= 32.0; - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/FlagCreateModel.cs b/src/GZCTF/Models/Request/Edit/FlagCreateModel.cs index ec750ac67..24d7d263e 100644 --- a/src/GZCTF/Models/Request/Edit/FlagCreateModel.cs +++ b/src/GZCTF/Models/Request/Edit/FlagCreateModel.cs @@ -28,4 +28,4 @@ public class FlagCreateModel /// 文件 Url(远程文件) /// public string? RemoteUrl { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/FlagInfoModel.cs b/src/GZCTF/Models/Request/Edit/FlagInfoModel.cs index 65fdc1d49..ebc74e787 100644 --- a/src/GZCTF/Models/Request/Edit/FlagInfoModel.cs +++ b/src/GZCTF/Models/Request/Edit/FlagInfoModel.cs @@ -1,6 +1,4 @@ -using GZCTF.Models.Data; - -namespace GZCTF.Models.Request.Edit; +namespace GZCTF.Models.Request.Edit; /// /// Flag 信息(Edit) @@ -22,11 +20,6 @@ public class FlagInfoModel /// public Attachment? Attachment { get; set; } - internal static FlagInfoModel FromFlagContext(FlagContext context) - => new() - { - Id = context.Id, - Flag = context.Flag, - Attachment = context.Attachment - }; -} + internal static FlagInfoModel FromFlagContext(FlagContext context) => + new() { Id = context.Id, Flag = context.Flag, Attachment = context.Attachment }; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/GameInfoModel.cs b/src/GZCTF/Models/Request/Edit/GameInfoModel.cs index 7e3a8af7e..ee266841f 100644 --- a/src/GZCTF/Models/Request/Edit/GameInfoModel.cs +++ b/src/GZCTF/Models/Request/Edit/GameInfoModel.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -using GZCTF.Utils; namespace GZCTF.Models.Request.Edit; @@ -23,7 +22,7 @@ public class GameInfoModel /// /// 是否隐藏 /// - public bool Hidden { get; set; } = false; + public bool Hidden { get; set; } /// /// 比赛描述 @@ -38,7 +37,7 @@ public class GameInfoModel /// /// 报名队伍免审核 /// - public bool AcceptWithoutReview { get; set; } = false; + public bool AcceptWithoutReview { get; set; } /// /// 比赛邀请码 @@ -54,7 +53,7 @@ public class GameInfoModel /// /// 队员数量限制, 0 为无上限 /// - public int TeamMemberCountLimit { get; set; } = 0; + public int TeamMemberCountLimit { get; set; } /// /// 队伍同时开启的容器数量限制 @@ -110,8 +109,8 @@ public class GameInfoModel [JsonPropertyName("bloodBonus")] public long BloodBonusValue { get; set; } = BloodBonus.DefaultValue; - internal static GameInfoModel FromGame(Models.Game game) - => new() + internal static GameInfoModel FromGame(Data.Game game) => + new() { Id = game.Id, Title = game.Title, @@ -132,4 +131,4 @@ internal static GameInfoModel FromGame(Models.Game game) WriteupNote = game.WriteupNote, BloodBonusValue = game.BloodBonus.Val }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/GameNoticeModel.cs b/src/GZCTF/Models/Request/Edit/GameNoticeModel.cs index 1194ccba2..23062f56c 100644 --- a/src/GZCTF/Models/Request/Edit/GameNoticeModel.cs +++ b/src/GZCTF/Models/Request/Edit/GameNoticeModel.cs @@ -12,4 +12,4 @@ public class GameNoticeModel /// [Required(ErrorMessage = "内容是必需的")] public string Content { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Edit/PostEditModel.cs b/src/GZCTF/Models/Request/Edit/PostEditModel.cs index b2c74cba7..cd3bec5d5 100644 --- a/src/GZCTF/Models/Request/Edit/PostEditModel.cs +++ b/src/GZCTF/Models/Request/Edit/PostEditModel.cs @@ -33,4 +33,4 @@ public class PostEditModel /// 是否置顶 /// public bool IsPinned { get; set; } = false; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/BasicGameInfoModel.cs b/src/GZCTF/Models/Request/Game/BasicGameInfoModel.cs index 134533123..734ccc05c 100644 --- a/src/GZCTF/Models/Request/Game/BasicGameInfoModel.cs +++ b/src/GZCTF/Models/Request/Game/BasicGameInfoModel.cs @@ -33,7 +33,7 @@ public partial class BasicGameInfoModel /// 队员数量限制 /// [JsonPropertyName("limit")] - public int TeamMemberLimitCount { get; set; } = 0; + public int TeamMemberLimitCount { get; set; } /// /// 开始时间 @@ -47,8 +47,8 @@ public partial class BasicGameInfoModel [JsonPropertyName("end")] public DateTimeOffset EndTimeUTC { get; set; } = DateTimeOffset.FromUnixTimeSeconds(0); - internal static BasicGameInfoModel FromGame(Models.Game game) - => new() + internal static BasicGameInfoModel FromGame(Data.Game game) => + new() { Id = game.Id, Title = game.Title, @@ -58,4 +58,4 @@ internal static BasicGameInfoModel FromGame(Models.Game game) EndTimeUTC = game.EndTimeUTC, TeamMemberLimitCount = game.TeamMemberCountLimit }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/BasicWriteupInfoModel.cs b/src/GZCTF/Models/Request/Game/BasicWriteupInfoModel.cs index 99f4eccd0..385630764 100644 --- a/src/GZCTF/Models/Request/Game/BasicWriteupInfoModel.cs +++ b/src/GZCTF/Models/Request/Game/BasicWriteupInfoModel.cs @@ -1,6 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; -using GZCTF.Models.Request.Info; +using System.Text.Json.Serialization; namespace GZCTF.Models.Request.Game; @@ -12,7 +10,7 @@ public class BasicWriteupInfoModel /// /// 是否已经提交 /// - public bool Submitted { get; set; } = false; + public bool Submitted { get; set; } /// /// 文件名称 @@ -22,7 +20,7 @@ public class BasicWriteupInfoModel /// /// 文件大小 /// - public long FileSize { get; set; } = 0; + public long FileSize { get; set; } /// /// Writeup 附加说明 @@ -30,12 +28,12 @@ public class BasicWriteupInfoModel [JsonPropertyName("note")] public string WriteupNote { get; set; } = string.Empty; - internal static BasicWriteupInfoModel FromParticipation(Participation part) - => new() + internal static BasicWriteupInfoModel FromParticipation(Participation part) => + new() { Submitted = part.Writeup is not null, Name = part.Writeup?.Name ?? "#", FileSize = part.Writeup?.FileSize ?? 0, WriteupNote = part.Game.WriteupNote }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/ChallengeDetailModel.cs b/src/GZCTF/Models/Request/Game/ChallengeDetailModel.cs index 059bab44e..314bacd26 100644 --- a/src/GZCTF/Models/Request/Game/ChallengeDetailModel.cs +++ b/src/GZCTF/Models/Request/Game/ChallengeDetailModel.cs @@ -45,8 +45,8 @@ public class ChallengeDetailModel /// public ClientFlagContext Context { get; set; } = default!; - internal static ChallengeDetailModel FromInstance(Instance instance) - => new() + internal static ChallengeDetailModel FromInstance(Instance instance) => + new() { Id = instance.Challenge.Id, Content = instance.Challenge.Content, @@ -60,7 +60,7 @@ internal static ChallengeDetailModel FromInstance(Instance instance) InstanceEntry = instance.Container?.Entry, CloseTime = instance.Container?.ExpectStopAt, Url = instance.AttachmentUrl, - FileSize = instance.Attachment?.FileSize, + FileSize = instance.Attachment?.FileSize } }; } @@ -75,15 +75,15 @@ public class ClientFlagContext /// /// 题目实例的连接方式 /// - public string? InstanceEntry { get; set; } = null; + public string? InstanceEntry { get; set; } /// /// 附件 Url /// - public string? Url { get; set; } = null; + public string? Url { get; set; } /// /// 附件文件大小 /// - public long? FileSize { get; set; } = null; -} + public long? FileSize { get; set; } +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/ChallengeTrafficModel.cs b/src/GZCTF/Models/Request/Game/ChallengeTrafficModel.cs index d99904b93..8d2372875 100644 --- a/src/GZCTF/Models/Request/Game/ChallengeTrafficModel.cs +++ b/src/GZCTF/Models/Request/Game/ChallengeTrafficModel.cs @@ -1,5 +1,4 @@ using System.ComponentModel.DataAnnotations; -using GZCTF.Utils; namespace GZCTF.Models.Request.Game; @@ -30,16 +29,16 @@ public class ChallengeTrafficModel /// /// 是否启用题目 /// - public bool IsEnabled { get; set; } = false; + public bool IsEnabled { get; set; } /// /// 题目所捕获到的队伍流量数量 /// - public int Count { get; set; } = 0; + public int Count { get; set; } internal static ChallengeTrafficModel FromChallenge(Challenge challenge) { - string trafficPath = $"{FilePath.Capture}/{challenge.Id}"; + var trafficPath = $"{FilePath.Capture}/{challenge.Id}"; return new() { @@ -48,8 +47,9 @@ internal static ChallengeTrafficModel FromChallenge(Challenge challenge) Tag = challenge.Tag, Type = challenge.Type, IsEnabled = challenge.IsEnabled, - Count = Directory.Exists(trafficPath) ? - Directory.GetDirectories(trafficPath, "*", SearchOption.TopDirectoryOnly).Length : 0 + Count = Directory.Exists(trafficPath) + ? Directory.GetDirectories(trafficPath, "*", SearchOption.TopDirectoryOnly).Length + : 0 }; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/CheatInfoModel.cs b/src/GZCTF/Models/Request/Game/CheatInfoModel.cs index 22f448e47..55d2d5db7 100644 --- a/src/GZCTF/Models/Request/Game/CheatInfoModel.cs +++ b/src/GZCTF/Models/Request/Game/CheatInfoModel.cs @@ -1,7 +1,4 @@ -using GZCTF.Models.Data; -using GZCTF.Utils; - -namespace GZCTF.Models.Request.Game; +namespace GZCTF.Models.Request.Game; /// /// 作弊行为信息 @@ -23,11 +20,11 @@ public class CheatInfoModel /// public Submission Submission { get; set; } = default!; - internal static CheatInfoModel FromCheatInfo(CheatInfo info) - => new() + internal static CheatInfoModel FromCheatInfo(CheatInfo info) => + new() { Submission = info.Submission, OwnedTeam = ParticipationModel.FromParticipation(info.SourceTeam), SubmitTeam = ParticipationModel.FromParticipation(info.SubmitTeam) }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/ContainerInfoModel.cs b/src/GZCTF/Models/Request/Game/ContainerInfoModel.cs index 6f19a07c4..733f9ce15 100644 --- a/src/GZCTF/Models/Request/Game/ContainerInfoModel.cs +++ b/src/GZCTF/Models/Request/Game/ContainerInfoModel.cs @@ -22,12 +22,6 @@ public class ContainerInfoModel /// public string Entry { get; set; } = string.Empty; - internal static ContainerInfoModel FromContainer(Container container) - => new() - { - Status = container.Status, - StartedAt = container.StartedAt, - ExpectStopAt = container.ExpectStopAt, - Entry = container.Entry - }; -} + internal static ContainerInfoModel FromContainer(Container container) => + new() { Status = container.Status, StartedAt = container.StartedAt, ExpectStopAt = container.ExpectStopAt, Entry = container.Entry }; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/DetailedGameInfoModel.cs b/src/GZCTF/Models/Request/Game/DetailedGameInfoModel.cs index 7b5baad06..cdcb3e0c5 100644 --- a/src/GZCTF/Models/Request/Game/DetailedGameInfoModel.cs +++ b/src/GZCTF/Models/Request/Game/DetailedGameInfoModel.cs @@ -29,7 +29,7 @@ public class DetailedGameInfoModel /// /// 是否为隐藏比赛 /// - public bool Hidden { get; set; } = false; + public bool Hidden { get; set; } /// /// 参赛所属单位列表 @@ -39,7 +39,7 @@ public class DetailedGameInfoModel /// /// 是否需要邀请码 /// - public bool InviteCodeRequired { get; set; } = false; + public bool InviteCodeRequired { get; set; } /// /// 比赛头图 @@ -51,12 +51,12 @@ public class DetailedGameInfoModel /// 队员数量限制 /// [JsonPropertyName("limit")] - public int TeamMemberCountLimit { get; set; } = 0; + public int TeamMemberCountLimit { get; set; } /// /// 报名参赛队伍数量 /// - public int TeamCount { get; set; } = 0; + public int TeamCount { get; set; } /// /// 当前报名的组织 @@ -99,8 +99,8 @@ public DetailedGameInfoModel WithParticipation(Participation? part) return this; } - internal static DetailedGameInfoModel FromGame(Models.Game game, int count) - => new() + internal static DetailedGameInfoModel FromGame(Data.Game game, int count) => + new() { Id = game.Id, Title = game.Title, @@ -116,4 +116,4 @@ internal static DetailedGameInfoModel FromGame(Models.Game game, int count) EndTimeUTC = game.EndTimeUTC, TeamMemberCountLimit = game.TeamMemberCountLimit }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/FlagSubmitModel.cs b/src/GZCTF/Models/Request/Game/FlagSubmitModel.cs index 0036efdc5..360142b11 100644 --- a/src/GZCTF/Models/Request/Game/FlagSubmitModel.cs +++ b/src/GZCTF/Models/Request/Game/FlagSubmitModel.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace GZCTF.Models.Request.Edit; +namespace GZCTF.Models.Request.Game; /// /// flag 提交 @@ -14,4 +14,4 @@ public class FlagSubmitModel [Required(ErrorMessage = "flag 是必需的")] [MaxLength(126, ErrorMessage = "flag 过长")] public string Flag { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/GameDetailModel.cs b/src/GZCTF/Models/Request/Game/GameDetailModel.cs index 41de34f94..96611a649 100644 --- a/src/GZCTF/Models/Request/Game/GameDetailModel.cs +++ b/src/GZCTF/Models/Request/Game/GameDetailModel.cs @@ -28,4 +28,4 @@ public class GameDetailModel [Required] [JsonPropertyName("wpddl")] public DateTimeOffset WriteupDeadline { get; set; } = DateTimeOffset.FromUnixTimeSeconds(0); -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/GameJoinModel.cs b/src/GZCTF/Models/Request/Game/GameJoinModel.cs index 056562011..38df85cea 100644 --- a/src/GZCTF/Models/Request/Game/GameJoinModel.cs +++ b/src/GZCTF/Models/Request/Game/GameJoinModel.cs @@ -16,4 +16,4 @@ public class GameJoinModel /// 参赛邀请码 /// public string? InviteCode { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/ScoreboardModel.cs b/src/GZCTF/Models/Request/Game/ScoreboardModel.cs index 7c5f2640e..61828907b 100644 --- a/src/GZCTF/Models/Request/Game/ScoreboardModel.cs +++ b/src/GZCTF/Models/Request/Game/ScoreboardModel.cs @@ -1,7 +1,5 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -using GZCTF.Models.Request.Admin; -using GZCTF.Utils; using MemoryPack; namespace GZCTF.Models.Request.Game; @@ -228,4 +226,4 @@ public partial class Blood /// 获得此血的时间 /// public DateTimeOffset? SubmitTimeUTC { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Game/TeamTrafficModel.cs b/src/GZCTF/Models/Request/Game/TeamTrafficModel.cs index bda978f0c..b7cce719e 100644 --- a/src/GZCTF/Models/Request/Game/TeamTrafficModel.cs +++ b/src/GZCTF/Models/Request/Game/TeamTrafficModel.cs @@ -1,6 +1,4 @@ -using GZCTF.Utils; - -namespace GZCTF.Models; +namespace GZCTF.Models.Request.Game; /// /// 队伍流量获取信息 @@ -39,7 +37,7 @@ public class TeamTrafficModel internal static TeamTrafficModel FromParticipation(Participation part, int challengeId) { - string trafficPath = $"{FilePath.Capture}/{challengeId}/{part.Id}"; + var trafficPath = $"{FilePath.Capture}/{challengeId}/{part.Id}"; return new() { @@ -48,8 +46,9 @@ internal static TeamTrafficModel FromParticipation(Participation part, int chall Name = part.Team.Name, Organization = part.Organization, Avatar = part.Team.AvatarUrl, - Count = Directory.Exists(trafficPath) ? - Directory.GetFiles(trafficPath, "*", SearchOption.TopDirectoryOnly).Length : 0 + Count = Directory.Exists(trafficPath) + ? Directory.GetFiles(trafficPath, "*", SearchOption.TopDirectoryOnly).Length + : 0 }; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/ClientCaptchaInfoModel.cs b/src/GZCTF/Models/Request/Info/ClientCaptchaInfoModel.cs index c4c96c9d0..15f9c3a83 100644 --- a/src/GZCTF/Models/Request/Info/ClientCaptchaInfoModel.cs +++ b/src/GZCTF/Models/Request/Info/ClientCaptchaInfoModel.cs @@ -7,18 +7,8 @@ namespace GZCTF.Models.Request.Info; /// public class ClientCaptchaInfoModel { - /// - /// 验证码类型 - /// - public CaptchaProvider Type { get; set; } = CaptchaProvider.None; - - /// - /// 客户端密钥 - /// - public string SiteKey { get; set; } = string.Empty; - - public ClientCaptchaInfoModel() { } + public ClientCaptchaInfoModel(CaptchaConfig? config) { if (config?.SiteKey is null || config.Provider == CaptchaProvider.None) @@ -27,5 +17,14 @@ public ClientCaptchaInfoModel(CaptchaConfig? config) Type = config.Provider; SiteKey = config.SiteKey; } -} + /// + /// 验证码类型 + /// + public CaptchaProvider Type { get; set; } = CaptchaProvider.None; + + /// + /// 客户端密钥 + /// + public string SiteKey { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/PostDetailModel.cs b/src/GZCTF/Models/Request/Info/PostDetailModel.cs index 498bc4235..35f2d13c1 100644 --- a/src/GZCTF/Models/Request/Info/PostDetailModel.cs +++ b/src/GZCTF/Models/Request/Info/PostDetailModel.cs @@ -35,7 +35,7 @@ public class PostDetailModel /// 是否置顶 /// [Required] - public bool IsPinned { get; set; } = false; + public bool IsPinned { get; set; } /// /// 文章标签 @@ -58,8 +58,8 @@ public class PostDetailModel [Required] public DateTimeOffset Time { get; set; } = DateTimeOffset.UtcNow; - internal static PostDetailModel FromPost(Post post) - => new() + internal static PostDetailModel FromPost(Post post) => + new() { Id = post.Id, Title = post.Title, @@ -69,6 +69,6 @@ internal static PostDetailModel FromPost(Post post) Content = post.Content, Time = post.UpdateTimeUTC, AuthorAvatar = post.Author?.AvatarUrl, - AuthorName = post.Author?.UserName, + AuthorName = post.Author?.UserName }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/PostInfoModel.cs b/src/GZCTF/Models/Request/Info/PostInfoModel.cs index e268e9100..94220e648 100644 --- a/src/GZCTF/Models/Request/Info/PostInfoModel.cs +++ b/src/GZCTF/Models/Request/Info/PostInfoModel.cs @@ -29,7 +29,7 @@ public class PostInfoModel /// 是否置顶 /// [Required] - public bool IsPinned { get; set; } = false; + public bool IsPinned { get; set; } /// /// 文章标签 @@ -52,8 +52,8 @@ public class PostInfoModel [Required] public DateTimeOffset Time { get; set; } = DateTimeOffset.UtcNow; - internal static PostInfoModel FromPost(Post post) - => new() + internal static PostInfoModel FromPost(Post post) => + new() { Id = post.Id, Title = post.Title, @@ -62,6 +62,6 @@ internal static PostInfoModel FromPost(Post post) Tags = post.Tags, Time = post.UpdateTimeUTC, AuthorAvatar = post.Author?.AvatarUrl, - AuthorName = post.Author?.UserName, + AuthorName = post.Author?.UserName }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/TeamInfoModel.cs b/src/GZCTF/Models/Request/Info/TeamInfoModel.cs index 031d344f2..b2e8a0256 100644 --- a/src/GZCTF/Models/Request/Info/TeamInfoModel.cs +++ b/src/GZCTF/Models/Request/Info/TeamInfoModel.cs @@ -35,28 +35,30 @@ public class TeamInfoModel /// public List? Members { get; set; } = new(); - internal static TeamInfoModel FromTeam(Team team, bool includeMembers = true) - => new() + internal static TeamInfoModel FromTeam(Team team, bool includeMembers = true) => + new() { Id = team.Id, Name = team.Name, Bio = team.Bio, Avatar = team.AvatarUrl, Locked = team.Locked, - Members = includeMembers ? team.Members.Select(m => new TeamUserInfoModel() - { - Id = m.Id, - Bio = m.Bio, - UserName = m.UserName, - Avatar = m.AvatarUrl, - Captain = m.Id == team.CaptainId, - RealName = m.RealName, - StudentNumber = m.StdNumber - }).ToList() : null + Members = includeMembers + ? team.Members.Select(m => new TeamUserInfoModel + { + Id = m.Id, + Bio = m.Bio, + UserName = m.UserName, + Avatar = m.AvatarUrl, + Captain = m.Id == team.CaptainId, + RealName = m.RealName, + StudentNumber = m.StdNumber + }).ToList() + : null }; - internal static TeamInfoModel FromParticipation(Participation part) - => new() + internal static TeamInfoModel FromParticipation(Participation part) => + new() { Id = part.Team.Id, Name = part.Team.Name, @@ -64,16 +66,16 @@ internal static TeamInfoModel FromParticipation(Participation part) Avatar = part.Team.AvatarUrl, Locked = part.Team.Locked, Members = part.Members - .Select(m => part.Team.Members.Single(u => u.Id == m.UserId)) - .Select(m => new TeamUserInfoModel() - { - Id = m.Id, - Bio = m.Bio, - UserName = m.UserName, - Avatar = m.AvatarUrl, - Captain = m.Id == part.Team.CaptainId, - RealName = m.RealName, - StudentNumber = m.StdNumber - }).ToList() + .Select(m => part.Team.Members.Single(u => u.Id == m.UserId)) + .Select(m => new TeamUserInfoModel + { + Id = m.Id, + Bio = m.Bio, + UserName = m.UserName, + Avatar = m.AvatarUrl, + Captain = m.Id == part.Team.CaptainId, + RealName = m.RealName, + StudentNumber = m.StdNumber + }).ToList() }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/TeamTransferModel.cs b/src/GZCTF/Models/Request/Info/TeamTransferModel.cs index 10a36f882..448f7d00c 100644 --- a/src/GZCTF/Models/Request/Info/TeamTransferModel.cs +++ b/src/GZCTF/Models/Request/Info/TeamTransferModel.cs @@ -9,4 +9,4 @@ public class TeamTransferModel /// [Required] public string NewCaptainId { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/TeamUpdateModel.cs b/src/GZCTF/Models/Request/Info/TeamUpdateModel.cs index a5b043b6f..2455351d6 100644 --- a/src/GZCTF/Models/Request/Info/TeamUpdateModel.cs +++ b/src/GZCTF/Models/Request/Info/TeamUpdateModel.cs @@ -25,4 +25,4 @@ public TeamUpdateModel(string teamName) /// [MaxLength(31, ErrorMessage = "队伍签名过长")] public string? Bio { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Models/Request/Info/TeamUserInfoModel.cs b/src/GZCTF/Models/Request/Info/TeamUserInfoModel.cs index 19665b68b..d7b7a8619 100644 --- a/src/GZCTF/Models/Request/Info/TeamUserInfoModel.cs +++ b/src/GZCTF/Models/Request/Info/TeamUserInfoModel.cs @@ -43,4 +43,4 @@ public class TeamUserInfoModel /// [JsonIgnore] public string? StudentNumber { get; set; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Pages/Error.cshtml.cs b/src/GZCTF/Pages/Error.cshtml.cs index b641ee50a..794c7a314 100644 --- a/src/GZCTF/Pages/Error.cshtml.cs +++ b/src/GZCTF/Pages/Error.cshtml.cs @@ -11,8 +11,5 @@ public class ErrorModel : PageModel public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } -} + public void OnGet() => RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; +} \ No newline at end of file diff --git a/src/GZCTF/Pages/_ViewImports.cshtml b/src/GZCTF/Pages/_ViewImports.cshtml index 7325e8bec..b1aa32d9e 100644 --- a/src/GZCTF/Pages/_ViewImports.cshtml +++ b/src/GZCTF/Pages/_ViewImports.cshtml @@ -1,3 +1,2 @@ -@using GZCTF -@namespace GZCTF.Pages +@namespace GZCTF.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/src/GZCTF/Program.cs b/src/GZCTF/Program.cs index 71495883b..17d9f91fa 100644 --- a/src/GZCTF/Program.cs +++ b/src/GZCTF/Program.cs @@ -1,4 +1,7 @@ -global using GZCTF.Models; +global using GZCTF.Models.Data; +global using GZCTF.Utils; +global using AppDbContext = GZCTF.Models.AppDbContext; +global using TaskStatus = GZCTF.Utils.TaskStatus; using System.Reflection; using System.Text; using System.Text.Json; @@ -9,6 +12,8 @@ using GZCTF.Repositories; using GZCTF.Repositories.Interface; using GZCTF.Services; +using GZCTF.Services.Cache; +using GZCTF.Services.Container; using GZCTF.Services.Interface; using GZCTF.Utils; using Microsoft.AspNetCore.DataProtection; @@ -16,15 +21,16 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using NJsonSchema.Generation; using Serilog; -var builder = WebApplication.CreateBuilder(args); +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -Banner(); +GZCTF.Program.Banner(); FilePath.EnsureDirs(); @@ -39,7 +45,9 @@ #endregion Logging #region AppDbContext -if (IsTesting || (builder.Environment.IsDevelopment() && !builder.Configuration.GetSection("ConnectionStrings").Exists())) + +if (GZCTF.Program.IsTesting || (builder.Environment.IsDevelopment() && + !builder.Configuration.GetSection("ConnectionStrings").Exists())) { builder.Services.AddDbContext( options => options.UseInMemoryDatabase("TestDb") @@ -48,7 +56,7 @@ else { if (!builder.Configuration.GetSection("ConnectionStrings").GetSection("Database").Exists()) - ExitWithFatalMessage("未找到数据库连接字符串字段 ConnectionStrings,请检查 appsettings.json 是否正常挂载及配置"); + GZCTF.Program.ExitWithFatalMessage("未找到数据库连接字符串字段 ConnectionStrings,请检查 appsettings.json 是否正常挂载及配置"); builder.Services.AddDbContext( options => @@ -63,11 +71,12 @@ } ); } + #endregion AppDbContext #region Configuration -if (!IsTesting) -{ + +if (!GZCTF.Program.IsTesting) try { builder.Configuration.AddEntityConfiguration(options => @@ -82,12 +91,13 @@ { if (builder.Configuration.GetSection("ConnectionStrings").GetSection("Database").Exists()) Log.Logger.Error($"当前连接字符串:{builder.Configuration.GetConnectionString("Database")}"); - ExitWithFatalMessage("数据库连接失败,请检查 Database 连接字符串配置"); + GZCTF.Program.ExitWithFatalMessage("数据库连接失败,请检查 Database 连接字符串配置"); } -} + #endregion Configuration #region OpenApiDocument + builder.Services.AddRouting(options => options.LowercaseUrls = true); builder.Services.AddOpenApiDocument(settings => { @@ -96,17 +106,17 @@ settings.Title = "GZCTF Server API"; settings.Description = "GZCTF Server 接口文档"; settings.UseControllerSummaryAsTagDescription = true; - settings.SerializerSettings = SystemTextJsonUtilities.ConvertJsonOptionsToNewtonsoftSettings(new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }); + settings.SerializerSettings = + SystemTextJsonUtilities.ConvertJsonOptionsToNewtonsoftSettings( + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); settings.DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull; }); + #endregion OpenApiDocument #region SignalR -var signalrBuilder = builder.Services.AddSignalR().AddJsonProtocol(); +ISignalRServerBuilder signalrBuilder = builder.Services.AddSignalR().AddJsonProtocol(); #endregion SignalR @@ -151,15 +161,15 @@ }); builder.Services.AddIdentityCore(options => -{ - options.User.RequireUniqueEmail = true; - options.Password.RequireNonAlphanumeric = false; - options.SignIn.RequireConfirmedEmail = true; -}).AddSignInManager>() -.AddUserManager>() -.AddEntityFrameworkStores() -.AddErrorDescriber() -.AddDefaultTokenProviders(); + { + options.User.RequireUniqueEmail = true; + options.Password.RequireNonAlphanumeric = false; + options.SignIn.RequireConfirmedEmail = true; + }).AddSignInManager>() + .AddUserManager>() + .AddEntityFrameworkStores() + .AddErrorDescriber() + .AddDefaultTokenProviders(); builder.Services.Configure(o => o.TokenLifespan = TimeSpan.FromHours(3) @@ -180,17 +190,13 @@ var forwardedOptions = builder.Configuration.GetSection(nameof(ForwardedOptions)).Get(); if (forwardedOptions is null) -{ builder.Services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); -} else -{ builder.Services.Configure(forwardedOptions.ToForwardedHeadersOptions); -} builder.Services.AddCaptchaService(builder.Configuration); builder.Services.AddContainerService(builder.Configuration); @@ -225,17 +231,17 @@ { options.Providers.Add(); options.Providers.Add(); - options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] - { "application/json", "text/javascript", "text/html", "text/css" } + options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( + new[] { "application/json", "text/javascript", "text/html", "text/css" } ); }); builder.Services.AddControllersWithViews().ConfigureApiBehaviorOptions(options => { - options.InvalidModelStateResponseFactory = InvalidModelStateHandler; + options.InvalidModelStateResponseFactory = GZCTF.Program.InvalidModelStateHandler; }); -var app = builder.Build(); +WebApplication app = builder.Build(); Log.Logger = LogHelper.GetLogger(app.Configuration, app.Services); @@ -273,7 +279,7 @@ if (app.Configuration.GetValue("DisableRateLimit") is not true) app.UseConfiguredRateLimiter(); -if (app.Environment.IsDevelopment() || app.Configuration.GetValue("RequestLogging") is true) +if (app.Environment.IsDevelopment() || app.Configuration.GetValue("RequestLogging")) app.UseRequestLogging(); app.UseWebSockets(new() { KeepAliveInterval = TimeSpan.FromMinutes(30) }); @@ -287,13 +293,13 @@ app.MapFallbackToFile("index.html"); -await using var scope = app.Services.CreateAsyncScope(); -var logger = scope.ServiceProvider.GetRequiredService>(); +await using AsyncServiceScope scope = app.Services.CreateAsyncScope(); +var logger = scope.ServiceProvider.GetRequiredService>(); try { - var version = typeof(Program).Assembly.GetCustomAttribute()?.Description; - logger.SystemLog(version ?? "GZ::CTF", GZCTF.TaskStatus.Pending, LogLevel.Debug); + var version = typeof(GZCTF.Program).Assembly.GetCustomAttribute()?.Description; + logger.SystemLog(version ?? "GZ::CTF", TaskStatus.Pending, LogLevel.Debug); await app.RunAsync(); } catch (Exception exception) @@ -303,64 +309,60 @@ } finally { - logger.SystemLog("服务器已退出", GZCTF.TaskStatus.Exit, LogLevel.Debug); + logger.SystemLog("服务器已退出", TaskStatus.Exit, LogLevel.Debug); Log.CloseAndFlush(); } -public partial class Program +namespace GZCTF { - public static bool IsTesting { get; set; } = false; - - public static void Banner() - { - const string banner = - @" ___ ___ ___ ___ " + "\n" + - @" / /\ / /\ / /\ ___ / /\ " + "\n" + - @" / /:/_ / /::| / /:/ / /\ / /:/_ " + "\n" + - @" / /:/ /\ / /:/:| / /:/ / /:/ / /:/ /\" + "\n" + - @" / /:/_/::\ / /:/|:|__ / /:/ ___ / /:/ / /:/ /:/" + "\n" + - @" /__/:/__\/\:\ /__/:/ |:| /\ /__/:/ / /\ / /::\ /__/:/ /:/ " + "\n" + - @" \ \:\ /~~/:/ \__\/ |:|/:/ \ \:\ / /:/ /__/:/\:\ \ \:\/:/ " + "\n" + - @" \ \:\ /:/ | |:/:/ \ \:\ /:/ \__\/ \:\ \ \::/ " + "\n" + - @" \ \:\/:/ | |::/ \ \:\/:/ \ \:\ \ \:\ " + "\n" + - @" \ \::/ | |:/ \ \::/ \__\/ \ \:\ " + "\n" + - @" \__\/ |__|/ \__\/ \__\/ " + "\n"; - Console.WriteLine(banner); - - var versionStr = ""; - var version = typeof(Codec).Assembly.GetName().Version; - if (version is not null) - versionStr = $"Version: {version.Major}.{version.Minor}.{version.Build}"; - - Console.WriteLine($"GZCTF © 2022-present GZTimeWalker {versionStr,33}\n"); - } - - public static void ExitWithFatalMessage(string msg) + public class Program { - Log.Logger.Fatal(msg); - Thread.Sleep(30000); - Environment.Exit(1); - } + public static bool IsTesting { get; set; } - public static IActionResult InvalidModelStateHandler(ActionContext context) - { - string? errmsg = null; + internal static void Banner() + { + const string banner = + @" ___ ___ ___ ___ " + "\n" + + @" / /\ / /\ / /\ ___ / /\ " + "\n" + + @" / /:/_ / /::| / /:/ / /\ / /:/_ " + "\n" + + @" / /:/ /\ / /:/:| / /:/ / /:/ / /:/ /\" + "\n" + + @" / /:/_/::\ / /:/|:|__ / /:/ ___ / /:/ / /:/ /:/" + "\n" + + @" /__/:/__\/\:\ /__/:/ |:| /\ /__/:/ / /\ / /::\ /__/:/ /:/ " + "\n" + + @" \ \:\ /~~/:/ \__\/ |:|/:/ \ \:\ / /:/ /__/:/\:\ \ \:\/:/ " + "\n" + + @" \ \:\ /:/ | |:/:/ \ \:\ /:/ \__\/ \:\ \ \::/ " + "\n" + + @" \ \:\/:/ | |::/ \ \:\/:/ \ \:\ \ \:\ " + "\n" + + @" \ \::/ | |:/ \ \::/ \__\/ \ \:\ " + "\n" + + @" \__\/ |__|/ \__\/ \__\/ " + "\n"; + Console.WriteLine(banner); + + var versionStr = ""; + Version? version = typeof(Codec).Assembly.GetName().Version; + if (version is not null) + versionStr = $"Version: {version.Major}.{version.Minor}.{version.Build}"; + + Console.WriteLine($"GZCTF © 2022-present GZTimeWalker {versionStr,33}\n"); + } - if (context.ModelState.ErrorCount > 0) + public static void ExitWithFatalMessage(string msg) { - foreach (var val in context.ModelState.Values) - { - if (val.Errors.Count > 0) - { - errmsg = val.Errors.FirstOrDefault()?.ErrorMessage; - break; - } - } + Log.Logger.Fatal(msg); + Thread.Sleep(30000); + Environment.Exit(1); } - return new JsonResult(new RequestResponse(errmsg is not null && errmsg.Length > 0 ? errmsg : "校验失败,请检查输入。")) + public static IActionResult InvalidModelStateHandler(ActionContext context) { - StatusCode = 400 - }; + string? errors = null; + + if (context.ModelState.ErrorCount <= 0) + return new JsonResult( + new RequestResponse(errors is not null && errors.Length > 0 ? errors : "校验失败,请检查输入。")) { StatusCode = 400 }; + + errors = (from val in context.ModelState.Values + where val.Errors.Count > 0 + select val.Errors.FirstOrDefault()?.ErrorMessage).FirstOrDefault(); + + return new JsonResult(new RequestResponse(errors is not null && errors.Length > 0 ? errors : "校验失败,请检查输入。")) { StatusCode = 400 }; + } } -} +} \ No newline at end of file diff --git a/src/GZCTF/Providers/EntityConfigurationProvider.cs b/src/GZCTF/Providers/EntityConfigurationProvider.cs index bfc180d05..e1a8a9d4c 100644 --- a/src/GZCTF/Providers/EntityConfigurationProvider.cs +++ b/src/GZCTF/Providers/EntityConfigurationProvider.cs @@ -1,6 +1,5 @@ using System.Security.Cryptography; using System.Text; -using GZCTF.Models.Data; using GZCTF.Models.Internal; using GZCTF.Services; using Microsoft.EntityFrameworkCore; @@ -10,14 +9,25 @@ namespace GZCTF.Providers; public class EntityConfigurationProvider(EntityConfigurationSource source) : ConfigurationProvider, IDisposable { - private readonly CancellationTokenSource _cancellationTokenSource = new(); - private Task? _databaseWatcher; - private byte[] _lastHash = []; - private bool _disposed = false; + readonly CancellationTokenSource _cancellationTokenSource = new(); + Task? _databaseWatcher; + bool _disposed; + byte[] _lastHash = Array.Empty(); - private static HashSet DefaultConfigs() + public void Dispose() { - HashSet configs = []; + if (_disposed) + return; + + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _disposed = true; + GC.SuppressFinalize(this); + } + + static HashSet DefaultConfigs() + { + HashSet configs = new(); configs.UnionWith(ConfigService.GetConfigs(new AccountPolicy())); configs.UnionWith(ConfigService.GetConfigs(new GlobalConfig())); @@ -26,31 +36,30 @@ private static HashSet DefaultConfigs() return configs; } - private async Task WatchDatabase(CancellationToken token) + async Task WatchDatabase(CancellationToken token) { while (!token.IsCancellationRequested) - { try { await Task.Delay(source.PollingInterval, token); IDictionary actualData = await GetDataAsync(token); - byte[] computedHash = ConfigHash(actualData); + var computedHash = ConfigHash(actualData); if (!computedHash.SequenceEqual(_lastHash)) { Data = actualData; OnReload(); } + _lastHash = computedHash; } catch (Exception ex) { Log.Logger?.Error(ex, "全局配置重载失败"); } - } } - private AppDbContext CreateAppDbContext() + AppDbContext CreateAppDbContext() { var builder = new DbContextOptionsBuilder(); source.OptionsAction(builder); @@ -58,21 +67,23 @@ private AppDbContext CreateAppDbContext() return new AppDbContext(builder.Options); } - private async Task> GetDataAsync(CancellationToken token = default) + async Task> GetDataAsync(CancellationToken token = default) { - var context = CreateAppDbContext(); + AppDbContext context = CreateAppDbContext(); return await context.Configs.ToDictionaryAsync(c => c.ConfigKey, c => c.Value, StringComparer.OrdinalIgnoreCase, token); } - private static byte[] ConfigHash(IDictionary configs) - => SHA256.HashData(Encoding.UTF8.GetBytes(string.Join(";", configs.Select(c => $"{c.Key}={c.Value}")))); + static byte[] ConfigHash(IDictionary configs) => + SHA256.HashData(Encoding.UTF8.GetBytes( + string.Join(";", configs.Select(c => $"{c.Key}={c.Value}")) + )); public override void Load() { if (_databaseWatcher is not null) { - var task = GetDataAsync(); + Task> task = GetDataAsync(); task.Wait(); Data = task.Result; @@ -80,7 +91,7 @@ public override void Load() return; } - var context = CreateAppDbContext(); + AppDbContext? context = CreateAppDbContext(); if (!context.Database.IsInMemory()) context.Database.Migrate(); @@ -91,7 +102,7 @@ public override void Load() { Log.Logger.Debug("初始化数据库……"); - var configs = DefaultConfigs(); + HashSet configs = DefaultConfigs(); if (context is not null) { @@ -108,18 +119,7 @@ public override void Load() _lastHash = ConfigHash(Data); - var cancellationToken = _cancellationTokenSource.Token; + CancellationToken cancellationToken = _cancellationTokenSource.Token; _databaseWatcher = Task.Run(() => WatchDatabase(cancellationToken), cancellationToken); } - - public void Dispose() - { - if (_disposed) - return; - - _cancellationTokenSource.Cancel(); - _cancellationTokenSource.Dispose(); - _disposed = true; - GC.SuppressFinalize(this); - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Providers/EntityConfigurationSource.cs b/src/GZCTF/Providers/EntityConfigurationSource.cs index 8b665f8eb..b2c7cce88 100644 --- a/src/GZCTF/Providers/EntityConfigurationSource.cs +++ b/src/GZCTF/Providers/EntityConfigurationSource.cs @@ -2,11 +2,11 @@ namespace GZCTF.Providers; -public class EntityConfigurationSource(Action optionsAction, int pollingInterval = 180000) : IConfigurationSource +public class EntityConfigurationSource + (Action optionsAction, int pollingInterval = 180000) : IConfigurationSource { public Action OptionsAction { get; set; } = optionsAction; public int PollingInterval { get; private set; } = pollingInterval; // default to 3min - public IConfigurationProvider Build(IConfigurationBuilder builder) - => new EntityConfigurationProvider(this); -} + public IConfigurationProvider Build(IConfigurationBuilder builder) => new EntityConfigurationProvider(this); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/ChallengeRepository.cs b/src/GZCTF/Repositories/ChallengeRepository.cs index 7b1301299..0f2fab007 100644 --- a/src/GZCTF/Repositories/ChallengeRepository.cs +++ b/src/GZCTF/Repositories/ChallengeRepository.cs @@ -1,29 +1,26 @@ -using GZCTF.Models.Data; -using GZCTF.Models.Request.Edit; +using GZCTF.Models.Request.Edit; using GZCTF.Repositories.Interface; using Microsoft.EntityFrameworkCore; namespace GZCTF.Repositories; -public class ChallengeRepository(AppDbContext context, IFileRepository fileRepository) : RepositoryBase(context), IChallengeRepository +public class ChallengeRepository(AppDbContext context, IFileRepository fileRepository) : RepositoryBase(context), + IChallengeRepository { public async Task AddFlags(Challenge challenge, FlagCreateModel[] models, CancellationToken token = default) { - foreach (var model in models) + foreach (FlagCreateModel model in models) { - Attachment? attachment = model.AttachmentType == FileType.None ? null : new() - { - Type = model.AttachmentType, - LocalFile = await fileRepository.GetFileByHash(model.FileHash, token), - RemoteUrl = model.RemoteUrl - }; - - challenge.Flags.Add(new() - { - Flag = model.Flag, - Challenge = challenge, - Attachment = attachment - }); + Attachment? attachment = model.AttachmentType == FileType.None + ? null + : new() + { + Type = model.AttachmentType, + LocalFile = await fileRepository.GetFileByHash(model.FileHash, token), + RemoteUrl = model.RemoteUrl + }; + + challenge.Flags.Add(new() { Flag = model.Flag, Challenge = challenge, Attachment = attachment }); } await SaveAsync(token); @@ -42,9 +39,9 @@ public async Task EnsureInstances(Challenge challenge, Game game, Cancella await context.Entry(challenge).Collection(c => c.Teams).LoadAsync(token); await context.Entry(game).Collection(g => g.Participations).LoadAsync(token); - bool update = false; + var update = false; - foreach (var participation in game.Participations) + foreach (Participation participation in game.Participations) update |= challenge.Teams.Add(participation); await SaveAsync(token); @@ -54,7 +51,7 @@ public async Task EnsureInstances(Challenge challenge, Game game, Cancella public Task GetChallenge(int gameId, int id, bool withFlag = false, CancellationToken token = default) { - var challenges = context.Challenges + IQueryable challenges = context.Challenges .Where(c => c.Id == id && c.GameId == gameId); if (withFlag) @@ -63,14 +60,15 @@ public async Task EnsureInstances(Challenge challenge, Game game, Cancella return challenges.FirstOrDefaultAsync(token); } - public Task GetChallenges(int gameId, CancellationToken token = default) - => context.Challenges.Where(c => c.GameId == gameId).OrderBy(c => c.Id).ToArrayAsync(token); + public Task GetChallenges(int gameId, CancellationToken token = default) => + context.Challenges.Where(c => c.GameId == gameId).OrderBy(c => c.Id).ToArrayAsync(token); - public Task GetChallengesWithTrafficCapturing(int gameId, CancellationToken token = default) - => context.Challenges.IgnoreAutoIncludes().Where(c => c.GameId == gameId && c.EnableTrafficCapture).ToArrayAsync(token); + public Task GetChallengesWithTrafficCapturing(int gameId, CancellationToken token = default) => + context.Challenges.IgnoreAutoIncludes().Where(c => c.GameId == gameId && c.EnableTrafficCapture) + .ToArrayAsync(token); - public Task VerifyStaticAnswer(Challenge challenge, string flag, CancellationToken token = default) - => context.Entry(challenge).Collection(e => e.Flags).Query().AnyAsync(f => f.Flag == flag, token); + public Task VerifyStaticAnswer(Challenge challenge, string flag, CancellationToken token = default) => + context.Entry(challenge).Collection(e => e.Flags).Query().AnyAsync(f => f.Flag == flag, token); public async Task RemoveChallenge(Challenge challenge, CancellationToken token = default) { @@ -82,7 +80,7 @@ public async Task RemoveChallenge(Challenge challenge, CancellationToken token = public async Task RemoveFlag(Challenge challenge, int flagId, CancellationToken token = default) { - var flag = challenge.Flags.FirstOrDefault(f => f.Id == flagId); + FlagContext? flag = challenge.Flags.FirstOrDefault(f => f.Id == flagId); if (flag is null) return TaskStatus.NotFound; @@ -99,14 +97,15 @@ public async Task RemoveFlag(Challenge challenge, int flagId, Cancel return TaskStatus.Success; } - public async Task UpdateAttachment(Challenge challenge, AttachmentCreateModel model, CancellationToken token = default) + public async Task UpdateAttachment(Challenge challenge, AttachmentCreateModel model, + CancellationToken token = default) { - Attachment? attachment = model.AttachmentType == FileType.None ? null : new() - { - Type = model.AttachmentType, - LocalFile = await fileRepository.GetFileByHash(model.FileHash, token), - RemoteUrl = model.RemoteUrl - }; + Attachment? attachment = model.AttachmentType == FileType.None + ? null + : new() + { + Type = model.AttachmentType, LocalFile = await fileRepository.GetFileByHash(model.FileHash, token), RemoteUrl = model.RemoteUrl + }; await DeleteAllAttachment(challenge, false, token); @@ -124,7 +123,7 @@ internal async Task DeleteAllAttachment(Challenge challenge, bool purge = false, if (purge && challenge.Type == ChallengeType.DynamicAttachment) { - foreach (var flag in challenge.Flags) + foreach (FlagContext flag in challenge.Flags) await DeleteAttachment(flag.Attachment, token); context.RemoveRange(challenge.Flags); @@ -141,4 +140,4 @@ internal async Task DeleteAttachment(Attachment? attachment, CancellationToken t context.Remove(attachment); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/CheatInfoRepository.cs b/src/GZCTF/Repositories/CheatInfoRepository.cs index 9b0137d1c..0f6efa3f1 100644 --- a/src/GZCTF/Repositories/CheatInfoRepository.cs +++ b/src/GZCTF/Repositories/CheatInfoRepository.cs @@ -1,5 +1,4 @@ -using GZCTF.Models.Data; -using GZCTF.Repositories.Interface; +using GZCTF.Repositories.Interface; using Microsoft.EntityFrameworkCore; namespace GZCTF.Repositories; @@ -7,31 +6,26 @@ namespace GZCTF.Repositories; public class CheatInfoRepository(AppDbContext context, IParticipationRepository participationRepository) : RepositoryBase(context), ICheatInfoRepository { - public async Task CreateCheatInfo(Submission submission, Instance source, CancellationToken token = default) + public async Task CreateCheatInfo(Submission submission, Instance source, + CancellationToken token = default) { - var submit = await participationRepository.GetParticipation(submission.Team, submission.Game, token); + Participation? submit = await participationRepository.GetParticipation(submission.Team, submission.Game, token); if (submit is null) throw new NullReferenceException(nameof(submit)); - CheatInfo info = new() - { - GameId = submission.GameId, - Submission = submission, - SubmitTeam = submit, - SourceTeam = source.Participation - }; + CheatInfo info = new() { GameId = submission.GameId, Submission = submission, SubmitTeam = submit, SourceTeam = source.Participation }; await context.AddAsync(info, token); return info; } - public Task GetCheatInfoByGameId(int gameId, CancellationToken token = default) - => context.CheatInfo.IgnoreAutoIncludes().Where(i => i.GameId == gameId) + public Task GetCheatInfoByGameId(int gameId, CancellationToken token = default) => + context.CheatInfo.IgnoreAutoIncludes().Where(i => i.GameId == gameId) .Include(i => i.SourceTeam).ThenInclude(t => t.Team) .Include(i => i.SubmitTeam).ThenInclude(t => t.Team) .Include(i => i.Submission).ThenInclude(s => s.User) .Include(i => i.Submission).ThenInclude(s => s.Challenge) .AsSplitQuery().ToArrayAsync(token); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/ContainerRepository.cs b/src/GZCTF/Repositories/ContainerRepository.cs index 31ecb7a72..db5d8531d 100644 --- a/src/GZCTF/Repositories/ContainerRepository.cs +++ b/src/GZCTF/Repositories/ContainerRepository.cs @@ -1,6 +1,6 @@ using GZCTF.Models.Request.Admin; using GZCTF.Repositories.Interface; -using GZCTF.Utils; +using GZCTF.Services.Cache; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; @@ -11,30 +11,29 @@ public class ContainerRepository(IDistributedCache cache, { public override Task CountAsync(CancellationToken token = default) => context.Containers.CountAsync(token); - public Task GetContainerById(string guid, CancellationToken token = default) - => context.Containers.FirstOrDefaultAsync(i => i.Id == guid, token); + public Task GetContainerById(string guid, CancellationToken token = default) => + context.Containers.FirstOrDefaultAsync(i => i.Id == guid, token); - public Task GetContainerWithInstanceById(string guid, CancellationToken token = default) - => context.Containers.IgnoreAutoIncludes() + public Task GetContainerWithInstanceById(string guid, CancellationToken token = default) => + context.Containers.IgnoreAutoIncludes() .Include(c => c.Instance).ThenInclude(i => i!.Challenge) .Include(c => c.Instance).ThenInclude(i => i!.FlagContext) .Include(c => c.Instance).ThenInclude(i => i!.Participation).ThenInclude(p => p.Team) .FirstOrDefaultAsync(i => i.Id == guid, token); - public Task> GetContainers(CancellationToken token = default) - => context.Containers.ToListAsync(token); + public Task> GetContainers(CancellationToken token = default) => context.Containers.ToListAsync(token); - public async Task GetContainerInstances(CancellationToken token = default) - => (await context.Containers - .Where(c => c.Instance != null) - .Include(c => c.Instance).ThenInclude(i => i!.Participation) - .OrderBy(c => c.StartedAt).ToArrayAsync(token)) - .Select(ContainerInstanceModel.FromContainer) - .ToArray(); + public async Task GetContainerInstances(CancellationToken token = default) => + (await context.Containers + .Where(c => c.Instance != null) + .Include(c => c.Instance).ThenInclude(i => i!.Participation) + .OrderBy(c => c.StartedAt).ToArrayAsync(token)) + .Select(ContainerInstanceModel.FromContainer) + .ToArray(); public Task> GetDyingContainers(CancellationToken token = default) { - var now = DateTimeOffset.UtcNow; + DateTimeOffset now = DateTimeOffset.UtcNow; return context.Containers.Where(c => c.ExpectStopAt < now).ToListAsync(token); } @@ -50,6 +49,6 @@ public async Task RemoveContainer(Container container, CancellationToken token = await SaveAsync(token); } - public async Task ValidateContainer(string guid, CancellationToken token = default) - => await context.Containers.AnyAsync(c => c.Id == guid, token); -} + public async Task ValidateContainer(string guid, CancellationToken token = default) => + await context.Containers.AnyAsync(c => c.Id == guid, token); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/FileRepository.cs b/src/GZCTF/Repositories/FileRepository.cs index eebdeed7c..662488594 100644 --- a/src/GZCTF/Repositories/FileRepository.cs +++ b/src/GZCTF/Repositories/FileRepository.cs @@ -1,60 +1,19 @@ using System.Security.Cryptography; using GZCTF.Repositories.Interface; -using GZCTF.Utils; using Microsoft.EntityFrameworkCore; using SixLabors.ImageSharp.Formats.Gif; namespace GZCTF.Repositories; -public class FileRepository(AppDbContext context, ILogger logger) : RepositoryBase(context), IFileRepository +public class FileRepository(AppDbContext context, ILogger logger) : RepositoryBase(context), + IFileRepository { public override Task CountAsync(CancellationToken token = default) => context.Files.CountAsync(token); - private static Stream GetStream(long bufferSize) => bufferSize <= 16 * 1024 * 1024 ? new MemoryStream() : - File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); - - private async Task StoreLocalFile(string fileName, Stream contentStream, CancellationToken token = default) - { - contentStream.Position = 0; - var hash = await SHA256.HashDataAsync(contentStream, token); - var fileHash = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); - - var localFile = await GetFileByHash(fileHash, token); - - if (localFile is not null) - { - localFile.FileSize = contentStream.Length; - localFile.Name = fileName; // allow rename - localFile.UploadTimeUTC = DateTimeOffset.UtcNow; // update upload time - localFile.ReferenceCount++; // same hash, add ref count - - logger.SystemLog($"文件引用计数 [{localFile.Hash[..8]}] {localFile.Name} => {localFile.ReferenceCount}", TaskStatus.Success, LogLevel.Debug); - - context.Update(localFile); - } - else - { - localFile = new() { Hash = fileHash, Name = fileName, FileSize = contentStream.Length }; - await context.AddAsync(localFile, token); - - var path = Path.Combine(FilePath.Uploads, localFile.Location); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - - using var fileStream = File.Create(Path.Combine(path, localFile.Hash)); - - contentStream.Position = 0; - await contentStream.CopyToAsync(fileStream, token); - } - - await SaveAsync(token); - return localFile; - } - - public async Task CreateOrUpdateFile(IFormFile file, string? fileName = null, CancellationToken token = default) + public async Task CreateOrUpdateFile(IFormFile file, string? fileName = null, + CancellationToken token = default) { - using var tmp = GetStream(file.Length); + using Stream tmp = GetStream(file.Length); logger.SystemLog($"缓存位置:{tmp.GetType()}", TaskStatus.Pending, LogLevel.Trace); @@ -62,7 +21,8 @@ public async Task CreateOrUpdateFile(IFormFile file, string? fileName return await StoreLocalFile(fileName ?? file.FileName, tmp, token); } - public async Task CreateOrUpdateImage(IFormFile file, string fileName, int resize = 300, CancellationToken token = default) + public async Task CreateOrUpdateImage(IFormFile file, string fileName, int resize = 300, + CancellationToken token = default) { // we do not process images larger than 32MB if (file.Length >= 32 * 1024 * 1024) @@ -72,11 +32,11 @@ public async Task CreateOrUpdateFile(IFormFile file, string? fileName { using Stream webpStream = new MemoryStream(); - using (var tmp = GetStream(file.Length)) + using (Stream tmp = GetStream(file.Length)) { await file.CopyToAsync(tmp, token); tmp.Position = 0; - using var image = await Image.LoadAsync(tmp, token); + using Image image = await Image.LoadAsync(tmp, token); if (image.Metadata.DecodedImageFormat is GifFormat) return await StoreLocalFile($"{fileName}.gif", tmp, token); @@ -104,7 +64,8 @@ public async Task DeleteFile(LocalFile file, CancellationToken token { file.ReferenceCount--; // other ref exists, decrease ref count - logger.SystemLog($"文件引用计数 [{file.Hash[..8]}] {file.Name} => {file.ReferenceCount}", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog($"文件引用计数 [{file.Hash[..8]}] {file.Name} => {file.ReferenceCount}", TaskStatus.Success, + LogLevel.Debug); await SaveAsync(token); @@ -130,7 +91,7 @@ public async Task DeleteFile(LocalFile file, CancellationToken token public async Task DeleteFileByHash(string fileHash, CancellationToken token = default) { - var file = await GetFileByHash(fileHash, token); + LocalFile? file = await GetFileByHash(fileHash, token); if (file is null) return TaskStatus.NotFound; @@ -138,9 +99,54 @@ public async Task DeleteFileByHash(string fileHash, CancellationToke return await DeleteFile(file, token); } - public Task GetFileByHash(string? fileHash, CancellationToken token = default) - => context.Files.SingleOrDefaultAsync(f => f.Hash == fileHash, token); + public Task GetFileByHash(string? fileHash, CancellationToken token = default) => + context.Files.SingleOrDefaultAsync(f => f.Hash == fileHash, token); - public Task GetFiles(int count, int skip, CancellationToken token = default) - => context.Files.OrderBy(e => e.Name).Skip(skip).Take(count).ToArrayAsync(token); -} + public Task GetFiles(int count, int skip, CancellationToken token = default) => + context.Files.OrderBy(e => e.Name).Skip(skip).Take(count).ToArrayAsync(token); + + static Stream GetStream(long bufferSize) => + bufferSize <= 16 * 1024 * 1024 + ? new MemoryStream() + : File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); + + async Task StoreLocalFile(string fileName, Stream contentStream, CancellationToken token = default) + { + contentStream.Position = 0; + var hash = await SHA256.HashDataAsync(contentStream, token); + var fileHash = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + + LocalFile? localFile = await GetFileByHash(fileHash, token); + + if (localFile is not null) + { + localFile.FileSize = contentStream.Length; + localFile.Name = fileName; // allow rename + localFile.UploadTimeUTC = DateTimeOffset.UtcNow; // update upload time + localFile.ReferenceCount++; // same hash, add ref count + + logger.SystemLog($"文件引用计数 [{localFile.Hash[..8]}] {localFile.Name} => {localFile.ReferenceCount}", + TaskStatus.Success, LogLevel.Debug); + + context.Update(localFile); + } + else + { + localFile = new() { Hash = fileHash, Name = fileName, FileSize = contentStream.Length }; + await context.AddAsync(localFile, token); + + var path = Path.Combine(FilePath.Uploads, localFile.Location); + + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + using FileStream fileStream = File.Create(Path.Combine(path, localFile.Hash)); + + contentStream.Position = 0; + await contentStream.CopyToAsync(fileStream, token); + } + + await SaveAsync(token); + return localFile; + } +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/GameEventRepository.cs b/src/GZCTF/Repositories/GameEventRepository.cs index 4c46ff970..7fb2399cc 100644 --- a/src/GZCTF/Repositories/GameEventRepository.cs +++ b/src/GZCTF/Repositories/GameEventRepository.cs @@ -18,18 +18,19 @@ public async Task AddEvent(GameEvent gameEvent, CancellationToken tok gameEvent = await context.GameEvents.SingleAsync(s => s.Id == gameEvent.Id, token); await hub.Clients.Group($"Game_{gameEvent.GameId}") - .ReceivedGameEvent(gameEvent); + .ReceivedGameEvent(gameEvent); return gameEvent; } - public Task GetEvents(int gameId, bool hideContainer = false, int count = 50, int skip = 0, CancellationToken token = default) + public Task GetEvents(int gameId, bool hideContainer = false, int count = 50, int skip = 0, + CancellationToken token = default) { - var data = context.GameEvents.Where(e => e.GameId == gameId); + IQueryable data = context.GameEvents.Where(e => e.GameId == gameId); if (hideContainer) data = data.Where(e => e.Type != EventType.ContainerStart && e.Type != EventType.ContainerDestroy); return data.OrderByDescending(e => e.PublishTimeUTC).Skip(skip).Take(count).ToArrayAsync(token); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/GameNoticeRepository.cs b/src/GZCTF/Repositories/GameNoticeRepository.cs index d4a0e09c0..4e5196345 100644 --- a/src/GZCTF/Repositories/GameNoticeRepository.cs +++ b/src/GZCTF/Repositories/GameNoticeRepository.cs @@ -2,7 +2,7 @@ using GZCTF.Hubs; using GZCTF.Hubs.Clients; using GZCTF.Repositories.Interface; -using GZCTF.Utils; +using GZCTF.Services.Cache; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; @@ -27,16 +27,16 @@ await hub.Clients.Group($"Game_{notice.GameId}") return notice; } - public Task GetNormalNotices(int gameId, CancellationToken token = default) - => context.GameNotices + public Task GetNormalNotices(int gameId, CancellationToken token = default) => + context.GameNotices .Where(n => n.GameId == gameId && n.Type == NoticeType.Normal) .ToArrayAsync(token); - public Task GetNoticeById(int gameId, int noticeId, CancellationToken token = default) - => context.GameNotices.FirstOrDefaultAsync(e => e.Id == noticeId && e.GameId == gameId, token); + public Task GetNoticeById(int gameId, int noticeId, CancellationToken token = default) => + context.GameNotices.FirstOrDefaultAsync(e => e.Id == noticeId && e.GameId == gameId, token); - public Task GetNotices(int gameId, int count = 100, int skip = 0, CancellationToken token = default) - => cache.GetOrCreateAsync(logger, CacheKey.GameNotice(gameId), (entry) => + public Task GetNotices(int gameId, int count = 100, int skip = 0, CancellationToken token = default) => + cache.GetOrCreateAsync(logger, CacheKey.GameNotice(gameId), entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30); return context.GameNotices.Where(e => e.GameId == gameId) @@ -61,4 +61,4 @@ public async Task UpdateNotice(GameNotice notice, CancellationToken return notice; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/GameRepository.cs b/src/GZCTF/Repositories/GameRepository.cs index 7f158687d..96a5ff517 100644 --- a/src/GZCTF/Repositories/GameRepository.cs +++ b/src/GZCTF/Repositories/GameRepository.cs @@ -1,10 +1,10 @@ using GZCTF.Extensions; using GZCTF.Models.Request.Game; using GZCTF.Repositories.Interface; -using GZCTF.Services; -using GZCTF.Utils; +using GZCTF.Services.Cache; using MemoryPack; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Caching.Distributed; namespace GZCTF.Repositories; @@ -17,7 +17,7 @@ public class GameRepository(IDistributedCache cache, ILogger logger, AppDbContext context) : RepositoryBase(context), IGameRepository { - private readonly byte[]? _xorkey = configuration["XorKey"]?.ToUTF8Bytes(); + readonly byte[]? _xorkey = configuration["XorKey"]?.ToUTF8Bytes(); public override Task CountAsync(CancellationToken token = default) => context.Games.CountAsync(token); @@ -33,19 +33,18 @@ public class GameRepository(IDistributedCache cache, return game; } - public string GetToken(Game game, Team team) - => $"{team.Id}:{game.Sign($"GZCTF_TEAM_{team.Id}", _xorkey)}"; + public string GetToken(Game game, Team team) => $"{team.Id}:{game.Sign($"GZCTF_TEAM_{team.Id}", _xorkey)}"; - public Task GetGameById(int id, CancellationToken token = default) - => context.Games.FirstOrDefaultAsync(x => x.Id == id, token); + public Task GetGameById(int id, CancellationToken token = default) => context.Games.FirstOrDefaultAsync(x => x.Id == id, token); - public Task GetUpcomingGames(CancellationToken token = default) - => context.Games.Where(g => g.StartTimeUTC > DateTime.UtcNow - && g.StartTimeUTC - DateTime.UtcNow < TimeSpan.FromMinutes(5)) + public Task GetUpcomingGames(CancellationToken token = default) => + context.Games.Where(g => g.StartTimeUTC > DateTime.UtcNow + && g.StartTimeUTC - DateTime.UtcNow < TimeSpan.FromMinutes(5)) .OrderBy(g => g.StartTimeUTC).Select(g => g.Id).ToArrayAsync(token); - public async Task GetBasicGameInfo(int count = 10, int skip = 0, CancellationToken token = default) - => await cache.GetOrCreateAsync(logger, CacheKey.BasicGameInfo, entry => + public async Task GetBasicGameInfo(int count = 10, int skip = 0, + CancellationToken token = default) => + await cache.GetOrCreateAsync(logger, CacheKey.BasicGameInfo, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2); return context.Games.Where(g => !g.Hidden) @@ -53,8 +52,8 @@ public async Task GetBasicGameInfo(int count = 10, int ski .Select(g => BasicGameInfoModel.FromGame(g)).ToArrayAsync(token); }, token); - public Task GetScoreboard(Game game, CancellationToken token = default) - => cache.GetOrCreateAsync(logger, CacheKey.ScoreBoard(game.Id), entry => + public Task GetScoreboard(Game game, CancellationToken token = default) => + cache.GetOrCreateAsync(logger, CacheKey.ScoreBoard(game.Id), entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(7); return GenScoreboard(game, token); @@ -63,13 +62,11 @@ public Task GetScoreboard(Game game, CancellationToken token = public async Task GetScoreboardWithMembers(Game game, CancellationToken token = default) { // In most cases, we can get the scoreboard from the cache - var scoreboard = await GetScoreboard(game, token); + ScoreboardModel scoreboard = await GetScoreboard(game, token); - foreach (var item in scoreboard.Items) - { + foreach (ScoreboardItem item in scoreboard.Items) item.TeamInfo = await teamRepository.GetTeamById(item.Id, token) ?? - throw new ArgumentNullException("team", "Team not found"); - } + throw new ArgumentNullException("team", "Team not found"); return scoreboard; } @@ -77,22 +74,24 @@ public async Task GetScoreboardWithMembers(Game game, Cancellat public async Task DeleteGame(Game game, CancellationToken token = default) { - var trans = await BeginTransactionAsync(token); + IDbContextTransaction trans = await BeginTransactionAsync(token); try { await context.Entry(game).Collection(g => g.Challenges).LoadAsync(token); - logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Challenges.Count} 个题目的相关附件……", TaskStatus.Pending, LogLevel.Debug); + logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Challenges.Count} 个题目的相关附件……", TaskStatus.Pending, + LogLevel.Debug); - foreach (var chal in game.Challenges) + foreach (Challenge chal in game.Challenges) await challengeRepository.RemoveChallenge(chal, token); await context.Entry(game).Collection(g => g.Participations).LoadAsync(token); - logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Participations.Count} 个队伍相关文件……", TaskStatus.Pending, LogLevel.Debug); + logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Participations.Count} 个队伍相关文件……", TaskStatus.Pending, + LogLevel.Debug); - foreach (var part in game.Participations) + foreach (Participation part in game.Participations) await participationRepository.RemoveParticipation(part, token); context.Remove(game); @@ -107,7 +106,7 @@ public async Task DeleteGame(Game game, CancellationToken token = de } catch { - logger.SystemLog($"删除比赛失败,相关文件可能已受损,请重新删除", TaskStatus.Pending, LogLevel.Debug); + logger.SystemLog("删除比赛失败,相关文件可能已受损,请重新删除", TaskStatus.Pending, LogLevel.Debug); await trans.RollbackAsync(token); return TaskStatus.Failed; @@ -118,28 +117,28 @@ public async Task DeleteAllWriteUps(Game game, CancellationToken token = default { await context.Entry(game).Collection(g => g.Participations).LoadAsync(token); - logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Participations.Count} 个队伍相关文件……", TaskStatus.Pending, LogLevel.Debug); + logger.SystemLog($"正在清理比赛 {game.Title} 的 {game.Participations.Count} 个队伍相关文件……", TaskStatus.Pending, + LogLevel.Debug); - foreach (var part in game.Participations) + foreach (Participation part in game.Participations) await participationRepository.DeleteParticipationWriteUp(part, token); } - public Task GetGames(int count, int skip, CancellationToken token) - => context.Games.OrderByDescending(g => g.Id).Skip(skip).Take(count).ToArrayAsync(token); + public Task GetGames(int count, int skip, CancellationToken token) => + context.Games.OrderByDescending(g => g.Id).Skip(skip).Take(count).ToArrayAsync(token); - public void FlushGameInfoCache() - => cache.Remove(CacheKey.BasicGameInfo); + public void FlushGameInfoCache() => cache.Remove(CacheKey.BasicGameInfo); #region Generate Scoreboard - private record Data(Instance Instance, Submission? Submission); + record Data(Instance Instance, Submission? Submission); // By xfoxfu & GZTimeWalker @ 2022/04/03 public async Task GenScoreboard(Game game, CancellationToken token = default) { - var data = await FetchData(game, token); - var bloods = GenBloods(data); - var items = GenScoreboardItems(data, game, bloods); + Data[] data = await FetchData(game, token); + IDictionary bloods = GenBloods(data); + IEnumerable items = GenScoreboardItems(data, game, bloods); return new() { Challenges = GenChallenges(data, bloods), @@ -149,16 +148,16 @@ public async Task GenScoreboard(Game game, CancellationToken to }; } - private Task FetchData(Game game, CancellationToken token = default) - => context.Instances + Task FetchData(Game game, CancellationToken token = default) => + context.Instances .Include(i => i.Challenge) .Where(i => i.Challenge.Game == game - && i.Challenge.IsEnabled - && i.Participation.Status == ParticipationStatus.Accepted) + && i.Challenge.IsEnabled + && i.Participation.Status == ParticipationStatus.Accepted) .Include(i => i.Participation).ThenInclude(p => p.Team).ThenInclude(t => t.Members) .GroupJoin( context.Submissions.Where(s => s.Status == AnswerResult.Accepted - && s.SubmitTimeUTC < game.EndTimeUTC), + && s.SubmitTimeUTC < game.EndTimeUTC), i => new { i.ChallengeId, i.ParticipationId }, s => new { s.ChallengeId, s.ParticipationId }, (i, s) => new { Instance = i, Submissions = s } @@ -166,32 +165,35 @@ private Task FetchData(Game game, CancellationToken token = default) (j, s) => new Data(j.Instance, s) ).AsSplitQuery().ToArrayAsync(token); - private static IDictionary GenBloods(Data[] data) - => data.GroupBy(j => j.Instance.Challenge).Select(g => new + static IDictionary GenBloods(Data[] data) => + data.GroupBy(j => j.Instance.Challenge).Select(g => new { g.Key, Value = g.GroupBy(c => c.Submission?.TeamId) .Where(t => t.Key is not null) .Select(c => { - var s = c.OrderBy(t => t.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) + Data? s = c.OrderBy(t => t.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) .FirstOrDefault(s => s.Submission?.Status == AnswerResult.Accepted); - return s is null ? null : new Blood - { - Id = s.Instance.Participation.TeamId, - Avatar = s.Instance.Participation.Team.AvatarUrl, - Name = s.Instance.Participation.Team.Name, - SubmitTimeUTC = s.Submission?.SubmitTimeUTC - }; + return s is null + ? null + : new Blood + { + Id = s.Instance.Participation.TeamId, + Avatar = s.Instance.Participation.Team.AvatarUrl, + Name = s.Instance.Participation.Team.Name, + SubmitTimeUTC = s.Submission?.SubmitTimeUTC + }; }) .Where(t => t is not null) .OrderBy(t => t?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) - .Take(3).ToArray(), + .Take(3).ToArray() }).ToDictionary(a => a.Key.Id, a => a.Value); - private static Dictionary> GenChallenges(Data[] data, IDictionary bloods) - => data.GroupBy(g => g.Instance.Challenge) + static Dictionary> GenChallenges(Data[] data, + IDictionary bloods) => + data.GroupBy(g => g.Instance.Challenge) .Select(c => new ChallengeInfo { Id = c.Key.Id, @@ -204,13 +206,13 @@ private static Dictionary> GenChallenge .OrderBy(i => i.Key) .ToDictionary(c => c.Key, c => c.AsEnumerable()); - private static IEnumerable GenScoreboardItems(Data[] data, Game game, IDictionary bloods) + static IEnumerable GenScoreboardItems(Data[] data, Game game, IDictionary bloods) { Dictionary Ranks = new(); return data.GroupBy(j => j.Instance.Participation) .Select(j => { - var challengeGroup = j.GroupBy(s => s.Instance.ChallengeId); + IEnumerable> challengeGroup = j.GroupBy(s => s.Instance.ChallengeId); return new ScoreboardItem { @@ -226,46 +228,54 @@ private static IEnumerable GenScoreboardItems(Data[] data, Game .OrderBy(t => t).LastOrDefault(game.StartTimeUTC), SolvedCount = challengeGroup.Count(c => c.Any( s => s.Submission?.Status == AnswerResult.Accepted - && s.Submission.SubmitTimeUTC < game.EndTimeUTC)), + && s.Submission.SubmitTimeUTC < game.EndTimeUTC)), Challenges = challengeGroup - .Select(c => + .Select(c => + { + var cid = c.Key; + Data? s = c.OrderBy(s => s.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) + .FirstOrDefault(s => s.Submission?.Status == AnswerResult.Accepted); + + var status = SubmissionType.Normal; + + if (s?.Submission is null) + status = SubmissionType.Unaccepted; + else if (bloods[cid][0] is not null && + s.Submission.SubmitTimeUTC <= bloods[cid][0]!.SubmitTimeUTC) + status = SubmissionType.FirstBlood; + else if (bloods[cid][1] is not null && + s.Submission.SubmitTimeUTC <= bloods[cid][1]!.SubmitTimeUTC) + status = SubmissionType.SecondBlood; + else if (bloods[cid][2] is not null && + s.Submission.SubmitTimeUTC <= bloods[cid][2]!.SubmitTimeUTC) + status = SubmissionType.ThirdBlood; + + return new ChallengeItem { - var cid = c.Key; - var s = c.OrderBy(s => s.Submission?.SubmitTimeUTC ?? DateTimeOffset.UtcNow) - .FirstOrDefault(s => s.Submission?.Status == AnswerResult.Accepted); - - SubmissionType status = SubmissionType.Normal; - - if (s?.Submission is null) - status = SubmissionType.Unaccepted; - else if (bloods[cid][0] is not null && s.Submission.SubmitTimeUTC <= bloods[cid][0]!.SubmitTimeUTC) - status = SubmissionType.FirstBlood; - else if (bloods[cid][1] is not null && s.Submission.SubmitTimeUTC <= bloods[cid][1]!.SubmitTimeUTC) - status = SubmissionType.SecondBlood; - else if (bloods[cid][2] is not null && s.Submission.SubmitTimeUTC <= bloods[cid][2]!.SubmitTimeUTC) - status = SubmissionType.ThirdBlood; - - return new ChallengeItem - { - Id = cid, - Type = status, - UserName = s?.Submission?.UserName, - SubmitTimeUTC = s?.Submission?.SubmitTimeUTC, - Score = s is null ? 0 : game.BloodBonus.NoBonus ? status switch + Id = cid, + Type = status, + UserName = s?.Submission?.UserName, + SubmitTimeUTC = s?.Submission?.SubmitTimeUTC, + Score = s is null ? 0 : + game.BloodBonus.NoBonus ? status switch { SubmissionType.Unaccepted => 0, - _ => s.Instance.Challenge.CurrentScore, + _ => s.Instance.Challenge.CurrentScore } : status switch { SubmissionType.Unaccepted => 0, - SubmissionType.FirstBlood => Convert.ToInt32(s.Instance.Challenge.CurrentScore * game.BloodBonus.FirstBloodFactor), - SubmissionType.SecondBlood => Convert.ToInt32(s.Instance.Challenge.CurrentScore * game.BloodBonus.SecondBloodFactor), - SubmissionType.ThirdBlood => Convert.ToInt32(s.Instance.Challenge.CurrentScore * game.BloodBonus.ThirdBloodFactor), + SubmissionType.FirstBlood => Convert.ToInt32(s.Instance.Challenge.CurrentScore * + game.BloodBonus.FirstBloodFactor), + SubmissionType.SecondBlood => Convert.ToInt32( + s.Instance.Challenge.CurrentScore * + game.BloodBonus.SecondBloodFactor), + SubmissionType.ThirdBlood => Convert.ToInt32(s.Instance.Challenge.CurrentScore * + game.BloodBonus.ThirdBloodFactor), SubmissionType.Normal => s.Instance.Challenge.CurrentScore, _ => throw new ArgumentException(nameof(status)) } - }; - }).ToList() + }; + }).ToList() }; }).OrderByDescending(j => j.Score).ThenBy(j => j.LastSubmissionTime) //成绩倒序,最后提交时间正序 .Select((j, i) => @@ -274,7 +284,7 @@ private static IEnumerable GenScoreboardItems(Data[] data, Game if (j.Organization is not null) { - if (Ranks.TryGetValue(j.Organization, out int rank)) + if (Ranks.TryGetValue(j.Organization, out var rank)) { j.OrganizationRank = rank + 1; Ranks[j.Organization]++; @@ -290,29 +300,23 @@ private static IEnumerable GenScoreboardItems(Data[] data, Game }).ToArray(); } - private static Dictionary> GenTopTimeLines(IEnumerable items, Game game) + static Dictionary> GenTopTimeLines(IEnumerable items, Game game) { - var timelines = game.Organizations is { Count: > 0 } ? items - .GroupBy(i => i.Organization ?? "all") - .ToDictionary(i => i.Key, i => i.Take(10) - .Select(team => new TopTimeLine - { - Id = team.Id, - Name = team.Name, - Items = GenTimeLine(team.Challenges) - }).ToArray().AsEnumerable()) : new(); + Dictionary> timelines = game.Organizations is { Count: > 0 } + ? items + .GroupBy(i => i.Organization ?? "all") + .ToDictionary(i => i.Key, i => i.Take(10) + .Select(team => new TopTimeLine { Id = team.Id, Name = team.Name, Items = GenTimeLine(team.Challenges) }).ToArray() + .AsEnumerable()) + : new(); - timelines["all"] = items.Take(10).Select(team => new TopTimeLine - { - Id = team.Id, - Name = team.Name, - Items = GenTimeLine(team.Challenges) - }).ToArray(); + timelines["all"] = items.Take(10).Select(team => new TopTimeLine { Id = team.Id, Name = team.Name, Items = GenTimeLine(team.Challenges) }) + .ToArray(); return timelines; } - private static IEnumerable GenTimeLine(IEnumerable items) + static IEnumerable GenTimeLine(IEnumerable items) { var score = 0; return items.Where(i => i.SubmitTimeUTC is not null) @@ -320,10 +324,9 @@ private static IEnumerable GenTimeLine(IEnumerable item .Select(i => { score += i.Score; - return new TimeLine() + return new TimeLine { - Score = score, - Time = i.SubmitTimeUTC!.Value // 此处不为 null + Score = score, Time = i.SubmitTimeUTC!.Value // 此处不为 null }; }); } @@ -333,32 +336,30 @@ private static IEnumerable GenTimeLine(IEnumerable item public class ScoreboardCacheHandler : ICacheRequestHandler { - public static CacheRequest MakeCacheRequest(int id) - => new(Utils.CacheKey.ScoreBoardBase, new() - { - AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(14) - }, id.ToString()); - public string? CacheKey(CacheRequest request) { if (request.Params.Length != 1) return null; - return Utils.CacheKey.ScoreBoard(request.Params[0]); + return Services.Cache.CacheKey.ScoreBoard(request.Params[0]); } public async Task Handler(AsyncServiceScope scope, CacheRequest request, CancellationToken token = default) { - if (!int.TryParse(request.Params[0], out int id)) + if (!int.TryParse(request.Params[0], out var id)) return Array.Empty(); var gameRepository = scope.ServiceProvider.GetRequiredService(); - var game = await gameRepository.GetGameById(id, token); + Game? game = await gameRepository.GetGameById(id, token); if (game is null) return Array.Empty(); - var scoreboard = await gameRepository.GenScoreboard(game, token); + ScoreboardModel scoreboard = await gameRepository.GenScoreboard(game, token); return MemoryPackSerializer.Serialize(scoreboard); } -} + + public static CacheRequest MakeCacheRequest(int id) => + new(Services.Cache.CacheKey.ScoreBoardBase, + new() { AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(14) }, id.ToString()); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/InstanceRepository.cs b/src/GZCTF/Repositories/InstanceRepository.cs index b5a73578a..d37f8a90c 100644 --- a/src/GZCTF/Repositories/InstanceRepository.cs +++ b/src/GZCTF/Repositories/InstanceRepository.cs @@ -1,8 +1,8 @@ using GZCTF.Models.Internal; using GZCTF.Repositories.Interface; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Options; namespace GZCTF.Repositories; @@ -17,16 +17,17 @@ public class InstanceRepository(AppDbContext context, { public async Task GetInstance(Participation part, int challengeId, CancellationToken token = default) { - using var transaction = await context.Database.BeginTransactionAsync(token); + using IDbContextTransaction transaction = await context.Database.BeginTransactionAsync(token); - var instance = await context.Instances + Instance? instance = await context.Instances .Include(i => i.FlagContext) .Where(e => e.ChallengeId == challengeId && e.Participation == part) .SingleOrDefaultAsync(token); if (instance is null) { - logger.SystemLog($"队伍对应参与对象为空,这可能是非预期的情况 [{part.Id}, {challengeId}]", TaskStatus.NotFound, LogLevel.Warning); + logger.SystemLog($"队伍对应参与对象为空,这可能是非预期的情况 [{part.Id}, {challengeId}]", TaskStatus.NotFound, + LogLevel.Warning); return null; } @@ -36,7 +37,7 @@ public class InstanceRepository(AppDbContext context, return instance; } - var challenge = instance.Challenge; + Challenge? challenge = instance.Challenge; if (challenge is null || !challenge.IsEnabled) { @@ -60,13 +61,14 @@ public class InstanceRepository(AppDbContext context, }; break; case ChallengeType.DynamicAttachment: - var flags = await context.FlagContexts + List flags = await context.FlagContexts .Where(e => e.Challenge == challenge && !e.IsOccupied) .ToListAsync(token); if (flags.Count == 0) { - logger.SystemLog($"题目 {challenge.Title}#{challenge.Id} 请求分配的动态附件数量不足", TaskStatus.Failed, LogLevel.Warning); + logger.SystemLog($"题目 {challenge.Title}#{challenge.Id} 请求分配的动态附件数量不足", TaskStatus.Failed, + LogLevel.Warning); return null; } @@ -75,8 +77,6 @@ public class InstanceRepository(AppDbContext context, instance.FlagId = flags[pos].Id; break; - default: - break; } // instance.FlagContext is null by default @@ -88,7 +88,8 @@ public class InstanceRepository(AppDbContext context, } catch { - logger.SystemLog($"为队伍 {part.Team.Name} 获取题目 {challenge.Title}#{challenge.Id} 的实例时遇到问题(可能由于并发错误),回滚中", TaskStatus.Failed, LogLevel.Warning); + logger.SystemLog($"为队伍 {part.Team.Name} 获取题目 {challenge.Title}#{challenge.Id} 的实例时遇到问题(可能由于并发错误),回滚中", + TaskStatus.Failed, LogLevel.Warning); await transaction.RollbackAsync(token); return null; } @@ -106,12 +107,15 @@ public async Task DestroyContainer(Container container, CancellationToken } catch (Exception ex) { - logger.SystemLog($"销毁容器 [{container.ContainerId[..12]}] ({container.Image.Split("/").LastOrDefault()}): {ex.Message}", TaskStatus.Failed, LogLevel.Warning); + logger.SystemLog( + $"销毁容器 [{container.ContainerId[..12]}] ({container.Image.Split("/").LastOrDefault()}): {ex.Message}", + TaskStatus.Failed, LogLevel.Warning); return false; } } - public async Task> CreateContainer(Instance instance, Team team, UserInfo user, int containerLimit = 3, CancellationToken token = default) + public async Task> CreateContainer(Instance instance, Team team, UserInfo user, + int containerLimit = 3, CancellationToken token = default) { if (string.IsNullOrEmpty(instance.Challenge.ContainerImage) || instance.Challenge.ContainerExposePort is null) { @@ -124,14 +128,15 @@ public async Task> CreateContainer(Instance instance, Team { if (gamePolicy.Value.AutoDestroyOnLimitReached) { - var running = await context.Instances + List running = await context.Instances .Where(i => i.Participation == instance.Participation && i.Container != null) .OrderBy(i => i.Container!.StartedAt).ToListAsync(token); - var first = running.FirstOrDefault(); + Instance? first = running.FirstOrDefault(); if (running.Count >= containerLimit && first is not null) { - logger.Log($"{team.Name} 自动销毁题目 {first.Challenge.Title} 的容器实例 [{first.Container!.ContainerId}]", user, TaskStatus.Success); + logger.Log($"{team.Name} 自动销毁题目 {first.Challenge.Title} 的容器实例 [{first.Container!.ContainerId}]", + user, TaskStatus.Success); await DestroyContainer(running.First().Container!, token); } } @@ -139,7 +144,7 @@ public async Task> CreateContainer(Instance instance, Team { var count = await context.Instances.CountAsync( i => i.Participation == instance.Participation && - i.Container != null, token); + i.Container != null, token); if (count >= containerLimit) return new TaskResult(TaskStatus.Denied); @@ -149,7 +154,7 @@ public async Task> CreateContainer(Instance instance, Team if (instance.Container is null) { await context.Entry(instance).Reference(e => e.FlagContext).LoadAsync(token); - var container = await service.CreateContainerAsync(new ContainerConfig() + Container? container = await service.CreateContainerAsync(new ContainerConfig { TeamId = team.Id.ToString(), UserId = user.Id, @@ -159,7 +164,7 @@ public async Task> CreateContainer(Instance instance, Team MemoryLimit = instance.Challenge.MemoryLimit ?? 64, StorageLimit = instance.Challenge.StorageLimit ?? 256, EnableTrafficCapture = instance.Challenge.EnableTrafficCapture, - ExposedPort = instance.Challenge.ContainerExposePort ?? throw new ArgumentException("创建容器时遇到无效的端口"), + ExposedPort = instance.Challenge.ContainerExposePort ?? throw new ArgumentException("创建容器时遇到无效的端口") }, token); if (container is null) @@ -171,17 +176,19 @@ public async Task> CreateContainer(Instance instance, Team instance.Container = container; instance.LastContainerOperation = DateTimeOffset.UtcNow; - logger.Log($"{team.Name} 启动题目 {instance.Challenge.Title} 的容器实例 [{container.ContainerId}]", user, TaskStatus.Success); + logger.Log($"{team.Name} 启动题目 {instance.Challenge.Title} 的容器实例 [{container.ContainerId}]", user, + TaskStatus.Success); // will save instance together - await gameEventRepository.AddEvent(new() - { - Type = EventType.ContainerStart, - GameId = instance.Challenge.GameId, - TeamId = instance.Participation.TeamId, - UserId = user.Id, - Content = $"{instance.Challenge.Title}#{instance.Challenge.Id} 启动容器实例" - }, token); + await gameEventRepository.AddEvent( + new() + { + Type = EventType.ContainerStart, + GameId = instance.Challenge.GameId, + TeamId = instance.Participation.TeamId, + UserId = user.Id, + Content = $"{instance.Challenge.Title}#{instance.Challenge.Id} 启动容器实例" + }, token); } return new TaskResult(TaskStatus.Success, instance.Container); @@ -193,26 +200,25 @@ public async Task ProlongContainer(Container container, TimeSpan time, Cancellat await SaveAsync(token); } - public Task GetInstances(Challenge challenge, CancellationToken token = default) - => context.Instances.Where(i => i.Challenge == challenge).OrderBy(i => i.ParticipationId) + public Task GetInstances(Challenge challenge, CancellationToken token = default) => + context.Instances.Where(i => i.Challenge == challenge).OrderBy(i => i.ParticipationId) .Include(i => i.Participation).ThenInclude(i => i.Team).ToArrayAsync(token); public async Task CheckCheat(Submission submission, CancellationToken token = default) { CheatCheckInfo checkInfo = new(); - var instances = await context.Instances.Where(i => i.ChallengeId == submission.ChallengeId && - i.ParticipationId != submission.ParticipationId) - .Include(i => i.FlagContext).Include(i => i.Participation) - .ThenInclude(i => i.Team).ToArrayAsync(token); + Instance[] instances = await context.Instances.Where(i => i.ChallengeId == submission.ChallengeId && + i.ParticipationId != submission.ParticipationId) + .Include(i => i.FlagContext).Include(i => i.Participation) + .ThenInclude(i => i.Team).ToArrayAsync(token); - foreach (var instance in instances) - { + foreach (Instance instance in instances) if (instance.FlagContext?.Flag == submission.Answer) { - var updateSub = await context.Submissions.Where(s => s.Id == submission.Id).SingleAsync(token); + Submission? updateSub = await context.Submissions.Where(s => s.Id == submission.Id).SingleAsync(token); - var cheatInfo = await cheatInfoRepository.CreateCheatInfo(updateSub, instance, token); + CheatInfo cheatInfo = await cheatInfoRepository.CreateCheatInfo(updateSub, instance, token); checkInfo = CheatCheckInfo.FromCheatInfo(cheatInfo); if (updateSub is not null) @@ -222,20 +228,19 @@ public async Task CheckCheat(Submission submission, Cancellation return checkInfo; } - } return checkInfo; } public async Task VerifyAnswer(Submission submission, CancellationToken token = default) { - var trans = await context.Database.BeginTransactionAsync(token); + IDbContextTransaction trans = await context.Database.BeginTransactionAsync(token); try { - var instance = await context.Instances.IgnoreAutoIncludes().Include(i => i.FlagContext) + Instance? instance = await context.Instances.IgnoreAutoIncludes().Include(i => i.FlagContext) .SingleOrDefaultAsync(i => i.ChallengeId == submission.ChallengeId && - i.ParticipationId == submission.ParticipationId, token); + i.ParticipationId == submission.ParticipationId, token); var ret = SubmissionType.Unaccepted; @@ -247,25 +252,23 @@ public async Task VerifyAnswer(Submission submission, Cancellation // submission is from the queue, do not modify it directly // we need to requery the entity to ensure it is being tracked correctly - var updateSub = await context.Submissions.SingleAsync(s => s.Id == submission.Id, token); + Submission updateSub = await context.Submissions.SingleAsync(s => s.Id == submission.Id, token); if (instance.FlagContext is null && submission.Challenge.Type.IsStatic()) - { updateSub.Status = await context.FlagContexts .AsNoTracking() .AnyAsync( f => f.ChallengeId == submission.ChallengeId && f.Flag == submission.Answer, token) - ? AnswerResult.Accepted : AnswerResult.WrongAnswer; - } + ? AnswerResult.Accepted + : AnswerResult.WrongAnswer; else - { updateSub.Status = instance.FlagContext?.Flag == submission.Answer - ? AnswerResult.Accepted : AnswerResult.WrongAnswer; - } + ? AnswerResult.Accepted + : AnswerResult.WrongAnswer; - bool firstTime = !instance.IsSolved && updateSub.Status == AnswerResult.Accepted; - bool beforeEnd = submission.Game.EndTimeUTC > submission.SubmitTimeUTC; + var firstTime = !instance.IsSolved && updateSub.Status == AnswerResult.Accepted; + var beforeEnd = submission.Game.EndTimeUTC > submission.SubmitTimeUTC; if (firstTime && beforeEnd) { @@ -281,8 +284,7 @@ public async Task VerifyAnswer(Submission submission, Cancellation } else { - ret = updateSub.Status == AnswerResult.Accepted ? - SubmissionType.Normal : SubmissionType.Unaccepted; + ret = updateSub.Status == AnswerResult.Accepted ? SubmissionType.Normal : SubmissionType.Unaccepted; } await SaveAsync(token); @@ -296,4 +298,4 @@ public async Task VerifyAnswer(Submission submission, Cancellation throw; } } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IChallengeRepository.cs b/src/GZCTF/Repositories/Interface/IChallengeRepository.cs index 4bdf832e3..0776c22f7 100644 --- a/src/GZCTF/Repositories/Interface/IChallengeRepository.cs +++ b/src/GZCTF/Repositories/Interface/IChallengeRepository.cs @@ -91,4 +91,4 @@ public interface IChallengeRepository : IRepository /// /// public Task VerifyStaticAnswer(Challenge challenge, string flag, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/ICheatInfoRepository.cs b/src/GZCTF/Repositories/Interface/ICheatInfoRepository.cs index 378c7755c..664c04989 100644 --- a/src/GZCTF/Repositories/Interface/ICheatInfoRepository.cs +++ b/src/GZCTF/Repositories/Interface/ICheatInfoRepository.cs @@ -1,6 +1,4 @@ -using GZCTF.Models.Data; - -namespace GZCTF.Repositories.Interface; +namespace GZCTF.Repositories.Interface; public interface ICheatInfoRepository : IRepository { @@ -20,4 +18,4 @@ public interface ICheatInfoRepository : IRepository /// /// public Task GetCheatInfoByGameId(int gameId, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IContainerRepository.cs b/src/GZCTF/Repositories/Interface/IContainerRepository.cs index c785706c5..26c7276e4 100644 --- a/src/GZCTF/Repositories/Interface/IContainerRepository.cs +++ b/src/GZCTF/Repositories/Interface/IContainerRepository.cs @@ -56,4 +56,4 @@ public interface IContainerRepository : IRepository /// /// public Task RemoveContainer(Container container, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IFileRepository.cs b/src/GZCTF/Repositories/Interface/IFileRepository.cs index 1b4516478..3f2d815c4 100644 --- a/src/GZCTF/Repositories/Interface/IFileRepository.cs +++ b/src/GZCTF/Repositories/Interface/IFileRepository.cs @@ -9,7 +9,8 @@ public interface IFileRepository : IRepository /// 保存文件名 /// 取消Token /// 文件Id - public Task CreateOrUpdateFile(IFormFile file, string? fileName = null, CancellationToken token = default); + public Task CreateOrUpdateFile(IFormFile file, string? fileName = null, + CancellationToken token = default); /// /// 创建或更新一个图像文件 @@ -19,7 +20,8 @@ public interface IFileRepository : IRepository /// 缩放后的宽,设置为 0 则不缩放 /// 取消Token /// 文件Id - public Task CreateOrUpdateImage(IFormFile file, string fileName, int resize = 300, CancellationToken token = default); + public Task CreateOrUpdateImage(IFormFile file, string fileName, int resize = 300, + CancellationToken token = default); /// /// 删除一个文件 @@ -53,4 +55,4 @@ public interface IFileRepository : IRepository /// 取消Token /// 文件对象列表 public Task GetFiles(int count, int skip, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IGameEventRepository.cs b/src/GZCTF/Repositories/Interface/IGameEventRepository.cs index af4e76b61..e280319e7 100644 --- a/src/GZCTF/Repositories/Interface/IGameEventRepository.cs +++ b/src/GZCTF/Repositories/Interface/IGameEventRepository.cs @@ -19,5 +19,6 @@ public interface IGameEventRepository : IRepository /// 跳过数量 /// /// - public Task GetEvents(int gameId, bool hideContainer = false, int count = 50, int skip = 0, CancellationToken token = default); -} + public Task GetEvents(int gameId, bool hideContainer = false, int count = 50, int skip = 0, + CancellationToken token = default); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IGameNoticeRepository.cs b/src/GZCTF/Repositories/Interface/IGameNoticeRepository.cs index 30227c20c..1d152fbf4 100644 --- a/src/GZCTF/Repositories/Interface/IGameNoticeRepository.cs +++ b/src/GZCTF/Repositories/Interface/IGameNoticeRepository.cs @@ -52,4 +52,4 @@ public interface IGameNoticeRepository : IRepository /// /// public Task RemoveNotice(GameNotice notice, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IGameRepository.cs b/src/GZCTF/Repositories/Interface/IGameRepository.cs index 6cc39fb10..e9348952a 100644 --- a/src/GZCTF/Repositories/Interface/IGameRepository.cs +++ b/src/GZCTF/Repositories/Interface/IGameRepository.cs @@ -96,4 +96,4 @@ public interface IGameRepository : IRepository /// 刷新比赛信息缓存 /// public void FlushGameInfoCache(); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IInstanceRepository.cs b/src/GZCTF/Repositories/Interface/IInstanceRepository.cs index 29a3af8b3..1635e1f72 100644 --- a/src/GZCTF/Repositories/Interface/IInstanceRepository.cs +++ b/src/GZCTF/Repositories/Interface/IInstanceRepository.cs @@ -1,5 +1,4 @@ using GZCTF.Models.Internal; -using GZCTF.Utils; namespace GZCTF.Repositories.Interface; @@ -47,7 +46,8 @@ public interface IInstanceRepository : IRepository /// 用户对象 /// /// - public Task> CreateContainer(Instance instance, Team team, UserInfo user, int containerLimit = 3, CancellationToken token = default); + public Task> CreateContainer(Instance instance, Team team, UserInfo user, + int containerLimit = 3, CancellationToken token = default); /// /// 销毁容器实例 @@ -65,4 +65,4 @@ public interface IInstanceRepository : IRepository /// /// public Task ProlongContainer(Container container, TimeSpan time, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/ILogRepository.cs b/src/GZCTF/Repositories/Interface/ILogRepository.cs index 18a55f63f..d00d28e6c 100644 --- a/src/GZCTF/Repositories/Interface/ILogRepository.cs +++ b/src/GZCTF/Repositories/Interface/ILogRepository.cs @@ -13,4 +13,4 @@ public interface ILogRepository : IRepository /// 操作取消token /// 不超过指定数量的日志 public Task GetLogs(int skip, int count, string? level, CancellationToken token); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IParticipationRepository.cs b/src/GZCTF/Repositories/Interface/IParticipationRepository.cs index a7be743bd..fb88d736c 100644 --- a/src/GZCTF/Repositories/Interface/IParticipationRepository.cs +++ b/src/GZCTF/Repositories/Interface/IParticipationRepository.cs @@ -1,5 +1,4 @@ using GZCTF.Models.Request.Admin; -using GZCTF.Models.Request.Game; namespace GZCTF.Repositories.Interface; @@ -122,5 +121,6 @@ public interface IParticipationRepository : IRepository /// 参与状态 /// /// - public Task UpdateParticipationStatus(Participation part, ParticipationStatus status, CancellationToken token = default); -} + public Task UpdateParticipationStatus(Participation part, ParticipationStatus status, + CancellationToken token = default); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IPostRepository.cs b/src/GZCTF/Repositories/Interface/IPostRepository.cs index 9b9dc6043..30b58c5df 100644 --- a/src/GZCTF/Repositories/Interface/IPostRepository.cs +++ b/src/GZCTF/Repositories/Interface/IPostRepository.cs @@ -48,4 +48,4 @@ public interface IPostRepository : IRepository /// /// public Task GetPostByIdFromCache(string id, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/IRepository.cs b/src/GZCTF/Repositories/Interface/IRepository.cs index 245458014..fda77ab6e 100644 --- a/src/GZCTF/Repositories/Interface/IRepository.cs +++ b/src/GZCTF/Repositories/Interface/IRepository.cs @@ -4,9 +4,8 @@ namespace GZCTF.Repositories.Interface; public interface IRepository { - Task BeginTransactionAsync(CancellationToken token = default); - public string ChangeTrackerView { get; } + Task BeginTransactionAsync(CancellationToken token = default); public void Detach(object item); @@ -15,4 +14,4 @@ public interface IRepository public Task CountAsync(CancellationToken token = default); public Task SaveAsync(CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/ISubmissionRepository.cs b/src/GZCTF/Repositories/Interface/ISubmissionRepository.cs index 8e8755314..f31b1d64c 100644 --- a/src/GZCTF/Repositories/Interface/ISubmissionRepository.cs +++ b/src/GZCTF/Repositories/Interface/ISubmissionRepository.cs @@ -11,7 +11,8 @@ public interface ISubmissionRepository : IRepository /// 跳过数量 /// /// - public Task GetSubmissions(Game game, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default); + public Task GetSubmissions(Game game, AnswerResult? type = null, int count = 100, int skip = 0, + CancellationToken token = default); /// /// 获取题目的提交,按时间降序 @@ -22,7 +23,8 @@ public interface ISubmissionRepository : IRepository /// 跳过数量 /// /// - public Task GetSubmissions(Challenge challenge, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default); + public Task GetSubmissions(Challenge challenge, AnswerResult? type = null, int count = 100, + int skip = 0, CancellationToken token = default); /// /// 通过 signalR 发送提交给检查者 @@ -39,7 +41,8 @@ public interface ISubmissionRepository : IRepository /// 跳过数量 /// /// - public Task GetSubmissions(Participation team, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default); + public Task GetSubmissions(Participation team, AnswerResult? type = null, int count = 100, + int skip = 0, CancellationToken token = default); /// /// 添加提交 @@ -65,5 +68,6 @@ public interface ISubmissionRepository : IRepository /// 提交Id /// /// - public Task GetSubmission(int gameId, int challengeId, string userId, int submitId, CancellationToken token = default); -} + public Task GetSubmission(int gameId, int challengeId, string userId, int submitId, + CancellationToken token = default); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/Interface/ITeamRepository.cs b/src/GZCTF/Repositories/Interface/ITeamRepository.cs index f736940fb..124c83f9e 100644 --- a/src/GZCTF/Repositories/Interface/ITeamRepository.cs +++ b/src/GZCTF/Repositories/Interface/ITeamRepository.cs @@ -87,4 +87,4 @@ public interface ITeamRepository : IRepository /// /// 队伍对象 public Task DeleteTeam(Team team, CancellationToken token = default); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/LogRepository.cs b/src/GZCTF/Repositories/LogRepository.cs index f65b0d1db..c275d1acd 100644 --- a/src/GZCTF/Repositories/LogRepository.cs +++ b/src/GZCTF/Repositories/LogRepository.cs @@ -16,4 +16,4 @@ public Task GetLogs(int skip, int count, string? level, Cance return (from log in data select LogMessageModel.FromLogModel(log)).ToArrayAsync(token); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/ParticipationRepository.cs b/src/GZCTF/Repositories/ParticipationRepository.cs index c0e8d98ed..20a9f3bd9 100644 --- a/src/GZCTF/Repositories/ParticipationRepository.cs +++ b/src/GZCTF/Repositories/ParticipationRepository.cs @@ -1,6 +1,6 @@ using GZCTF.Models.Request.Admin; using GZCTF.Repositories.Interface; -using GZCTF.Services; +using GZCTF.Services.Cache; using Microsoft.EntityFrameworkCore; namespace GZCTF.Repositories; @@ -12,14 +12,14 @@ public class ParticipationRepository( { public async Task EnsureInstances(Participation part, Game game, CancellationToken token = default) { - var challenges = await context.Challenges.Where(c => c.Game == game && c.IsEnabled).ToArrayAsync(token); + Challenge[] challenges = await context.Challenges.Where(c => c.Game == game && c.IsEnabled).ToArrayAsync(token); // requery instead of Entry part = await context.Participations.Include(p => p.Challenges).SingleAsync(p => p.Id == part.Id, token); - bool update = false; + var update = false; - foreach (var challenge in challenges) + foreach (Challenge challenge in challenges) update |= part.Challenges.Add(challenge); await SaveAsync(token); @@ -27,38 +27,40 @@ public async Task EnsureInstances(Participation part, Game game, Cancellat return update; } - public Task GetParticipationById(int id, CancellationToken token = default) - => context.Participations.FirstOrDefaultAsync(p => p.Id == id, token); + public Task GetParticipationById(int id, CancellationToken token = default) => + context.Participations.FirstOrDefaultAsync(p => p.Id == id, token); - public Task GetParticipation(Team team, Game game, CancellationToken token = default) - => context.Participations.FirstOrDefaultAsync(e => e.Team == team && e.Game == game, token); + public Task GetParticipation(Team team, Game game, CancellationToken token = default) => + context.Participations.FirstOrDefaultAsync(e => e.Team == team && e.Game == game, token); - public Task GetParticipation(UserInfo user, Game game, CancellationToken token = default) - => context.Participations.FirstOrDefaultAsync(p => p.Members.Any(m => m.Game == game && m.User == user), token); + public Task GetParticipation(UserInfo user, Game game, CancellationToken token = default) => + context.Participations.FirstOrDefaultAsync(p => p.Members.Any(m => m.Game == game && m.User == user), + token); - public Task GetParticipationCount(Game game, CancellationToken token = default) - => context.Participations.Where(p => p.GameId == game.Id).CountAsync(token); + public Task GetParticipationCount(Game game, CancellationToken token = default) => + context.Participations.Where(p => p.GameId == game.Id).CountAsync(token); - public Task GetParticipations(Game game, CancellationToken token = default) - => context.Participations.Where(p => p.GameId == game.Id) + public Task GetParticipations(Game game, CancellationToken token = default) => + context.Participations.Where(p => p.GameId == game.Id) .Include(p => p.Team) .ThenInclude(t => t.Members) .OrderBy(p => p.TeamId).ToArrayAsync(token); - public Task GetWriteups(Game game, CancellationToken token = default) - => context.Participations.Where(p => p.Game == game && p.Writeup != null) - .OrderByDescending(p => p.Writeup!.UploadTimeUTC) - .Select(p => WriteupInfoModel.FromParticipation(p)!) - .ToArrayAsync(token); + public Task GetWriteups(Game game, CancellationToken token = default) => + context.Participations.Where(p => p.Game == game && p.Writeup != null) + .OrderByDescending(p => p.Writeup!.UploadTimeUTC) + .Select(p => WriteupInfoModel.FromParticipation(p)!) + .ToArrayAsync(token); - public Task CheckRepeatParticipation(UserInfo user, Game game, CancellationToken token = default) - => context.UserParticipations.Include(p => p.Participation) + public Task CheckRepeatParticipation(UserInfo user, Game game, CancellationToken token = default) => + context.UserParticipations.Include(p => p.Participation) .AnyAsync(p => p.User == user && p.Game == game - && p.Participation.Status != ParticipationStatus.Rejected, token); + && p.Participation.Status != ParticipationStatus.Rejected, token); - public async Task UpdateParticipationStatus(Participation part, ParticipationStatus status, CancellationToken token = default) + public async Task UpdateParticipationStatus(Participation part, ParticipationStatus status, + CancellationToken token = default) { - var oldStatus = part.Status; + ParticipationStatus oldStatus = part.Status; part.Status = status; if (status == ParticipationStatus.Accepted) @@ -83,18 +85,18 @@ public async Task UpdateParticipationStatus(Participation part, ParticipationSta await cacheHelper.FlushScoreboardCache(part.GameId, token); } - public Task GetParticipationsByIds(IEnumerable ids, CancellationToken token = default) - => context.Participations.Where(p => ids.Contains(p.Id)) + public Task GetParticipationsByIds(IEnumerable ids, CancellationToken token = default) => + context.Participations.Where(p => ids.Contains(p.Id)) .Include(p => p.Team) .ToArrayAsync(token); - public async Task RemoveUserParticipations(UserInfo user, Game game, CancellationToken token = default) - => context.RemoveRange(await context.UserParticipations - .Where(p => p.User == user && p.Game == game).ToArrayAsync(token)); + public async Task RemoveUserParticipations(UserInfo user, Game game, CancellationToken token = default) => + context.RemoveRange(await context.UserParticipations + .Where(p => p.User == user && p.Game == game).ToArrayAsync(token)); - public async Task RemoveUserParticipations(UserInfo user, Team team, CancellationToken token = default) - => context.RemoveRange(await context.UserParticipations - .Where(p => p.User == user && p.Team == team).ToArrayAsync(token)); + public async Task RemoveUserParticipations(UserInfo user, Team team, CancellationToken token = default) => + context.RemoveRange(await context.UserParticipations + .Where(p => p.User == user && p.Team == team).ToArrayAsync(token)); public async Task RemoveParticipation(Participation part, CancellationToken token = default) { @@ -110,4 +112,4 @@ public Task DeleteParticipationWriteUp(Participation part, CancellationToken tok return fileRepository.DeleteFile(part.Writeup, token); return Task.CompletedTask; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/PostRepository.cs b/src/GZCTF/Repositories/PostRepository.cs index 6ad6b5b27..3f3f0908f 100644 --- a/src/GZCTF/Repositories/PostRepository.cs +++ b/src/GZCTF/Repositories/PostRepository.cs @@ -1,6 +1,6 @@ using GZCTF.Extensions; using GZCTF.Repositories.Interface; -using GZCTF.Utils; +using GZCTF.Services.Cache; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; @@ -23,18 +23,17 @@ public async Task CreatePost(Post post, CancellationToken token = default) return post; } - public Task GetPostById(string id, CancellationToken token = default) - => context.Posts.FirstOrDefaultAsync(p => p.Id == id, token); + public Task GetPostById(string id, CancellationToken token = default) => context.Posts.FirstOrDefaultAsync(p => p.Id == id, token); - public async Task GetPostByIdFromCache(string id, CancellationToken token = default) - => (await GetPosts(token)).FirstOrDefault(p => p.Id == id); + public async Task GetPostByIdFromCache(string id, CancellationToken token = default) => + (await GetPosts(token)).FirstOrDefault(p => p.Id == id); - public Task GetPosts(CancellationToken token = default) - => cache.GetOrCreateAsync(logger, CacheKey.Posts, entry => + public Task GetPosts(CancellationToken token = default) => + cache.GetOrCreateAsync(logger, CacheKey.Posts, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12); return context.Posts.AsNoTracking().OrderByDescending(n => n.IsPinned) - .ThenByDescending(n => n.UpdateTimeUTC).ToArrayAsync(token); + .ThenByDescending(n => n.UpdateTimeUTC).ToArrayAsync(token); }, token); public async Task RemovePost(Post post, CancellationToken token = default) @@ -52,4 +51,4 @@ public async Task UpdatePost(Post post, CancellationToken token = default) cache.Remove(CacheKey.Posts); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/RepositoryBase.cs b/src/GZCTF/Repositories/RepositoryBase.cs index da8a8daf5..f6dac0401 100644 --- a/src/GZCTF/Repositories/RepositoryBase.cs +++ b/src/GZCTF/Repositories/RepositoryBase.cs @@ -1,5 +1,6 @@ using GZCTF.Repositories.Interface; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Storage; namespace GZCTF.Repositories; @@ -8,16 +9,14 @@ public class RepositoryBase(AppDbContext context) : IRepository { protected readonly AppDbContext context = context; - public Task BeginTransactionAsync(CancellationToken token = default) - => context.Database.BeginTransactionAsync(token); + public Task BeginTransactionAsync(CancellationToken token = default) => context.Database.BeginTransactionAsync(token); public string ChangeTrackerView => context.ChangeTracker.DebugView.LongView; public async Task SaveAsync(CancellationToken token = default) { - bool saved = false; + var saved = false; while (!saved) - { try { await context.SaveChangesAsync(token); @@ -26,22 +25,14 @@ public async Task SaveAsync(CancellationToken token = default) catch (DbUpdateConcurrencyException ex) { // FIXME: detect change - foreach (var entry in ex.Entries) + foreach (EntityEntry entry in ex.Entries) entry.Reload(); } - catch - { - throw; - } - } } public void Detach(object item) => context.Entry(item).State = EntityState.Detached; public void Add(object item) => context.Add(item); - public virtual Task CountAsync(CancellationToken token = default) - { - throw new NotImplementedException(); - } -} + public virtual Task CountAsync(CancellationToken token = default) => throw new NotImplementedException(); +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/SubmissionRepository.cs b/src/GZCTF/Repositories/SubmissionRepository.cs index 4c2ec57b6..9d88661cb 100644 --- a/src/GZCTF/Repositories/SubmissionRepository.cs +++ b/src/GZCTF/Repositories/SubmissionRepository.cs @@ -9,7 +9,7 @@ namespace GZCTF.Repositories; public class SubmissionRepository : RepositoryBase, ISubmissionRepository { - private readonly IHubContext _hubContext; + readonly IHubContext _hubContext; public SubmissionRepository(IHubContext hub, AppDbContext context) : base(context) @@ -25,32 +25,38 @@ public async Task AddSubmission(Submission submission, CancellationT return submission; } - public Task GetSubmission(int gameId, int challengeId, string userId, int submitId, CancellationToken token = default) - => context.Submissions.Where(s => s.Id == submitId && s.UserId == userId && s.GameId == gameId && s.ChallengeId == challengeId) + public Task GetSubmission(int gameId, int challengeId, string userId, int submitId, + CancellationToken token = default) => + context.Submissions.Where(s => + s.Id == submitId && s.UserId == userId && s.GameId == gameId && s.ChallengeId == challengeId) .SingleOrDefaultAsync(token); - public Task GetUncheckedFlags(CancellationToken token = default) - => context.Submissions.Where(s => s.Status == AnswerResult.FlagSubmitted) + public Task GetUncheckedFlags(CancellationToken token = default) => + context.Submissions.Where(s => s.Status == AnswerResult.FlagSubmitted) .AsNoTracking().Include(e => e.Game).ToArrayAsync(token); - private IQueryable GetSubmissionsByType(AnswerResult? type = null) + public Task GetSubmissions(Game game, AnswerResult? type = null, int count = 100, int skip = 0, + CancellationToken token = default) => + GetSubmissionsByType(type).Where(s => s.Game == game).TakeAllIfZero(count, skip).ToArrayAsync(token); + + public Task GetSubmissions(Challenge challenge, AnswerResult? type = null, int count = 100, + int skip = 0, CancellationToken token = default) => + GetSubmissionsByType(type).Where(s => s.Challenge == challenge).TakeAllIfZero(count, skip) + .ToArrayAsync(token); + + public Task GetSubmissions(Participation team, AnswerResult? type = null, int count = 100, + int skip = 0, CancellationToken token = default) => + GetSubmissionsByType(type).Where(s => s.TeamId == team.TeamId).TakeAllIfZero(count, skip) + .ToArrayAsync(token); + + public Task SendSubmission(Submission submission) => _hubContext.Clients.Group($"Game_{submission.GameId}").ReceivedSubmissions(submission); + + IQueryable GetSubmissionsByType(AnswerResult? type = null) { - var subs = type is not null + IQueryable subs = type is not null ? context.Submissions.Where(s => s.Status == type.Value) : context.Submissions; return subs.OrderByDescending(s => s.SubmitTimeUTC); } - - public Task GetSubmissions(Game game, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default) - => GetSubmissionsByType(type).Where(s => s.Game == game).TakeAllIfZero(count, skip).ToArrayAsync(token); - - public Task GetSubmissions(Challenge challenge, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default) - => GetSubmissionsByType(type).Where(s => s.Challenge == challenge).TakeAllIfZero(count, skip).ToArrayAsync(token); - - public Task GetSubmissions(Participation team, AnswerResult? type = null, int count = 100, int skip = 0, CancellationToken token = default) - => GetSubmissionsByType(type).Where(s => s.TeamId == team.TeamId).TakeAllIfZero(count, skip).ToArrayAsync(token); - - public Task SendSubmission(Submission submission) - => _hubContext.Clients.Group($"Game_{submission.GameId}").ReceivedSubmissions(submission); -} +} \ No newline at end of file diff --git a/src/GZCTF/Repositories/TeamRepository.cs b/src/GZCTF/Repositories/TeamRepository.cs index faac01ecb..8eff5f4ee 100644 --- a/src/GZCTF/Repositories/TeamRepository.cs +++ b/src/GZCTF/Repositories/TeamRepository.cs @@ -12,7 +12,7 @@ public TeamRepository(AppDbContext context) : base(context) public async Task AnyActiveGame(Team team, CancellationToken token = default) { - var current = DateTimeOffset.UtcNow; + DateTimeOffset current = DateTimeOffset.UtcNow; var result = await context.Participations .Where(p => p.Team == team && p.Game.EndTimeUTC > current) .AnyAsync(token); @@ -28,8 +28,7 @@ public async Task AnyActiveGame(Team team, CancellationToken token = defau public override Task CountAsync(CancellationToken token = default) => context.Teams.CountAsync(token); - public Task CheckIsCaptain(UserInfo user, CancellationToken token = default) - => context.Teams.AnyAsync(t => t.Captain == user, token); + public Task CheckIsCaptain(UserInfo user, CancellationToken token = default) => context.Teams.AnyAsync(t => t.Captain == user, token); public async Task CreateTeam(TeamUpdateModel model, UserInfo user, CancellationToken token = default) { @@ -52,19 +51,19 @@ public Task DeleteTeam(Team team, CancellationToken token = default) return SaveAsync(token); } - public Task GetTeamById(int id, CancellationToken token = default) - => context.Teams.Include(e => e.Members).FirstOrDefaultAsync(t => t.Id == id, token); + public Task GetTeamById(int id, CancellationToken token = default) => + context.Teams.Include(e => e.Members).FirstOrDefaultAsync(t => t.Id == id, token); - public Task GetTeams(int count = 100, int skip = 0, CancellationToken token = default) - => context.Teams.Include(t => t.Members).OrderBy(t => t.Id) + public Task GetTeams(int count = 100, int skip = 0, CancellationToken token = default) => + context.Teams.Include(t => t.Members).OrderBy(t => t.Id) .Skip(skip).Take(count).ToArrayAsync(token); - public Task GetUserTeams(UserInfo user, CancellationToken token = default) - => context.Teams.Where(t => t.Members.Any(u => u.Id == user.Id)) + public Task GetUserTeams(UserInfo user, CancellationToken token = default) => + context.Teams.Where(t => t.Members.Any(u => u.Id == user.Id)) .Include(t => t.Members).ToArrayAsync(token); - public Task SearchTeams(string hint, CancellationToken token = default) - => context.Teams.Include(t => t.Members).Where(item => EF.Functions.Like(item.Name, $"%{hint}%")) + public Task SearchTeams(string hint, CancellationToken token = default) => + context.Teams.Include(t => t.Members).Where(item => EF.Functions.Like(item.Name, $"%{hint}%")) .OrderBy(t => t.Id).Take(30).ToArrayAsync(token); public Task Transfer(Team team, UserInfo user, CancellationToken token = default) @@ -75,7 +74,7 @@ public Task Transfer(Team team, UserInfo user, CancellationToken token = default public async Task VerifyToken(int id, string inviteCode, CancellationToken token = default) { - var team = await context.Teams.FirstOrDefaultAsync(t => t.Id == id, token); + Team? team = await context.Teams.FirstOrDefaultAsync(t => t.Id == id, token); return team is not null && team.InviteCode == inviteCode; } -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Assets/URLEmailTemplate.html b/src/GZCTF/Services/Assets/URLEmailTemplate.html index 4c4eb1863..d559e955f 100644 --- a/src/GZCTF/Services/Assets/URLEmailTemplate.html +++ b/src/GZCTF/Services/Assets/URLEmailTemplate.html @@ -1,15 +1,15 @@ - + -
+

{title}

你好,{userName}!

{information}

- {title} border-radius: 7px; margin: 10px auto; " - > - {btnmsg} - + > + {btnmsg} +

-

- 如果以上按钮无效,请复制此链接到浏览器访问:
{url} +

+ 如果以上按钮无效,请复制此链接到浏览器访问:
{url} -

-

如果你没有进行相关操作,请忽略此封邮件。

+

+

如果你没有进行相关操作,请忽略此封邮件。

GZCTF @ {nowtime}

-
+
diff --git a/src/GZCTF/Services/Cache/CacheHelper.cs b/src/GZCTF/Services/Cache/CacheHelper.cs index 85528d27a..b25e657e7 100644 --- a/src/GZCTF/Services/Cache/CacheHelper.cs +++ b/src/GZCTF/Services/Cache/CacheHelper.cs @@ -1,65 +1,61 @@ using System.Threading.Channels; using GZCTF.Repositories; -namespace GZCTF.Services +namespace GZCTF.Services.Cache; + +public class CacheHelper(ChannelWriter channelWriter) { - public class CacheHelper(ChannelWriter channelWriter) - { - public async Task FlushScoreboardCache(int gameId, CancellationToken token) - => await channelWriter.WriteAsync(ScoreboardCacheHandler.MakeCacheRequest(gameId), token); - } + public async Task FlushScoreboardCache(int gameId, CancellationToken token) => + await channelWriter.WriteAsync(ScoreboardCacheHandler.MakeCacheRequest(gameId), token); } -namespace GZCTF.Utils +/// +/// 缓存标识 +/// +public static class CacheKey { /// - /// 缓存标识 + /// 积分榜缓存根标识 /// - public static class CacheKey - { - /// - /// 缓存更新锁 - /// - public static string UpdateLock(string key) => $"_CacheUpdateLock_{key}"; + public const string ScoreBoardBase = "_ScoreBoard"; - /// - /// 积分榜缓存 - /// - public static string ScoreBoard(int id) => $"_ScoreBoard_{id}"; + /// + /// 比赛基础信息缓存 + /// + public const string BasicGameInfo = "_BasicGameInfo"; - /// - /// 积分榜缓存 - /// - public static string ScoreBoard(string id) => $"_ScoreBoard_{id}"; + /// + /// 文章 + /// + public const string Posts = "_Posts"; - /// - /// 积分榜缓存根标识 - /// - public const string ScoreBoardBase = "_ScoreBoard"; + /// + /// 缓存更新锁 + /// + public static string UpdateLock(string key) => $"_CacheUpdateLock_{key}"; - /// - /// 比赛通知缓存 - /// - public static string GameNotice(int id) => $"_GameNotice_{id}"; + /// + /// 积分榜缓存 + /// + public static string ScoreBoard(int id) => $"_ScoreBoard_{id}"; - /// - /// 比赛通知缓存 - /// - public static string GameNotice(string id) => $"_ScoreBoard_{id}"; + /// + /// 积分榜缓存 + /// + public static string ScoreBoard(string id) => $"_ScoreBoard_{id}"; - /// - /// 比赛基础信息缓存 - /// - public const string BasicGameInfo = "_BasicGameInfo"; + /// + /// 比赛通知缓存 + /// + public static string GameNotice(int id) => $"_GameNotice_{id}"; - /// - /// 文章 - /// - public const string Posts = "_Posts"; + /// + /// 比赛通知缓存 + /// + public static string GameNotice(string id) => $"_ScoreBoard_{id}"; - /// - /// 容器连接数缓存 - /// - public static string ConnectionCount(string id) => $"_Container_Conn_{id}"; - } -} + /// + /// 容器连接数缓存 + /// + public static string ConnectionCount(string id) => $"_Container_Conn_{id}"; +} \ No newline at end of file diff --git a/src/GZCTF/Services/Cache/CacheMaker.cs b/src/GZCTF/Services/Cache/CacheMaker.cs index 9d4d26ffc..34fdf8735 100644 --- a/src/GZCTF/Services/Cache/CacheMaker.cs +++ b/src/GZCTF/Services/Cache/CacheMaker.cs @@ -1,9 +1,8 @@ using System.Threading.Channels; using GZCTF.Repositories; -using GZCTF.Utils; using Microsoft.Extensions.Caching.Distributed; -namespace GZCTF.Services; +namespace GZCTF.Services.Cache; /// /// 缓存更新请求 @@ -30,19 +29,42 @@ public class CacheMaker( ChannelReader channelReader, IServiceScopeFactory serviceScopeFactory) : IHostedService { - private CancellationTokenSource _tokenSource { get; set; } = new CancellationTokenSource(); - private readonly Dictionary _cacheHandlers = new(); + readonly Dictionary _cacheHandlers = new(); + CancellationTokenSource _tokenSource { get; set; } = new(); - public void AddCacheRequestHandler(string key) where T : ICacheRequestHandler, new() - => _cacheHandlers.Add(key, new T()); + public Task StartAsync(CancellationToken token) + { + _tokenSource = new CancellationTokenSource(); + + #region Add Handlers + + AddCacheRequestHandler(CacheKey.ScoreBoardBase); - private async Task Maker(CancellationToken token = default) + #endregion + + _ = Maker(_tokenSource.Token); + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken token) + { + _tokenSource.Cancel(); + + logger.SystemLog("缓存更新已停用", TaskStatus.Success, LogLevel.Debug); + + return Task.CompletedTask; + } + + public void AddCacheRequestHandler(string key) where T : ICacheRequestHandler, new() => _cacheHandlers.Add(key, new T()); + + async Task Maker(CancellationToken token = default) { - logger.SystemLog($"缓存更新线程已启动", TaskStatus.Pending, LogLevel.Debug); + logger.SystemLog("缓存更新线程已启动", TaskStatus.Pending, LogLevel.Debug); try { - await foreach (var item in channelReader.ReadAllAsync(token)) + await foreach (CacheRequest item in channelReader.ReadAllAsync(token)) { if (!_cacheHandlers.ContainsKey(item.Key)) { @@ -50,7 +72,7 @@ private async Task Maker(CancellationToken token = default) continue; } - var handler = _cacheHandlers[item.Key]; + ICacheRequestHandler handler = _cacheHandlers[item.Key]; var key = handler.CacheKey(item); if (key is null) @@ -68,14 +90,13 @@ private async Task Maker(CancellationToken token = default) continue; } - await using var scope = serviceScopeFactory.CreateAsyncScope(); + await using AsyncServiceScope scope = serviceScopeFactory.CreateAsyncScope(); try { - await cache.SetAsync(updateLock, [], new DistributedCacheEntryOptions - { - AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60) - }, token); + await cache.SetAsync(updateLock, Array.Empty(), + new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60) }, + token); var bytes = await handler.Handler(scope, item, token); @@ -103,35 +124,11 @@ private async Task Maker(CancellationToken token = default) } catch (OperationCanceledException) { - logger.SystemLog($"任务取消,缓存更新线程将退出", TaskStatus.Exit, LogLevel.Debug); + logger.SystemLog("任务取消,缓存更新线程将退出", TaskStatus.Exit, LogLevel.Debug); } finally { - logger.SystemLog($"缓存更新线程已退出", TaskStatus.Exit, LogLevel.Debug); + logger.SystemLog("缓存更新线程已退出", TaskStatus.Exit, LogLevel.Debug); } } - - public Task StartAsync(CancellationToken token) - { - _tokenSource = new CancellationTokenSource(); - - #region Add Handlers - - AddCacheRequestHandler(CacheKey.ScoreBoardBase); - - #endregion - - _ = Maker(_tokenSource.Token); - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken token) - { - _tokenSource.Cancel(); - - logger.SystemLog("缓存更新已停用", TaskStatus.Success, LogLevel.Debug); - - return Task.CompletedTask; - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/ConfigService.cs b/src/GZCTF/Services/ConfigService.cs index 4b7409949..69a265286 100644 --- a/src/GZCTF/Services/ConfigService.cs +++ b/src/GZCTF/Services/ConfigService.cs @@ -1,7 +1,6 @@ using System.ComponentModel; -using GZCTF.Models.Data; +using System.Reflection; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.EntityFrameworkCore; namespace GZCTF.Services; @@ -10,9 +9,15 @@ public class ConfigService(AppDbContext context, ILogger logger, IConfiguration configuration) : IConfigService { - private readonly IConfigurationRoot? _configuration = configuration as IConfigurationRoot; + readonly IConfigurationRoot? _configuration = configuration as IConfigurationRoot; - private static void MapConfigsInternal(string key, HashSet configs, Type? type, object? value) + public Task SaveConfig(Type type, object? value, CancellationToken token = default) => SaveConfigInternal(GetConfigs(type, value), token); + + public Task SaveConfig(T config, CancellationToken token = default) where T : class => SaveConfigInternal(GetConfigs(config), token); + + public void ReloadConfig() => _configuration?.Reload(); + + static void MapConfigsInternal(string key, HashSet configs, Type? type, object? value) { if (value is null || type is null) return; @@ -22,21 +27,17 @@ private static void MapConfigsInternal(string key, HashSet configs, Type TypeConverter converter = TypeDescriptor.GetConverter(type); if (type == typeof(string) || type.IsValueType) - { configs.Add(new(key, converter.ConvertToString(value) ?? string.Empty)); - } else if (type.IsClass) - { - foreach (var item in type.GetProperties()) + foreach (PropertyInfo item in type.GetProperties()) MapConfigsInternal($"{key}:{item.Name}", configs, item.PropertyType, item.GetValue(value)); - } } - public static HashSet GetConfigs(Type type, object? value) + static HashSet GetConfigs(Type type, object? value) { HashSet configs = new(); - foreach (var item in type.GetProperties()) + foreach (PropertyInfo item in type.GetProperties()) MapConfigsInternal($"{type.Name}:{item.Name}", configs, item.PropertyType, item.GetValue(value)); return configs; @@ -45,26 +46,19 @@ public static HashSet GetConfigs(Type type, object? value) public static HashSet GetConfigs(T config) where T : class { HashSet configs = new(); - var type = typeof(T); + Type type = typeof(T); - foreach (var item in type.GetProperties()) + foreach (PropertyInfo item in type.GetProperties()) MapConfigsInternal($"{type.Name}:{item.Name}", configs, item.PropertyType, item.GetValue(config)); return configs; } - public Task SaveConfig(Type type, object? value, CancellationToken token = default) - => SaveConfigInternal(GetConfigs(type, value), token); - - public Task SaveConfig(T config, CancellationToken token = default) where T : class - => SaveConfigInternal(GetConfigs(config), token); - - private async Task SaveConfigInternal(HashSet configs, CancellationToken token = default) + async Task SaveConfigInternal(HashSet configs, CancellationToken token = default) { - var dbConfigs = await context.Configs.ToDictionaryAsync(c => c.ConfigKey, c => c, token); - foreach (var conf in configs) - { - if (dbConfigs.TryGetValue(conf.ConfigKey, out var dbConf)) + Dictionary dbConfigs = await context.Configs.ToDictionaryAsync(c => c.ConfigKey, c => c, token); + foreach (Config conf in configs) + if (dbConfigs.TryGetValue(conf.ConfigKey, out Config? dbConf)) { if (dbConf.Value != conf.Value) { @@ -77,24 +71,20 @@ private async Task SaveConfigInternal(HashSet configs, CancellationToken logger.SystemLog($"添加全局设置:{conf.ConfigKey} => {conf.Value}", TaskStatus.Success, LogLevel.Debug); await context.Configs.AddAsync(conf, token); } - } await context.SaveChangesAsync(token); _configuration?.Reload(); } - private static bool IsArrayLikeInterface(Type type) + static bool IsArrayLikeInterface(Type type) { - if (!type.IsInterface || !type.IsConstructedGenericType) - { return false; } + if (!type.IsInterface || !type.IsConstructedGenericType) return false; Type genericTypeDefinition = type.GetGenericTypeDefinition(); return genericTypeDefinition == typeof(IEnumerable<>) - || genericTypeDefinition == typeof(ICollection<>) - || genericTypeDefinition == typeof(IList<>) - || genericTypeDefinition == typeof(IDictionary<,>) - || genericTypeDefinition == typeof(ISet<>); + || genericTypeDefinition == typeof(ICollection<>) + || genericTypeDefinition == typeof(IList<>) + || genericTypeDefinition == typeof(IDictionary<,>) + || genericTypeDefinition == typeof(ISet<>); } - - public void ReloadConfig() => _configuration?.Reload(); -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/ContainerServiceExtension.cs b/src/GZCTF/Services/Container/ContainerServiceExtension.cs index 3b07b4780..018a3dc3f 100644 --- a/src/GZCTF/Services/Container/ContainerServiceExtension.cs +++ b/src/GZCTF/Services/Container/ContainerServiceExtension.cs @@ -1,9 +1,11 @@ using Docker.DotNet; using GZCTF.Models.Internal; +using GZCTF.Services.Container.Manager; +using GZCTF.Services.Container.Provider; using GZCTF.Services.Interface; using k8s; -namespace GZCTF.Services; +namespace GZCTF.Services.Container; public class ContainerProviderMetadata { @@ -25,23 +27,27 @@ public class ContainerProviderMetadata public static class ContainerServiceExtension { - internal static IServiceCollection AddContainerService(this IServiceCollection services, ConfigurationManager configuration) + internal static IServiceCollection AddContainerService(this IServiceCollection services, + ConfigurationManager configuration) { - var config = configuration.GetSection(nameof(ContainerProvider)).Get() ?? new(); + ContainerProvider config = configuration.GetSection(nameof(ContainerProvider)).Get() ?? + new(); // FIXME: custom IPortMapper return services.AddProvider(config).AddManager(config); } - private static IServiceCollection AddProvider(this IServiceCollection services, ContainerProvider config) - => config.Type switch + static IServiceCollection AddProvider(this IServiceCollection services, ContainerProvider config) => + config.Type switch { - ContainerProviderType.Docker => services.AddSingleton, DockerProvider>(), - ContainerProviderType.Kubernetes => services.AddSingleton, K8sProvider>(), + ContainerProviderType.Docker => services + .AddSingleton, DockerProvider>(), + ContainerProviderType.Kubernetes => services + .AddSingleton, K8sProvider>(), _ => throw new NotImplementedException() }; - private static IServiceCollection AddManager(this IServiceCollection services, ContainerProvider config) + static IServiceCollection AddManager(this IServiceCollection services, ContainerProvider config) { if (config.Type == ContainerProviderType.Kubernetes) return services.AddSingleton(); @@ -51,4 +57,4 @@ private static IServiceCollection AddManager(this IServiceCollection services, C return services.AddSingleton(); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/Manager/DockerManager.cs b/src/GZCTF/Services/Container/Manager/DockerManager.cs index 2dec3a07f..cae3bb272 100644 --- a/src/GZCTF/Services/Container/Manager/DockerManager.cs +++ b/src/GZCTF/Services/Container/Manager/DockerManager.cs @@ -2,30 +2,29 @@ using Docker.DotNet; using Docker.DotNet.Models; using GZCTF.Models.Internal; +using GZCTF.Services.Container.Provider; using GZCTF.Services.Interface; -using GZCTF.Utils; +using ContainerStatus = GZCTF.Utils.ContainerStatus; -namespace GZCTF.Services; +namespace GZCTF.Services.Container.Manager; public class DockerManager : IContainerManager { - private readonly ILogger _logger; - private readonly IContainerProvider _provider; - private readonly DockerMetadata _meta; - private readonly DockerClient _client; + readonly DockerClient _client; + readonly ILogger _logger; + readonly DockerMetadata _meta; public DockerManager(IContainerProvider provider, ILogger logger) { _logger = logger; - _provider = provider; - _meta = _provider.GetMetadata(); - _client = _provider.GetProvider(); + _meta = provider.GetMetadata(); + _client = provider.GetProvider(); - logger.SystemLog($"容器管理模式:Docker 单实例容器控制", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog("容器管理模式:Docker 单实例容器控制", TaskStatus.Success, LogLevel.Debug); } - public async Task DestroyContainerAsync(Container container, CancellationToken token = default) + public async Task DestroyContainerAsync(Models.Data.Container container, CancellationToken token = default) { try { @@ -43,8 +42,10 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t } else { - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.StatusCode}", TaskStatus.Failed, LogLevel.Warning); - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.ResponseBody}", TaskStatus.Failed, LogLevel.Error); + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.StatusCode}", TaskStatus.Failed, + LogLevel.Warning); + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.ResponseBody}", TaskStatus.Failed, + LogLevel.Error); return; } } @@ -57,31 +58,14 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t container.Status = ContainerStatus.Destroyed; } - private CreateContainerParameters GetCreateContainerParameters(ContainerConfig config) - => new() - { - Image = config.Image, - Labels = new Dictionary { ["TeamId"] = config.TeamId, ["UserId"] = config.UserId }, - Name = DockerMetadata.GetName(config), - Env = config.Flag is null ? Array.Empty() : new string[] { $"GZCTF_FLAG={config.Flag}" }, - HostConfig = new() - { - Memory = config.MemoryLimit * 1024 * 1024, - CPUPercent = config.CPUCount * 10, - NetworkMode = _meta.Config.ChallengeNetwork, - }, - }; - - public async Task CreateContainerAsync(ContainerConfig config, CancellationToken token = default) + public async Task CreateContainerAsync(ContainerConfig config, + CancellationToken token = default) { - var parameters = GetCreateContainerParameters(config); + CreateContainerParameters parameters = GetCreateContainerParameters(config); if (_meta.ExposePort) { - parameters.ExposedPorts = new Dictionary() - { - [config.ExposedPort.ToString()] = new EmptyStruct() - }; + parameters.ExposedPorts = new Dictionary { [config.ExposedPort.ToString()] = new() }; parameters.HostConfig.PublishAllPorts = true; } @@ -94,13 +78,11 @@ private CreateContainerParameters GetCreateContainerParameters(ContainerConfig c { _logger.SystemLog($"拉取容器镜像 {config.Image}", TaskStatus.Pending, LogLevel.Information); - await _client.Images.CreateImageAsync(new() - { - FromImage = config.Image - }, _meta.Auth, new Progress(msg => - { - Console.WriteLine($"{msg.Status}|{msg.ProgressMessage}|{msg.ErrorMessage}"); - }), token); + await _client.Images.CreateImageAsync(new() { FromImage = config.Image }, _meta.Auth, + new Progress(msg => + { + Console.WriteLine($"{msg.Status}|{msg.ProgressMessage}|{msg.ErrorMessage}"); + }), token); } catch (Exception e) { @@ -118,11 +100,7 @@ await _client.Images.CreateImageAsync(new() return null; } - var container = new Container() - { - ContainerId = containerRes.ID, - Image = config.Image, - }; + var container = new Models.Data.Container { ContainerId = containerRes.ID, Image = config.Image }; var retry = 0; bool started; @@ -133,21 +111,28 @@ await _client.Images.CreateImageAsync(new() retry++; if (retry == 3) { - _logger.SystemLog($"启动容器实例 {container.ContainerId[..12]} ({config.Image.Split("/").LastOrDefault()}) 失败", TaskStatus.Failed, LogLevel.Warning); + _logger.SystemLog( + $"启动容器实例 {container.ContainerId[..12]} ({config.Image.Split("/").LastOrDefault()}) 失败", + TaskStatus.Failed, LogLevel.Warning); return null; } + if (!started) await Task.Delay(500, token); } while (!started); - var info = await _client.Containers.InspectContainerAsync(container.ContainerId, token); + ContainerInspectResponse? info = await _client.Containers.InspectContainerAsync(container.ContainerId, token); - container.Status = (info.State.Dead || info.State.OOMKilled || info.State.Restarting) ? ContainerStatus.Destroyed : - info.State.Running ? ContainerStatus.Running : ContainerStatus.Pending; + container.Status = info.State.Dead || info.State.OOMKilled || info.State.Restarting + ? ContainerStatus.Destroyed + : info.State.Running + ? ContainerStatus.Running + : ContainerStatus.Pending; if (container.Status != ContainerStatus.Running) { - _logger.SystemLog($"创建 {config.Image.Split("/").LastOrDefault()} 实例遇到错误:{info.State.Error}", TaskStatus.Failed, LogLevel.Warning); + _logger.SystemLog($"创建 {config.Image.Split("/").LastOrDefault()} 实例遇到错误:{info.State.Error}", + TaskStatus.Failed, LogLevel.Warning); return null; } @@ -160,12 +145,12 @@ await _client.Images.CreateImageAsync(new() if (_meta.ExposePort) { var port = info.NetworkSettings.Ports - .FirstOrDefault(p => - p.Key.StartsWith(config.ExposedPort.ToString()) - ).Value.First().HostPort; + .FirstOrDefault(p => + p.Key.StartsWith(config.ExposedPort.ToString()) + ).Value.First().HostPort; - if (int.TryParse(port, out var numport)) - container.PublicPort = numport; + if (int.TryParse(port, out var numPort)) + container.PublicPort = numPort; else _logger.SystemLog($"无法转换端口号:{port},这是非预期的行为", TaskStatus.Failed, LogLevel.Warning); @@ -175,4 +160,17 @@ await _client.Images.CreateImageAsync(new() return container; } -} + + CreateContainerParameters GetCreateContainerParameters(ContainerConfig config) => + new() + { + Image = config.Image, + Labels = new Dictionary { ["TeamId"] = config.TeamId, ["UserId"] = config.UserId }, + Name = DockerMetadata.GetName(config), + Env = config.Flag is null ? Array.Empty() : new[] { $"GZCTF_FLAG={config.Flag}" }, + HostConfig = new() + { + Memory = config.MemoryLimit * 1024 * 1024, CPUPercent = config.CPUCount * 10, NetworkMode = _meta.Config.ChallengeNetwork + } + }; +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/Manager/K8sManager.cs b/src/GZCTF/Services/Container/Manager/K8sManager.cs index 16955b300..8bd76ec57 100644 --- a/src/GZCTF/Services/Container/Manager/K8sManager.cs +++ b/src/GZCTF/Services/Container/Manager/K8sManager.cs @@ -1,35 +1,36 @@ +using System.Diagnostics.CodeAnalysis; using System.Net; using GZCTF.Models.Internal; +using GZCTF.Services.Container.Provider; using GZCTF.Services.Interface; -using GZCTF.Utils; using k8s; using k8s.Autorest; using k8s.Models; -namespace GZCTF.Services; +namespace GZCTF.Services.Container.Manager; +[SuppressMessage("ReSharper", "InconsistentNaming")] public class K8sManager : IContainerManager { - private readonly ILogger _logger; - private readonly IContainerProvider _provider; - private readonly K8sMetadata _meta; - private readonly Kubernetes _client; + readonly Kubernetes _client; + readonly ILogger _logger; + readonly K8sMetadata _meta; public K8sManager(IContainerProvider provider, ILogger logger) { _logger = logger; - _provider = provider; - _meta = _provider.GetMetadata(); - _client = _provider.GetProvider(); + _meta = provider.GetMetadata(); + _client = provider.GetProvider(); - logger.SystemLog($"容器管理模式:K8s 集群 Pod 容器控制", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog("容器管理模式:K8s 集群 Pod 容器控制", TaskStatus.Success, LogLevel.Debug); } - public async Task CreateContainerAsync(ContainerConfig config, CancellationToken token = default) + public async Task CreateContainerAsync(ContainerConfig config, + CancellationToken token = default) { var imageName = config.Image.Split("/").LastOrDefault()?.Split(":").FirstOrDefault(); - var _authSecretName = _meta.AuthSecretName; - var _options = _meta.Config; + var authSecretName = _meta.AuthSecretName; + K8sConfig options = _meta.Config; if (imageName is null) { @@ -41,54 +42,49 @@ public K8sManager(IContainerProvider provider, ILogger< var pod = new V1Pod("v1", "Pod") { - Metadata = new V1ObjectMeta() + Metadata = new V1ObjectMeta { Name = name, - NamespaceProperty = _options.Namespace, - Labels = new Dictionary() + NamespaceProperty = options.Namespace, + Labels = new Dictionary { - ["ctf.gzti.me/ResourceId"] = name, - ["ctf.gzti.me/TeamId"] = config.TeamId, - ["ctf.gzti.me/UserId"] = config.UserId + ["ctf.gzti.me/ResourceId"] = name, ["ctf.gzti.me/TeamId"] = config.TeamId, ["ctf.gzti.me/UserId"] = config.UserId } }, - Spec = new V1PodSpec() + Spec = new V1PodSpec { - ImagePullSecrets = _authSecretName is null ? - Array.Empty() : - new List() { new() { Name = _authSecretName } }, + ImagePullSecrets = + authSecretName is null + ? Array.Empty() + : new List { new() { Name = authSecretName } }, DnsPolicy = "None", DnsConfig = new() { // FIXME: remove nullable when JsonObjectCreationHandling release - Nameservers = _options.DNS ?? new[] { "8.8.8.8", "223.5.5.5", "114.114.114.114" }, + Nameservers = options.DNS ?? new[] { "8.8.8.8", "223.5.5.5", "114.114.114.114" } }, EnableServiceLinks = false, Containers = new[] { - new V1Container() + new V1Container { Name = name, Image = config.Image, ImagePullPolicy = "Always", - Env = config.Flag is null ? new List() : new[] - { - new V1EnvVar("GZCTF_FLAG", config.Flag) - }, + Env = + config.Flag is null + ? new List() + : new[] { new V1EnvVar("GZCTF_FLAG", config.Flag) }, Ports = new[] { new V1ContainerPort(config.ExposedPort) }, - Resources = new V1ResourceRequirements() + Resources = new V1ResourceRequirements { - Limits = new Dictionary() + Limits = new Dictionary { - ["cpu"] = new ResourceQuantity($"{config.CPUCount * 100}m"), - ["memory"] = new ResourceQuantity($"{config.MemoryLimit}Mi"), - ["ephemeral-storage"] = new ResourceQuantity($"{config.StorageLimit}Mi") + ["cpu"] = new($"{config.CPUCount * 100}m"), + ["memory"] = new($"{config.MemoryLimit}Mi"), + ["ephemeral-storage"] = new($"{config.StorageLimit}Mi") }, - Requests = new Dictionary() - { - ["cpu"] = new ResourceQuantity("10m"), - ["memory"] = new ResourceQuantity("32Mi") - } + Requests = new Dictionary { ["cpu"] = new("10m"), ["memory"] = new("32Mi") } } } }, @@ -98,7 +94,7 @@ public K8sManager(IContainerProvider provider, ILogger< try { - pod = await _client.CreateNamespacedPodAsync(pod, _options.Namespace, cancellationToken: token); + pod = await _client.CreateNamespacedPodAsync(pod, options.Namespace, cancellationToken: token); } catch (HttpOperationException e) { @@ -114,43 +110,34 @@ public K8sManager(IContainerProvider provider, ILogger< if (pod is null) { - _logger.SystemLog($"创建容器实例 {config.Image.Split("/").LastOrDefault()} 失败", TaskStatus.Failed, LogLevel.Warning); + _logger.SystemLog($"创建容器实例 {config.Image.Split("/").LastOrDefault()} 失败", TaskStatus.Failed, + LogLevel.Warning); return null; } // Service is needed for port mapping - var container = new Container() - { - ContainerId = name, - Image = config.Image, - Port = config.ExposedPort, - }; + var container = new Models.Data.Container { ContainerId = name, Image = config.Image, Port = config.ExposedPort }; var service = new V1Service("v1", "Service") { - Metadata = new V1ObjectMeta() + Metadata = new V1ObjectMeta { Name = name, NamespaceProperty = _meta.Config.Namespace, - Labels = new Dictionary() { ["ctf.gzti.me/ResourceId"] = name } + Labels = new Dictionary { ["ctf.gzti.me/ResourceId"] = name } }, - Spec = new V1ServiceSpec() + Spec = new V1ServiceSpec { Type = _meta.ExposePort ? "NodePort" : "ClusterIP", - Ports = new[] - { - new V1ServicePort(config.ExposedPort, targetPort: config.ExposedPort) - }, - Selector = new Dictionary() - { - ["ctf.gzti.me/ResourceId"] = name - } + Ports = new[] { new V1ServicePort(config.ExposedPort, targetPort: config.ExposedPort) }, + Selector = new Dictionary { ["ctf.gzti.me/ResourceId"] = name } } }; try { - service = await _client.CoreV1.CreateNamespacedServiceAsync(service, _meta.Config.Namespace, cancellationToken: token); + service = await _client.CoreV1.CreateNamespacedServiceAsync(service, _meta.Config.Namespace, + cancellationToken: token); } catch (HttpOperationException e) { @@ -159,7 +146,11 @@ public K8sManager(IContainerProvider provider, ILogger< // remove the pod if service creation failed, ignore the error await _client.CoreV1.DeleteNamespacedPodAsync(name, _meta.Config.Namespace, cancellationToken: token); } - catch { } + catch + { + // ignored + } + _logger.SystemLog($"服务 {name} 创建失败, 状态:{e.Response.StatusCode}", TaskStatus.Failed, LogLevel.Warning); _logger.SystemLog($"服务 {name} 创建失败, 响应:{e.Response.Content}", TaskStatus.Failed, LogLevel.Error); return null; @@ -171,7 +162,11 @@ public K8sManager(IContainerProvider provider, ILogger< // remove the pod if service creation failed, ignore the error await _client.CoreV1.DeleteNamespacedPodAsync(name, _meta.Config.Namespace, cancellationToken: token); } - catch { } + catch + { + // ignored + } + _logger.LogError(e, "创建服务失败"); return null; } @@ -191,12 +186,14 @@ public K8sManager(IContainerProvider provider, ILogger< return container; } - public async Task DestroyContainerAsync(Container container, CancellationToken token = default) + public async Task DestroyContainerAsync(Models.Data.Container container, CancellationToken token = default) { try { - await _client.CoreV1.DeleteNamespacedServiceAsync(container.ContainerId, _meta.Config.Namespace, cancellationToken: token); - await _client.CoreV1.DeleteNamespacedPodAsync(container.ContainerId, _meta.Config.Namespace, cancellationToken: token); + await _client.CoreV1.DeleteNamespacedServiceAsync(container.ContainerId, _meta.Config.Namespace, + cancellationToken: token); + await _client.CoreV1.DeleteNamespacedPodAsync(container.ContainerId, _meta.Config.Namespace, + cancellationToken: token); } catch (HttpOperationException e) { @@ -205,8 +202,11 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t container.Status = ContainerStatus.Destroyed; return; } - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.Response.StatusCode}", TaskStatus.Failed, LogLevel.Warning); - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.Response.Content}", TaskStatus.Failed, LogLevel.Error); + + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.Response.StatusCode}", TaskStatus.Failed, + LogLevel.Warning); + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.Response.Content}", TaskStatus.Failed, + LogLevel.Error); } catch (Exception e) { @@ -216,5 +216,4 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t container.Status = ContainerStatus.Destroyed; } - -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/Manager/SwarmManager.cs b/src/GZCTF/Services/Container/Manager/SwarmManager.cs index 2045a1b82..32c84beca 100644 --- a/src/GZCTF/Services/Container/Manager/SwarmManager.cs +++ b/src/GZCTF/Services/Container/Manager/SwarmManager.cs @@ -2,29 +2,28 @@ using Docker.DotNet; using Docker.DotNet.Models; using GZCTF.Models.Internal; +using GZCTF.Services.Container.Provider; using GZCTF.Services.Interface; -using GZCTF.Utils; +using ContainerStatus = GZCTF.Utils.ContainerStatus; -namespace GZCTF.Services; +namespace GZCTF.Services.Container.Manager; public class SwarmManager : IContainerManager { - private readonly ILogger _logger; - private readonly IContainerProvider _provider; - private readonly DockerMetadata _meta; - private readonly DockerClient _client; + readonly DockerClient _client; + readonly ILogger _logger; + readonly DockerMetadata _meta; public SwarmManager(IContainerProvider provider, ILogger logger) { _logger = logger; - _provider = provider; - _meta = _provider.GetMetadata(); - _client = _provider.GetProvider(); + _meta = provider.GetMetadata(); + _client = provider.GetProvider(); - logger.SystemLog($"容器管理模式:Docker Swarm 集群容器控制", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog("容器管理模式:Docker Swarm 集群容器控制", TaskStatus.Success, LogLevel.Debug); } - public async Task DestroyContainerAsync(Container container, CancellationToken token = default) + public async Task DestroyContainerAsync(Models.Data.Container container, CancellationToken token = default) { try { @@ -42,8 +41,10 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t } else { - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.StatusCode}", TaskStatus.Failed, LogLevel.Warning); - _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.ResponseBody}", TaskStatus.Failed, LogLevel.Error); + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 状态:{e.StatusCode}", TaskStatus.Failed, + LogLevel.Warning); + _logger.SystemLog($"容器 {container.ContainerId} 删除失败, 响应:{e.ResponseBody}", TaskStatus.Failed, + LogLevel.Error); return; } } @@ -56,49 +57,13 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t container.Status = ContainerStatus.Destroyed; } - private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig config) - => new() - { - RegistryAuth = _meta.Auth, - Service = new() - { - Name = DockerMetadata.GetName(config), - Labels = new Dictionary { ["TeamId"] = config.TeamId, ["UserId"] = config.UserId }, - Mode = new() { Replicated = new() { Replicas = 1 } }, - TaskTemplate = new() - { - RestartPolicy = new() { Condition = "none" }, - ContainerSpec = new() - { - Image = config.Image, - Env = config.Flag is null ? Array.Empty() : new string[] { $"GZCTF_FLAG={config.Flag}" } - }, - Resources = new() - { - Limits = new() - { - MemoryBytes = config.MemoryLimit * 1024 * 1024, - NanoCPUs = config.CPUCount * 1_0000_0000, - }, - }, - }, - EndpointSpec = new() - { - Ports = new PortConfig[] { new() { - PublishMode = _meta.ExposePort ? "global" : "vip", - TargetPort = (uint)config.ExposedPort, - } - }, - }, - } - }; - - public async Task CreateContainerAsync(ContainerConfig config, CancellationToken token = default) + public async Task CreateContainerAsync(ContainerConfig config, + CancellationToken token = default) { - var parameters = GetServiceCreateParameters(config); - int retry = 0; + ServiceCreateParameters parameters = GetServiceCreateParameters(config); + var retry = 0; ServiceCreateResponse? serviceRes; - CreateContainer: + CreateContainer: try { serviceRes = await _client.Swarm.CreateServiceAsync(parameters, token); @@ -107,17 +72,18 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi { if (e.StatusCode == HttpStatusCode.Conflict && retry < 3) { - _logger.SystemLog($"容器 {parameters.Service.Name} 已存在,尝试移除后重新创建", TaskStatus.Duplicate, LogLevel.Warning); + _logger.SystemLog($"容器 {parameters.Service.Name} 已存在,尝试移除后重新创建", TaskStatus.Duplicate, + LogLevel.Warning); await _client.Swarm.RemoveServiceAsync(parameters.Service.Name, token); retry++; goto CreateContainer; } - else - { - _logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 状态:{e.StatusCode}", TaskStatus.Failed, LogLevel.Warning); - _logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 响应:{e.ResponseBody}", TaskStatus.Failed, LogLevel.Error); - return null; - } + + _logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 状态:{e.StatusCode}", TaskStatus.Failed, + LogLevel.Warning); + _logger.SystemLog($"容器 {parameters.Service.Name} 创建失败, 响应:{e.ResponseBody}", TaskStatus.Failed, + LogLevel.Error); + return null; } catch (Exception e) { @@ -125,11 +91,7 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi return null; } - var container = new Container() - { - ContainerId = serviceRes.ID, - Image = config.Image, - }; + var container = new Models.Data.Container { ContainerId = serviceRes.ID, Image = config.Image }; retry = 0; SwarmService? res; @@ -139,9 +101,11 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi retry++; if (retry == 3) { - _logger.SystemLog($"容器 {container.ContainerId} 创建后未获取到端口暴露信息,创建失败", TaskStatus.Failed, LogLevel.Warning); + _logger.SystemLog($"容器 {container.ContainerId} 创建后未获取到端口暴露信息,创建失败", TaskStatus.Failed, + LogLevel.Warning); return null; } + if (res is not { Endpoint.Ports.Count: > 0 }) await Task.Delay(500, token); } while (res is not { Endpoint.Ports.Count: > 0 }); @@ -163,4 +127,38 @@ private ServiceCreateParameters GetServiceCreateParameters(ContainerConfig confi return container; } -} + + ServiceCreateParameters GetServiceCreateParameters(ContainerConfig config) => + new() + { + RegistryAuth = _meta.Auth, + Service = new() + { + Name = DockerMetadata.GetName(config), + Labels = + new Dictionary { ["TeamId"] = config.TeamId, ["UserId"] = config.UserId }, + Mode = new() { Replicated = new() { Replicas = 1 } }, + TaskTemplate = new() + { + RestartPolicy = new() { Condition = "none" }, + ContainerSpec = + new() + { + Image = config.Image, + Env = + config.Flag is null + ? Array.Empty() + : new[] { $"GZCTF_FLAG={config.Flag}" } + }, + Resources = new() { Limits = new() { MemoryBytes = config.MemoryLimit * 1024 * 1024, NanoCPUs = config.CPUCount * 1_0000_0000 } } + }, + EndpointSpec = new() + { + Ports = new PortConfig[] + { + new() { PublishMode = _meta.ExposePort ? "global" : "vip", TargetPort = (uint)config.ExposedPort } + } + } + } + }; +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/Provider/DockerProvider.cs b/src/GZCTF/Services/Container/Provider/DockerProvider.cs index 012551d79..85447b16e 100644 --- a/src/GZCTF/Services/Container/Provider/DockerProvider.cs +++ b/src/GZCTF/Services/Container/Provider/DockerProvider.cs @@ -2,10 +2,9 @@ using Docker.DotNet.Models; using GZCTF.Models.Internal; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.Extensions.Options; -namespace GZCTF.Services; +namespace GZCTF.Services.Container.Provider; public class DockerMetadata : ContainerProviderMetadata { @@ -24,43 +23,40 @@ public class DockerMetadata : ContainerProviderMetadata /// /// /// - public static string GetName(ContainerConfig config) - => $"{config.Image.Split("/").LastOrDefault()?.Split(":").FirstOrDefault()}_{(config.Flag ?? Guid.NewGuid().ToString()).StrMD5()[..16]}"; + public static string GetName(ContainerConfig config) => + $"{config.Image.Split("/").LastOrDefault()?.Split(":").FirstOrDefault()}_{(config.Flag ?? Guid.NewGuid().ToString()).StrMd5()[..16]}"; } public class DockerProvider : IContainerProvider { - private readonly DockerClient _dockerClient; - private readonly DockerMetadata _dockerMeta; + readonly DockerClient _dockerClient; + readonly DockerMetadata _dockerMeta; - public DockerMetadata GetMetadata() => _dockerMeta; - public DockerClient GetProvider() => _dockerClient; - - public DockerProvider(IOptions options, IOptions registry, ILogger logger) + public DockerProvider(IOptions options, IOptions registry, + ILogger logger) { _dockerMeta = new() { - Config = options.Value.DockerConfig ?? new(), - PortMappingType = options.Value.PortMappingType, - PublicEntry = options.Value.PublicEntry, + Config = options.Value.DockerConfig ?? new(), PortMappingType = options.Value.PortMappingType, PublicEntry = options.Value.PublicEntry }; - DockerClientConfiguration cfg = string.IsNullOrEmpty(_dockerMeta.Config.Uri) ? new() : new(new Uri(_dockerMeta.Config.Uri)); + DockerClientConfiguration cfg = string.IsNullOrEmpty(_dockerMeta.Config.Uri) + ? new() + : new(new Uri(_dockerMeta.Config.Uri)); // TODO: Docker Auth Required _dockerClient = cfg.CreateClient(); // Auth for registry if (!string.IsNullOrWhiteSpace(registry.Value.UserName) && !string.IsNullOrWhiteSpace(registry.Value.Password)) - { - _dockerMeta.Auth = new AuthConfig() - { - Username = registry.Value.UserName, - Password = registry.Value.Password, - }; - } + _dockerMeta.Auth = new AuthConfig { Username = registry.Value.UserName, Password = registry.Value.Password }; - logger.SystemLog($"Docker 初始化成功 ({(string.IsNullOrEmpty(_dockerMeta.Config.Uri) ? "localhost" : _dockerMeta.Config.Uri)})", TaskStatus.Success, LogLevel.Debug); + logger.SystemLog( + $"Docker 初始化成功 ({(string.IsNullOrEmpty(_dockerMeta.Config.Uri) ? "localhost" : _dockerMeta.Config.Uri)})", + TaskStatus.Success, LogLevel.Debug); } -} + public DockerMetadata GetMetadata() => _dockerMeta; + + public DockerClient GetProvider() => _dockerClient; +} \ No newline at end of file diff --git a/src/GZCTF/Services/Container/Provider/K8sProvider.cs b/src/GZCTF/Services/Container/Provider/K8sProvider.cs index 42dd37378..e09db12c5 100644 --- a/src/GZCTF/Services/Container/Provider/K8sProvider.cs +++ b/src/GZCTF/Services/Container/Provider/K8sProvider.cs @@ -1,12 +1,11 @@ using System.Text.Json; using GZCTF.Models.Internal; using GZCTF.Services.Interface; -using GZCTF.Utils; using k8s; using k8s.Models; using Microsoft.Extensions.Options; -namespace GZCTF.Services; +namespace GZCTF.Services.Container.Provider; public class K8sMetadata : ContainerProviderMetadata { @@ -18,7 +17,7 @@ public class K8sMetadata : ContainerProviderMetadata /// /// K8s 集群 Host IP /// - public string HostIP { get; set; } = string.Empty; + public string HostIp { get; set; } = string.Empty; /// /// K8s 配置 @@ -28,43 +27,39 @@ public class K8sMetadata : ContainerProviderMetadata public class K8sProvider : IContainerProvider { - private const string NetworkPolicy = "gzctf-policy"; + const string NetworkPolicy = "gzctf-policy"; + readonly K8sMetadata _k8sMetadata; - private readonly Kubernetes _kubernetesClient; - private readonly K8sMetadata _k8sMetadata; + readonly Kubernetes _kubernetesClient; - public Kubernetes GetProvider() => _kubernetesClient; - public K8sMetadata GetMetadata() => _k8sMetadata; - - public K8sProvider(IOptions registry, IOptions options, ILogger logger) + public K8sProvider(IOptions registry, IOptions options, + ILogger logger) { _k8sMetadata = new() { - Config = options.Value.K8sConfig ?? new(), - PortMappingType = options.Value.PortMappingType, - PublicEntry = options.Value.PublicEntry, + Config = options.Value.K8sConfig ?? new(), PortMappingType = options.Value.PortMappingType, PublicEntry = options.Value.PublicEntry }; if (!File.Exists(_k8sMetadata.Config.KubeConfig)) { - LogHelper.SystemLog(logger, $"无法加载 K8s 配置文件,请确保配置文件存在 {_k8sMetadata.Config.KubeConfig}"); + logger.SystemLog($"无法加载 K8s 配置文件,请确保配置文件存在 {_k8sMetadata.Config.KubeConfig}"); throw new FileNotFoundException(_k8sMetadata.Config.KubeConfig); } var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(_k8sMetadata.Config.KubeConfig); - _k8sMetadata.HostIP = config.Host[(config.Host.LastIndexOf('/') + 1)..config.Host.LastIndexOf(':')]; + _k8sMetadata.HostIp = config.Host[(config.Host.LastIndexOf('/') + 1)..config.Host.LastIndexOf(':')]; _kubernetesClient = new Kubernetes(config); - var registryValue = registry.Value; + RegistryConfig registryValue = registry.Value; var withAuth = !string.IsNullOrWhiteSpace(registryValue.ServerAddress) - && !string.IsNullOrWhiteSpace(registryValue.UserName) - && !string.IsNullOrWhiteSpace(registryValue.Password); + && !string.IsNullOrWhiteSpace(registryValue.UserName) + && !string.IsNullOrWhiteSpace(registryValue.Password); if (withAuth) { - var padding = $"{registryValue.UserName}@{registryValue.Password}@{registryValue.ServerAddress}".StrMD5(); + var padding = $"{registryValue.UserName}@{registryValue.Password}@{registryValue.ServerAddress}".StrMd5(); _k8sMetadata.AuthSecretName = $"{registryValue.UserName}-{padding}".ToValidRFC1123String("secret"); } @@ -81,14 +76,18 @@ public K8sProvider(IOptions registry, IOptions _kubernetesClient; + + public K8sMetadata GetMetadata() => _k8sMetadata; + + void InitK8s(bool withAuth, RegistryConfig? registry) { if (_kubernetesClient.CoreV1.ListNamespace().Items.All(ns => ns.Metadata.Name != _k8sMetadata.Config.Namespace)) - _kubernetesClient.CoreV1.CreateNamespace(new() { Metadata = new() { Name = _k8sMetadata.Config.Namespace } }); - - if (_kubernetesClient.NetworkingV1.ListNamespacedNetworkPolicy(_k8sMetadata.Config.Namespace).Items.All(np => np.Metadata.Name != NetworkPolicy)) - { + _kubernetesClient.CoreV1.CreateNamespace( + new() { Metadata = new() { Name = _k8sMetadata.Config.Namespace } }); + if (_kubernetesClient.NetworkingV1.ListNamespacedNetworkPolicy(_k8sMetadata.Config.Namespace).Items + .All(np => np.Metadata.Name != NetworkPolicy)) _kubernetesClient.NetworkingV1.CreateNamespacedNetworkPolicy(new() { Metadata = new() { Name = NetworkPolicy }, @@ -98,54 +97,48 @@ private void InitK8s(bool withAuth, RegistryConfig? registry) PolicyTypes = new[] { "Egress" }, Egress = new[] { - new V1NetworkPolicyEgressRule() + new V1NetworkPolicyEgressRule { To = new[] { - new V1NetworkPolicyPeer() { - IpBlock = new() { + new V1NetworkPolicyPeer + { + IpBlock = new() + { Cidr = "0.0.0.0/0", - // FIXME: remove nullable when JsonObjectCreationHandling release - Except = _k8sMetadata.Config.AllowCIDR ?? new[] { "10.0.0.0/8" } + Except + // FIXME: remove nullable when JsonObjectCreationHandling release + = _k8sMetadata.Config.AllowCIDR ?? new[] { "10.0.0.0/8" } } - }, + } } } } } }, _k8sMetadata.Config.Namespace); - } if (withAuth && registry is not null && registry.ServerAddress is not null) { var auth = Codec.Base64.Encode($"{registry.UserName}:{registry.Password}"); - var dockerjsonObj = new + var dockerJsonObj = new { - auths = new Dictionary { - { - registry.ServerAddress, new { - auth, - username = registry.UserName, - password = registry.Password - } - } + auths = new Dictionary + { + { registry.ServerAddress, new { auth, username = registry.UserName, password = registry.Password } } } }; - var dockerjsonBytes = JsonSerializer.SerializeToUtf8Bytes(dockerjsonObj); - var secret = new V1Secret() + var dockerJsonBytes = JsonSerializer.SerializeToUtf8Bytes(dockerJsonObj); + var secret = new V1Secret { - Metadata = new V1ObjectMeta() - { - Name = _k8sMetadata.AuthSecretName, - NamespaceProperty = _k8sMetadata.Config.Namespace, - }, - Data = new Dictionary() { [".dockerconfigjson"] = dockerjsonBytes }, + Metadata = new V1ObjectMeta { Name = _k8sMetadata.AuthSecretName, NamespaceProperty = _k8sMetadata.Config.Namespace }, + Data = new Dictionary { [".dockerconfigjson"] = dockerJsonBytes }, Type = "kubernetes.io/dockerconfigjson" }; try { - _kubernetesClient.CoreV1.ReplaceNamespacedSecret(secret, _k8sMetadata.AuthSecretName, _k8sMetadata.Config.Namespace); + _kubernetesClient.CoreV1.ReplaceNamespacedSecret(secret, _k8sMetadata.AuthSecretName, + _k8sMetadata.Config.Namespace); } catch { @@ -153,5 +146,4 @@ private void InitK8s(bool withAuth, RegistryConfig? registry) } } } -} - +} \ No newline at end of file diff --git a/src/GZCTF/Services/CronJobService.cs b/src/GZCTF/Services/CronJobService.cs index 0b861bb3a..b31ef13ba 100644 --- a/src/GZCTF/Services/CronJobService.cs +++ b/src/GZCTF/Services/CronJobService.cs @@ -1,15 +1,21 @@ using System.Threading.Channels; using GZCTF.Repositories; using GZCTF.Repositories.Interface; +using GZCTF.Services.Cache; using GZCTF.Services.Interface; -using GZCTF.Utils; using Microsoft.Extensions.Caching.Distributed; namespace GZCTF.Services; public class CronJobService(IServiceScopeFactory provider, ILogger logger) : IHostedService, IDisposable { - private Timer? _timer; + Timer? _timer; + + public void Dispose() + { + _timer?.Dispose(); + GC.SuppressFinalize(this); + } public Task StartAsync(CancellationToken token) { @@ -18,12 +24,19 @@ public Task StartAsync(CancellationToken token) return Task.CompletedTask; } - private async Task ContainerChecker(AsyncServiceScope scope) + public Task StopAsync(CancellationToken token) + { + _timer?.Change(Timeout.Infinite, 0); + logger.SystemLog("定时任务已停止", TaskStatus.Exit, LogLevel.Debug); + return Task.CompletedTask; + } + + async Task ContainerChecker(AsyncServiceScope scope) { var containerRepo = scope.ServiceProvider.GetRequiredService(); var containerService = scope.ServiceProvider.GetRequiredService(); - foreach (var container in await containerRepo.GetDyingContainers()) + foreach (Models.Data.Container container in await containerRepo.GetDyingContainers()) { await containerService.DestroyContainerAsync(container); await containerRepo.RemoveContainer(container); @@ -31,7 +44,7 @@ private async Task ContainerChecker(AsyncServiceScope scope) } } - private async Task BootstrapCache(AsyncServiceScope scope) + async Task BootstrapCache(AsyncServiceScope scope) { var gameRepo = scope.ServiceProvider.GetRequiredService(); var upcoming = await gameRepo.GetUpcomingGames(); @@ -54,24 +67,11 @@ private async Task BootstrapCache(AsyncServiceScope scope) } } - private async void Execute(object? state) + async void Execute(object? state) { - await using var scope = provider.CreateAsyncScope(); + await using AsyncServiceScope scope = provider.CreateAsyncScope(); await ContainerChecker(scope); await BootstrapCache(scope); } - - public Task StopAsync(CancellationToken token) - { - _timer?.Change(Timeout.Infinite, 0); - logger.SystemLog("定时任务已停止", TaskStatus.Exit, LogLevel.Debug); - return Task.CompletedTask; - } - - public void Dispose() - { - _timer?.Dispose(); - GC.SuppressFinalize(this); - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/FlagChecker.cs b/src/GZCTF/Services/FlagChecker.cs index b01c3cc87..0d3c54cb6 100644 --- a/src/GZCTF/Services/FlagChecker.cs +++ b/src/GZCTF/Services/FlagChecker.cs @@ -1,6 +1,7 @@ using System.Threading.Channels; +using GZCTF.Models.Internal; using GZCTF.Repositories.Interface; -using GZCTF.Utils; +using GZCTF.Services.Cache; using Microsoft.EntityFrameworkCore; namespace GZCTF.Services; @@ -10,19 +11,49 @@ public class FlagChecker(ChannelReader channelReader, ILogger logger, IServiceScopeFactory serviceScopeFactory) : IHostedService { - private CancellationTokenSource TokenSource { get; set; } = new CancellationTokenSource(); + CancellationTokenSource TokenSource { get; set; } = new(); - private async Task Checker(int id, CancellationToken token = default) + public async Task StartAsync(CancellationToken cancellationToken) + { + TokenSource = new CancellationTokenSource(); + + for (var i = 0; i < 2; ++i) + _ = Checker(i, TokenSource.Token); + + await using AsyncServiceScope scope = serviceScopeFactory.CreateAsyncScope(); + + var submissionRepository = scope.ServiceProvider.GetRequiredService(); + Submission[] flags = await submissionRepository.GetUncheckedFlags(TokenSource.Token); + + foreach (Submission item in flags) + await channelWriter.WriteAsync(item, TokenSource.Token); + + if (flags.Length > 0) + logger.SystemLog($"重新开始检查 {flags.Length} 个 flag", TaskStatus.Pending, LogLevel.Debug); + + logger.SystemLog("Flag 检查已启用", TaskStatus.Success, LogLevel.Debug); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + TokenSource.Cancel(); + + logger.SystemLog("Flag 检查已停止", TaskStatus.Exit, LogLevel.Debug); + + return Task.CompletedTask; + } + + async Task Checker(int id, CancellationToken token = default) { logger.SystemLog($"检查线程 #{id} 已启动", TaskStatus.Pending, LogLevel.Debug); try { - await foreach (var item in channelReader.ReadAllAsync(token)) + await foreach (Submission item in channelReader.ReadAllAsync(token)) { logger.SystemLog($"检查线程 #{id} 开始处理提交:{item.Answer}", TaskStatus.Pending, LogLevel.Debug); - await using var scope = serviceScopeFactory.CreateAsyncScope(); + await using AsyncServiceScope scope = serviceScopeFactory.CreateAsyncScope(); var cacheHelper = scope.ServiceProvider.GetRequiredService(); var eventRepository = scope.ServiceProvider.GetRequiredService(); @@ -32,13 +63,17 @@ private async Task Checker(int id, CancellationToken token = default) try { - var (type, ans) = await instanceRepository.VerifyAnswer(item, token); + (SubmissionType type, AnswerResult ans) = await instanceRepository.VerifyAnswer(item, token); if (ans == AnswerResult.NotFound) - logger.Log($"[实例未知] 未找到队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的实例", item.User!, TaskStatus.NotFound, LogLevel.Warning); + { + logger.Log($"[实例未知] 未找到队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的实例", item.User, + TaskStatus.NotFound, LogLevel.Warning); + } else if (ans == AnswerResult.Accepted) { - logger.Log($"[提交正确] 队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的答案 [{item.Answer}]", item.User!, TaskStatus.Success, LogLevel.Information); + logger.Log($"[提交正确] 队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的答案 [{item.Answer}]", + item.User, TaskStatus.Success, LogLevel.Information); await eventRepository.AddEvent(GameEvent.FromSubmission(item, type, ans), token); @@ -48,24 +83,29 @@ private async Task Checker(int id, CancellationToken token = default) } else { - logger.Log($"[提交错误] 队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的答案 [{item.Answer}]", item.User!, TaskStatus.Failed, LogLevel.Information); + logger.Log($"[提交错误] 队伍 [{item.Team.Name}] 提交题目 [{item.Challenge.Title}] 的答案 [{item.Answer}]", + item.User, TaskStatus.Failed, LogLevel.Information); await eventRepository.AddEvent(GameEvent.FromSubmission(item, type, ans), token); - var result = await instanceRepository.CheckCheat(item, token); + CheatCheckInfo result = await instanceRepository.CheckCheat(item, token); ans = result.AnswerResult; if (ans == AnswerResult.CheatDetected) { - logger.Log($"[作弊检查] 队伍 [{item.Team.Name}] 疑似违规 [{item.Challenge.Title}],相关队伍 [{result.SourceTeamName}]", item.User!, TaskStatus.Success, LogLevel.Information); - await eventRepository.AddEvent(new() - { - Type = EventType.CheatDetected, - Content = $"题目 [{item.Challenge.Title}] 疑似发生违规,相关队伍 [{item.Team.Name}] 和 [{result.SourceTeamName}]", - TeamId = item.TeamId, - UserId = item.UserId, - GameId = item.GameId, - }, token); + logger.Log( + $"[作弊检查] 队伍 [{item.Team.Name}] 疑似违规 [{item.Challenge.Title}],相关队伍 [{result.SourceTeamName}]", + item.User, TaskStatus.Success, LogLevel.Information); + await eventRepository.AddEvent( + new() + { + Type = EventType.CheatDetected, + Content = + $"题目 [{item.Challenge.Title}] 疑似发生违规,相关队伍 [{item.Team.Name}] 和 [{result.SourceTeamName}]", + TeamId = item.TeamId, + UserId = item.UserId, + GameId = item.GameId + }, token); } } @@ -100,34 +140,4 @@ await eventRepository.AddEvent(new() logger.SystemLog($"检查线程 #{id} 已退出", TaskStatus.Exit, LogLevel.Debug); } } - - public async Task StartAsync(CancellationToken cancellationToken) - { - TokenSource = new CancellationTokenSource(); - - for (int i = 0; i < 2; ++i) - _ = Checker(i, TokenSource.Token); - - await using var scope = serviceScopeFactory.CreateAsyncScope(); - - var submissionRepository = scope.ServiceProvider.GetRequiredService(); - var flags = await submissionRepository.GetUncheckedFlags(TokenSource.Token); - - foreach (var item in flags) - await channelWriter.WriteAsync(item, TokenSource.Token); - - if (flags.Length > 0) - logger.SystemLog($"重新开始检查 {flags.Length} 个 flag", TaskStatus.Pending, LogLevel.Debug); - - logger.SystemLog("Flag 检查已启用", TaskStatus.Success, LogLevel.Debug); - } - - public Task StopAsync(CancellationToken cancellationToken) - { - TokenSource.Cancel(); - - logger.SystemLog("Flag 检查已停止", TaskStatus.Exit, LogLevel.Debug); - - return Task.CompletedTask; - } -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Interface/IConfigService.cs b/src/GZCTF/Services/Interface/IConfigService.cs index 3f02846bd..19c7d7cad 100644 --- a/src/GZCTF/Services/Interface/IConfigService.cs +++ b/src/GZCTF/Services/Interface/IConfigService.cs @@ -24,4 +24,4 @@ public interface IConfigService /// 重载配置 /// public void ReloadConfig(); -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/Interface/IContainerManager.cs b/src/GZCTF/Services/Interface/IContainerManager.cs index 0e30e8d0b..2bb6bd04c 100644 --- a/src/GZCTF/Services/Interface/IContainerManager.cs +++ b/src/GZCTF/Services/Interface/IContainerManager.cs @@ -10,7 +10,7 @@ public interface IContainerManager /// 容器配置 /// /// - public Task CreateContainerAsync(ContainerConfig config, CancellationToken token = default); + public Task CreateContainerAsync(ContainerConfig config, CancellationToken token = default); /// /// 销毁容器 @@ -18,5 +18,5 @@ public interface IContainerManager /// 容器对象 /// /// - public Task DestroyContainerAsync(Container container, CancellationToken token = default); -} + public Task DestroyContainerAsync(Models.Data.Container container, CancellationToken token = default); +} \ No newline at end of file diff --git a/src/GZCTF/Services/Interface/IContainerProvider.cs b/src/GZCTF/Services/Interface/IContainerProvider.cs index 6660f83e8..deb693b94 100644 --- a/src/GZCTF/Services/Interface/IContainerProvider.cs +++ b/src/GZCTF/Services/Interface/IContainerProvider.cs @@ -13,5 +13,4 @@ public interface IContainerProvider /// /// public M GetMetadata(); -} - +} \ No newline at end of file diff --git a/src/GZCTF/Services/Interface/IMailSender.cs b/src/GZCTF/Services/Interface/IMailSender.cs index 5d5707a66..f8e0a5cfa 100644 --- a/src/GZCTF/Services/Interface/IMailSender.cs +++ b/src/GZCTF/Services/Interface/IMailSender.cs @@ -20,7 +20,8 @@ public interface IMailSender /// 用户名 /// 电子邮件地址 /// 链接 - public Task SendUrlAsync(string? title, string? information, string? btnmsg, string? userName, string? email, string? url); + public Task SendUrlAsync(string? title, string? information, string? btnmsg, string? userName, string? email, + string? url); /// /// 发送新用户验证URL @@ -45,4 +46,4 @@ public interface IMailSender /// 用户的电子邮件 /// 重置链接 public bool SendResetPasswordUrl(string? userName, string? email, string? resetLink); -} +} \ No newline at end of file diff --git a/src/GZCTF/Services/MailSender.cs b/src/GZCTF/Services/MailSender.cs index a10cc3afd..af4c6a8b0 100644 --- a/src/GZCTF/Services/MailSender.cs +++ b/src/GZCTF/Services/MailSender.cs @@ -2,16 +2,16 @@ using System.Text; using GZCTF.Models.Internal; using GZCTF.Services.Interface; -using GZCTF.Utils; using MailKit.Net.Smtp; using Microsoft.Extensions.Options; using MimeKit; +using MimeKit.Text; namespace GZCTF.Services; public class MailSender(IOptions options, ILogger logger) : IMailSender { - private readonly EmailConfig? _options = options.Value; + readonly EmailConfig? _options = options.Value; public async Task SendEmailAsync(string subject, string content, string to) { @@ -24,7 +24,7 @@ public async Task SendEmailAsync(string subject, string content, string to msg.From.Add(new MailboxAddress(_options.SendMailAddress, _options.SendMailAddress)); msg.To.Add(new MailboxAddress(to, to)); msg.Subject = subject; - msg.Body = new TextPart(MimeKit.Text.TextFormat.Html) { Text = content }; + msg.Body = new TextPart(TextFormat.Html) { Text = content }; try { @@ -46,7 +46,8 @@ public async Task SendEmailAsync(string subject, string content, string to } } - public async Task SendUrlAsync(string? title, string? information, string? btnmsg, string? userName, string? email, string? url) + public async Task SendUrlAsync(string? title, string? information, string? btnmsg, string? userName, string? email, + string? url) { if (email is null || userName is null || title is null) { @@ -54,12 +55,12 @@ public async Task SendUrlAsync(string? title, string? information, string? btnms return; } - string ns = typeof(MailSender).Namespace ?? "GZCTF.Services"; + var ns = typeof(MailSender).Namespace ?? "GZCTF.Services"; Assembly asm = typeof(MailSender).Assembly; - string resourceName = $"{ns}.Assets.URLEmailTemplate.html"; - string emailContent = await + var resourceName = $"{ns}.Assets.URLEmailTemplate.html"; + var emailContent = await new StreamReader(asm.GetManifestResourceStream(resourceName)!) - .ReadToEndAsync(); + .ReadToEndAsync(); emailContent = new StringBuilder(emailContent) .Replace("{title}", title) @@ -75,27 +76,28 @@ public async Task SendUrlAsync(string? title, string? information, string? btnms logger.SystemLog("邮件发送失败!", TaskStatus.Failed); } - private bool SendUrlIfPossible(string? title, string? information, string? btnmsg, string? userName, string? email, string? url) - { - if (_options?.SendMailAddress is null) - return false; - - var _ = SendUrlAsync(title, information, btnmsg, userName, email, url); - return true; - } - - public bool SendConfirmEmailUrl(string? userName, string? email, string? confirmLink) - => SendUrlIfPossible("验证邮箱", + public bool SendConfirmEmailUrl(string? userName, string? email, string? confirmLink) => + SendUrlIfPossible("验证邮箱", $"你正在进行账户注册操作,我们需要验证你的注册邮箱:{email},请点击下方按钮进行验证。", "确认验证邮箱", userName, email, confirmLink); - public bool SendChangeEmailUrl(string? userName, string? email, string? resetLink) - => SendUrlIfPossible("更换邮箱", + public bool SendChangeEmailUrl(string? userName, string? email, string? resetLink) => + SendUrlIfPossible("更换邮箱", "你正在进行账户邮箱更换操作,请点击下方按钮验证你的新邮箱。", "确认更换邮箱", userName, email, resetLink); - public bool SendResetPasswordUrl(string? userName, string? email, string? resetLink) - => SendUrlIfPossible("重置密码", + public bool SendResetPasswordUrl(string? userName, string? email, string? resetLink) => + SendUrlIfPossible("重置密码", "你正在进行账户密码重置操作,请点击下方按钮重置你的密码。", "确认重置密码", userName, email, resetLink); -} + + bool SendUrlIfPossible(string? title, string? information, string? btnmsg, string? userName, string? email, + string? url) + { + if (_options?.SendMailAddress is null) + return false; + + Task _ = SendUrlAsync(title, information, btnmsg, userName, email, url); + return true; + } +} \ No newline at end of file diff --git a/src/GZCTF/Utils/Codec.cs b/src/GZCTF/Utils/Codec.cs index fd0775dc1..509ec71ac 100644 --- a/src/GZCTF/Utils/Codec.cs +++ b/src/GZCTF/Utils/Codec.cs @@ -1,13 +1,130 @@ -using System.IO.Compression; +using System.Diagnostics.CodeAnalysis; +using System.IO.Compression; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; -using NPOI.HSSF.Record; namespace GZCTF.Utils; public partial class Codec { + [GeneratedRegex(@"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()\-_=+]).{8,}$")] + private static partial Regex PasswordRegex(); + + /// + /// 生成随机密码 + /// + /// 密码长度 + /// + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string RandomPassword(int length) + { + var random = new Random(); + const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+"; + + string pwd; + do + { + pwd = new string(Enumerable.Repeat(chars, length < 8 ? 8 : length) + .Select(s => s[random.Next(s.Length)]).ToArray()); + } while (!PasswordRegex().IsMatch(pwd)); + + return pwd; + } + + /// + /// 转换为对应进制 + /// + /// 源数据 + /// 进制支持2,8,10,16 + /// + public static List ToBase(List source, int toBase) => new(source.ConvertAll(a => Convert.ToString(a, toBase))); + + /// + /// 字节数组转换为16进制字符串 + /// + /// 原始字节数组 + /// 是否使用小写 + /// + public static string BytesToHex(byte[] bytes, bool useLower = true) + { + var output = BitConverter.ToString(bytes).Replace("-", ""); + return useLower ? output.ToLowerInvariant() : output.ToUpperInvariant(); + } + + /// + /// 根据xor进行byte数异或 + /// + /// 原始数据 + /// xor密钥 + /// 异或结果 + public static byte[] Xor(byte[] data, byte[] xor) + { + var res = new byte[data.Length]; + for (var i = 0; i < data.Length; ++i) res[i] = (byte)(data[i] ^ xor[i % xor.Length]); + return res; + } + + /// + /// 将文件打包为 zip 文件 + /// + /// 文件列表 + /// 根目录 + /// 压缩包根目录 + /// + /// + public static async Task ZipFilesAsync(IEnumerable files, string basePath, string zipName, + CancellationToken token = default) + { + var size = files.Select(f => f.FileSize).Sum(); + + Stream tmp = size <= 64 * 1024 * 1024 + ? new MemoryStream() + : File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); + + using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); + + foreach (LocalFile file in files) + { + ZipArchiveEntry entry = zip.CreateEntry(Path.Combine(zipName, file.Name), CompressionLevel.Optimal); + await using Stream entryStream = entry.Open(); + await using FileStream fileStream = File.OpenRead(Path.Combine(basePath, file.Location, file.Hash)); + await fileStream.CopyToAsync(entryStream, token); + } + + await tmp.FlushAsync(token); + return tmp; + } + + /// + /// 将文件夹打包为 zip 文件 + /// + /// 根目录 + /// 压缩包根目录 + /// + /// + public static async Task ZipFilesAsync(string basePath, string zipName, CancellationToken token = default) + { + List records = FilePath.GetFileRecords(basePath, out var size); + + Stream tmp = size <= 64 * 1024 * 1024 + ? new MemoryStream() + : File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); + + using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); + + foreach (FileRecord file in records) + { + ZipArchiveEntry entry = zip.CreateEntry(Path.Combine(zipName, file.FileName), CompressionLevel.Optimal); + await using Stream entryStream = entry.Open(); + await using FileStream fileStream = File.OpenRead(Path.Combine(basePath, file.FileName)); + await fileStream.CopyToAsync(entryStream, token); + } + + await tmp.FlushAsync(token); + return tmp; + } + /// /// Base64编解码 /// @@ -46,7 +163,7 @@ public static string Encode(string? str, string type = "utf-8") public static byte[] EncodeToBytes(string? str, string type = "utf-8") { if (str is null) - return []; + return Array.Empty(); byte[] encoded; try @@ -55,27 +172,26 @@ public static byte[] EncodeToBytes(string? str, string type = "utf-8") } catch { - return []; + return Array.Empty(); } Span buffer = new char[encoded.Length * 4 / 3 + 8]; if (Convert.TryToBase64Chars(encoded, buffer, out var charsWritten)) return Encoding.GetEncoding(type).GetBytes(buffer[..charsWritten].ToArray()); - else - return []; + return Array.Empty(); } public static byte[] DecodeToBytes(string? str) { if (str is null) - return []; + return Array.Empty(); Span buffer = new byte[str.Length * 3 / 4 + 8]; - if (Convert.TryFromBase64String(str, buffer, out int bytesWritten)) + if (Convert.TryFromBase64String(str, buffer, out var bytesWritten)) return buffer[..bytesWritten].ToArray(); - return []; + return Array.Empty(); } } @@ -84,7 +200,7 @@ public static byte[] DecodeToBytes(string? str) /// public static class Leet { - private readonly static Dictionary CharMap = new() + static readonly Dictionary CharMap = new() { ['A'] = "Aa4", ['B'] = "Bb68", @@ -129,14 +245,12 @@ public static double LeetEntropy(string flag) double entropy = 0; var doLeet = false; foreach (var c in flag) - { - if (c == '{' || c == ']') + if (c is '{' or ']') doLeet = true; - else if (doLeet && (c == '}' || c == '[')) + else if (doLeet && c is '}' or '[') doLeet = false; - else if (doLeet && CharMap.TryGetValue(char.ToUpperInvariant(c), out var table) && table is not null) + else if (doLeet && CharMap.TryGetValue(char.ToUpperInvariant(c), out var table)) entropy += Math.Log(table.Length, 2); - } return entropy; } @@ -146,14 +260,18 @@ public static string LeetFlag(string original) Random random = new(); var doLeet = false; - // note: only leet 'X' in flag{XXXX_XXX_[TEAM_HASH]_XXX} + // note: only leet 'X' in flag{XXX_XXX_[TEAM_HASH]_XXX} foreach (var c in original) { - if (c == '{' || c == ']') + if (c is '{' or ']') + { doLeet = true; - else if (doLeet && (c == '}' || c == '[')) + } + else if (doLeet && c is '}' or '[') + { doLeet = false; - else if (doLeet && CharMap.TryGetValue(char.ToUpperInvariant(c), out var table) && table is not null) + } + else if (doLeet && CharMap.TryGetValue(char.ToUpperInvariant(c), out var table)) { var nc = table[random.Next(table.Length)]; sb.Append(nc); @@ -166,129 +284,10 @@ public static string LeetFlag(string original) return sb.ToString(); } } - - [GeneratedRegex("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()\\-_=+]).{8,}$")] - private static partial Regex PasswordRegex(); - - /// - /// 生成随机密码 - /// - /// 密码长度 - /// - public static string RandomPassword(int length) - { - var random = new Random(); - const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+"; - - string pwd; - do - { - pwd = new string(Enumerable.Repeat(chars, length < 8 ? 8 : length) - .Select(s => s[random.Next(s.Length)]).ToArray()); - } - while (!PasswordRegex().IsMatch(pwd)); - - return pwd; - } - - /// - /// 转换为对应进制 - /// - /// 源数据 - /// 进制支持2,8,10,16 - /// - public static List ToBase(List source, int tobase) - => new(source.ConvertAll((a) => Convert.ToString(a, tobase))); - - /// - /// 字节数组转换为16进制字符串 - /// - /// 原始字节数组 - /// 是否使用小写 - /// - public static string BytesToHex(byte[] bytes, bool useLower = true) - { - var output = BitConverter.ToString(bytes).Replace("-", ""); - return useLower ? output.ToLowerInvariant() : output.ToUpperInvariant(); - } - - /// - /// 根据xor进行byte数异或 - /// - /// 原始数据 - /// xor密钥 - /// 异或结果 - public static byte[] Xor(byte[] data, byte[] xor) - { - var res = new byte[data.Length]; - for (var i = 0; i < data.Length; ++i) - { - res[i] = (byte)(data[i] ^ xor[i % xor.Length]); - } - return res; - } - - /// - /// 将文件打包为 zip 文件 - /// - /// 文件列表 - /// 根目录 - /// 压缩包根目录 - /// - /// - public async static Task ZipFilesAsync(IEnumerable files, string basepath, string zipName, CancellationToken token = default) - { - var size = files.Select(f => f.FileSize).Sum(); - - Stream tmp = size <= 64 * 1024 * 1024 ? new MemoryStream() : - File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); - - using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); - - foreach (var file in files) - { - var entry = zip.CreateEntry(Path.Combine(zipName, file.Name), CompressionLevel.Optimal); - await using var entryStream = entry.Open(); - await using var fileStream = File.OpenRead(Path.Combine(basepath, file.Location, file.Hash)); - await fileStream.CopyToAsync(entryStream, token); - } - - await tmp.FlushAsync(token); - return tmp; - } - - /// - /// 将文件夹打包为 zip 文件 - /// - /// 根目录 - /// 压缩包根目录 - /// - /// - public async static Task ZipFilesAsync(string basePath, string zipName, CancellationToken token = default) - { - var records = FilePath.GetFileRecords(basePath, out long size); - - Stream tmp = size <= 64 * 1024 * 1024 ? new MemoryStream() : - File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); - - using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); - - foreach (var file in records) - { - var entry = zip.CreateEntry(Path.Combine(zipName, file.FileName), CompressionLevel.Optimal); - await using var entryStream = entry.Open(); - await using var fileStream = File.OpenRead(Path.Combine(basePath, file.FileName)); - await fileStream.CopyToAsync(entryStream, token); - } - - await tmp.FlushAsync(token); - return tmp; - } } public static partial class CodecExtensions { - [GeneratedRegex("[^a-zA-Z0-9]+")] private static partial Regex RFC1123ReplacePattern(); @@ -311,12 +310,7 @@ public static string ToValidRFC1123String(this string str, string leading = "nam ///
/// 原字符串 /// - public static List ASCII(this string str) - { - var buff = Encoding.ASCII.GetBytes(str); - List res = [..buff]; - return res; - } + public static byte[] Ascii(this string str) => Encoding.ASCII.GetBytes(str); /// /// 反转字符串 @@ -336,7 +330,7 @@ public static string Reverse(this string s) /// 原始字符串 /// 是否使用Base64编码 /// - public static string StrMD5(this string str, bool useBase64 = false) + public static string StrMd5(this string str, bool useBase64 = false) { var output = MD5.HashData(str.ToUTF8Bytes()); if (useBase64) @@ -363,16 +357,14 @@ public static string StrSHA256(this string str, bool useBase64 = false) /// /// 原始字符串 /// - public static byte[] BytesMD5(this string str) - => MD5.HashData(str.ToUTF8Bytes()); + public static byte[] BytesMd5(this string str) => MD5.HashData(str.ToUTF8Bytes()); /// /// 获取 SHA256 哈希字节摘要 /// /// 原始字符串 /// - public static byte[] BytesSHA256(this string str) - => SHA256.HashData(str.ToUTF8Bytes()); + public static byte[] BytesSHA256(this string str) => SHA256.HashData(str.ToUTF8Bytes()); /// @@ -380,7 +372,5 @@ public static byte[] BytesSHA256(this string str) /// /// 原始字符串 /// - public static byte[] ToUTF8Bytes(this string str) - => Encoding.UTF8.GetBytes(str); - -} + public static byte[] ToUTF8Bytes(this string str) => Encoding.UTF8.GetBytes(str); +} \ No newline at end of file diff --git a/src/GZCTF/Utils/DigitalSignature.cs b/src/GZCTF/Utils/DigitalSignature.cs index da1e619e2..41d950504 100644 --- a/src/GZCTF/Utils/DigitalSignature.cs +++ b/src/GZCTF/Utils/DigitalSignature.cs @@ -11,20 +11,9 @@ namespace GZCTF.Utils; public enum SignAlgorithm { Ed25519, - Ed25519ph, - Ed25519ctx, + Ed25519Ctx, Ed448, - Ed448ph, - MD5withRSA, - SHA256withRSA, - SHA384withRSA, - SHA512withRSA, - SHA256withDSA, - SHA384withDSA, - SHA512withDSA, - SHA256withECDSA, - SHA384withECDSA, - SHA512withECDSA, + SHA512WithRSA } public static class DigitalSignature @@ -38,14 +27,15 @@ public static string GenerateSignature(string data, AsymmetricKeyParameter priva throw new ArgumentNullException(nameof(privateKey)); var byteData = Encoding.UTF8.GetBytes(data); - var normalSig = SignerUtilities.GetSigner(signAlgorithm.ToString()); + ISigner? normalSig = SignerUtilities.GetSigner(signAlgorithm.ToString()); normalSig.Init(true, privateKey); normalSig.BlockUpdate(byteData, 0, data.Length); var normalResult = normalSig.GenerateSignature(); return Base64.ToBase64String(normalResult); } - public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter publicKey, SignAlgorithm signAlgorithm) + public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter publicKey, + SignAlgorithm signAlgorithm) { if (string.IsNullOrEmpty(data)) throw new ArgumentNullException(nameof(data)); @@ -58,10 +48,10 @@ public static bool VerifySignature(string data, string sign, AsymmetricKeyParame var signBytes = Base64.Decode(sign); var plainBytes = Encoding.UTF8.GetBytes(data); - var verifier = SignerUtilities.GetSigner(signAlgorithm.ToString()); + ISigner? verifier = SignerUtilities.GetSigner(signAlgorithm.ToString()); verifier.Init(false, publicKey); verifier.BlockUpdate(plainBytes, 0, plainBytes.Length); return verifier.VerifySignature(signBytes); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/Enums.cs b/src/GZCTF/Utils/Enums.cs index 849ad1391..2d124aebd 100644 --- a/src/GZCTF/Utils/Enums.cs +++ b/src/GZCTF/Utils/Enums.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace GZCTF; +namespace GZCTF.Utils; /// /// 用户权限枚举 @@ -26,7 +26,7 @@ public enum Role : byte /// /// 管理员权限,可查看系统日志 /// - Admin = 3, + Admin = 3 } /// @@ -90,7 +90,7 @@ public enum TaskStatus : sbyte /// /// 任务线程将要退出 /// - Exit = 5, + Exit = 5 } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -110,7 +110,7 @@ public enum FileType : byte /// /// 远程文件 /// - Remote = 2, + Remote = 2 } /// @@ -169,13 +169,13 @@ public enum NoticeType : byte /// /// 发布新的题目 /// - NewChallenge = 5, + NewChallenge = 5 } public static class SubmissionTypeExtensions { - public static string ToBloodString(this SubmissionType type) - => type switch + public static string ToBloodString(this SubmissionType type) => + type switch { SubmissionType.FirstBlood => "一血", SubmissionType.SecondBlood => "二血", @@ -245,7 +245,7 @@ public enum SubmissionType : byte /// /// 解出 /// - Normal = 4, + Normal = 4 } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -274,7 +274,7 @@ public enum ParticipationStatus : byte /// /// 未提交 /// - Unsubmitted = 4, + Unsubmitted = 4 } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -380,8 +380,8 @@ public enum AnswerResult : byte public static class AnswerResultExtensions { - public static string ToShortString(this AnswerResult result) - => result switch + public static string ToShortString(this AnswerResult result) => + result switch { AnswerResult.FlagSubmitted => "成功提交", AnswerResult.Accepted => "答案正确", @@ -390,4 +390,4 @@ public static string ToShortString(this AnswerResult result) AnswerResult.CheatDetected => "作弊检测", _ => "??" }; -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/ExcelHelper.cs b/src/GZCTF/Utils/ExcelHelper.cs index 13f96ca81..d27ed6c98 100644 --- a/src/GZCTF/Utils/ExcelHelper.cs +++ b/src/GZCTF/Utils/ExcelHelper.cs @@ -6,8 +6,8 @@ namespace GZCTF.Utils; public static class ExcelHelper { - private static readonly string[] CommonScoreboardHeader = ["排名", "战队", "队长", "队员", "学号", "手机号", "解题数量", "得分时间", "总分"]; - private static readonly string[] CommonSubmissionHeader = ["提交状态", "提交时间", "战队", "用户", "题目", "提交内容", "用户邮箱"]; + static readonly string[] CommonScoreboardHeader = { "排名", "战队", "队长", "队员", "学号", "手机号", "解题数量", "得分时间", "总分" }; + static readonly string[] CommonSubmissionHeader = { "提交状态", "提交时间", "战队", "用户", "题目", "提交内容", "用户邮箱" }; public static MemoryStream GetScoreboardExcel(ScoreboardModel scoreboard, Game game) { @@ -15,8 +15,8 @@ public static MemoryStream GetScoreboardExcel(ScoreboardModel scoreboard, Game g throw new ArgumentException("Team is not loaded"); var workbook = new XSSFWorkbook(); - var boardSheet = workbook.CreateSheet("排行榜"); - var headerStyle = GetHeaderStyle(workbook); + ISheet? boardSheet = workbook.CreateSheet("排行榜"); + ICellStyle headerStyle = GetHeaderStyle(workbook); var challIds = WriteBoardHeader(boardSheet, headerStyle, scoreboard, game); WriteBoardContent(boardSheet, scoreboard, challIds, game); @@ -28,8 +28,8 @@ public static MemoryStream GetScoreboardExcel(ScoreboardModel scoreboard, Game g public static MemoryStream GetSubmissionExcel(IEnumerable submissions) { var workbook = new XSSFWorkbook(); - var subSheet = workbook.CreateSheet("全部提交"); - var headerStyle = GetHeaderStyle(workbook); + ISheet? subSheet = workbook.CreateSheet("全部提交"); + ICellStyle headerStyle = GetHeaderStyle(workbook); WriteSubmissionHeader(subSheet, headerStyle); WriteSubmissionContent(subSheet, submissions); @@ -38,10 +38,10 @@ public static MemoryStream GetSubmissionExcel(IEnumerable submission return stream; } - private static ICellStyle GetHeaderStyle(XSSFWorkbook workbook) + static ICellStyle GetHeaderStyle(XSSFWorkbook workbook) { - var style = workbook.CreateCellStyle(); - var boldFontStyle = workbook.CreateFont(); + ICellStyle? style = workbook.CreateCellStyle(); + IFont? boldFontStyle = workbook.CreateFont(); boldFontStyle.IsBold = true; style.SetFont(boldFontStyle); @@ -52,26 +52,26 @@ private static ICellStyle GetHeaderStyle(XSSFWorkbook workbook) return style; } - private static void WriteSubmissionHeader(ISheet sheet, ICellStyle style) + static void WriteSubmissionHeader(ISheet sheet, ICellStyle style) { - var row = sheet.CreateRow(0); + IRow? row = sheet.CreateRow(0); var colIndex = 0; foreach (var col in CommonSubmissionHeader) { - var cell = row.CreateCell(colIndex++); + ICell? cell = row.CreateCell(colIndex++); cell.SetCellValue(col); cell.CellStyle = style; } } - private static void WriteSubmissionContent(ISheet sheet, IEnumerable submissions) + static void WriteSubmissionContent(ISheet sheet, IEnumerable submissions) { var rowIndex = 1; - foreach (var item in submissions) + foreach (Submission item in submissions) { - var row = sheet.CreateRow(rowIndex); + IRow? row = sheet.CreateRow(rowIndex); row.CreateCell(0).SetCellValue(item.Status.ToShortString()); row.CreateCell(1).SetCellValue(item.SubmitTimeUTC.ToString("u")); row.CreateCell(2).SetCellValue(item.TeamName); @@ -84,16 +84,16 @@ private static void WriteSubmissionContent(ISheet sheet, IEnumerable } } - private static int[] WriteBoardHeader(ISheet sheet, ICellStyle style, ScoreboardModel scoreboard, Game game) + static int[] WriteBoardHeader(ISheet sheet, ICellStyle style, ScoreboardModel scoreboard, Game game) { - var row = sheet.CreateRow(0); + IRow? row = sheet.CreateRow(0); var colIndex = 0; var challIds = new List(); var withOrg = game.Organizations is not null && game.Organizations.Count > 0; foreach (var col in CommonScoreboardHeader) { - var cell = row.CreateCell(colIndex++); + ICell? cell = row.CreateCell(colIndex++); cell.SetCellValue(col); cell.CellStyle = style; @@ -105,29 +105,27 @@ private static int[] WriteBoardHeader(ISheet sheet, ICellStyle style, Scoreboard } } - foreach (var type in scoreboard.Challenges) + foreach (KeyValuePair> type in scoreboard.Challenges) + foreach (ChallengeInfo chall in type.Value) { - foreach (var chall in type.Value) - { - var cell = row.CreateCell(colIndex++); - cell.SetCellValue(chall.Title); - cell.CellStyle = style; - challIds.Add(chall.Id); - } + ICell? cell = row.CreateCell(colIndex++); + cell.SetCellValue(chall.Title); + cell.CellStyle = style; + challIds.Add(chall.Id); } return challIds.ToArray(); } - private static void WriteBoardContent(ISheet sheet, ScoreboardModel scoreboard, int[] challIds, Game game) + static void WriteBoardContent(ISheet sheet, ScoreboardModel scoreboard, int[] challIds, Game game) { var rowIndex = 1; var withOrg = game.Organizations is not null && game.Organizations.Count > 0; - foreach (var item in scoreboard.Items) + foreach (ScoreboardItem item in scoreboard.Items) { var colIndex = 0; - var row = sheet.CreateRow(rowIndex); + IRow? row = sheet.CreateRow(rowIndex); row.CreateCell(colIndex++).SetCellValue(item.Rank); row.CreateCell(colIndex++).SetCellValue(item.Name); @@ -137,7 +135,8 @@ private static void WriteBoardContent(ISheet sheet, ScoreboardModel scoreboard, row.CreateCell(colIndex++).SetCellValue(item.TeamInfo!.Captain!.RealName); row.CreateCell(colIndex++).SetCellValue(string.Join("/", item.TeamInfo!.Members.Select(m => m.RealName))); row.CreateCell(colIndex++).SetCellValue(string.Join("/", item.TeamInfo!.Members.Select(m => m.StdNumber))); - row.CreateCell(colIndex++).SetCellValue(string.Join("/", item.TeamInfo!.Members.Select(m => m.PhoneNumber))); + row.CreateCell(colIndex++) + .SetCellValue(string.Join("/", item.TeamInfo!.Members.Select(m => m.PhoneNumber))); row.CreateCell(colIndex++).SetCellValue(item.SolvedCount); row.CreateCell(colIndex++).SetCellValue(item.LastSubmissionTime.ToString("u")); @@ -145,11 +144,11 @@ private static void WriteBoardContent(ISheet sheet, ScoreboardModel scoreboard, foreach (var challId in challIds) { - var chall = item.Challenges.Single(c => c.Id == challId); + ChallengeItem chall = item.Challenges.Single(c => c.Id == challId); row.CreateCell(colIndex++).SetCellValue(chall.Score); } rowIndex++; } } -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/FilePath.cs b/src/GZCTF/Utils/FilePath.cs index f75e7df2e..9740a9b11 100644 --- a/src/GZCTF/Utils/FilePath.cs +++ b/src/GZCTF/Utils/FilePath.cs @@ -1,25 +1,26 @@ namespace GZCTF.Utils; -internal enum DirType : byte +enum DirType : byte { Logs, Uploads, Capture } -internal static class FilePath +static class FilePath { - internal const string Base = "files"; + const string Base = "files"; + + internal static string Logs => GetDir(DirType.Logs); + internal static string Uploads => GetDir(DirType.Uploads); + internal static string Capture => GetDir(DirType.Capture); internal static void EnsureDirs() { foreach (DirType type in Enum.GetValues()) { - string path = Path.Combine(Base, type.ToString().ToLower()); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } + var path = Path.Combine(Base, type.ToString().ToLower()); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); } } @@ -28,12 +29,7 @@ internal static void EnsureDirs() /// /// /// - internal static string GetDir(DirType type) - => Path.Combine(Base, type.ToString().ToLower()); - - internal static string Logs => GetDir(DirType.Logs); - internal static string Uploads => GetDir(DirType.Uploads); - internal static string Capture => GetDir(DirType.Capture); + static string GetDir(DirType type) => Path.Combine(Base, type.ToString().ToLower()); /// /// 获取文件夹内容 @@ -46,9 +42,9 @@ internal static List GetFileRecords(string dir, out long totSize) totSize = 0; var records = new List(); - foreach (string file in Directory.EnumerateFiles(dir, "*", SearchOption.TopDirectoryOnly)) + foreach (var file in Directory.EnumerateFiles(dir, "*", SearchOption.TopDirectoryOnly)) { - var info = new FileInfo(file)!; + var info = new FileInfo(file); records.Add(FileRecord.FromFileInfo(info)); diff --git a/src/GZCTF/Utils/HubHelper.cs b/src/GZCTF/Utils/HubHelper.cs index 8fe3ef480..3ad4870bc 100644 --- a/src/GZCTF/Utils/HubHelper.cs +++ b/src/GZCTF/Utils/HubHelper.cs @@ -11,42 +11,37 @@ public static class HubHelper /// 当前请求 /// 权限 /// - public static async Task HasPrivilege(HttpContext context, Role privilege) + static async Task HasPrivilege(HttpContext context, Role privilege) { var dbContext = context.RequestServices.GetRequiredService(); var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier); - if (dbContext is null || userId is null) + if (userId is null) return false; - var currentUser = await dbContext.Users.FirstOrDefaultAsync(i => i.Id == userId); - - var env = context.RequestServices.GetRequiredService(); + UserInfo? currentUser = await dbContext.Users.FirstOrDefaultAsync(i => i.Id == userId); return currentUser is not null && currentUser.Role >= privilege; } /// - /// 当前请求是否具有权限 + /// 当前请求是否具有权限 /// /// 当前请求 /// - public static Task HasAdmin(HttpContext context) - => HasPrivilege(context, Role.Admin); + public static Task HasAdmin(HttpContext context) => HasPrivilege(context, Role.Admin); /// - /// 当前请求是否具有大于等于权限 + /// 当前请求是否具有大于等于权限 /// /// 当前请求 /// - public static Task HasMonitor(HttpContext context) - => HasPrivilege(context, Role.Monitor); + public static Task HasMonitor(HttpContext context) => HasPrivilege(context, Role.Monitor); /// - /// 当前请求是否具有大于等于权限 + /// 当前请求是否具有大于等于权限 /// /// 当前请求 /// - public static Task HasUser(HttpContext context) - => HasPrivilege(context, Role.User); -} + public static Task HasUser(HttpContext context) => HasPrivilege(context, Role.User); +} \ No newline at end of file diff --git a/src/GZCTF/Utils/LogHelper.cs b/src/GZCTF/Utils/LogHelper.cs index 3d98aa9ff..ae7b8a621 100644 --- a/src/GZCTF/Utils/LogHelper.cs +++ b/src/GZCTF/Utils/LogHelper.cs @@ -9,12 +9,29 @@ using Serilog.Sinks.PostgreSQL; using Serilog.Templates; using Serilog.Templates.Themes; -using LogLevel = Microsoft.Extensions.Logging.LogLevel; +using ILogger = Serilog.ILogger; namespace GZCTF.Utils; public static class LogHelper { + const string LogTemplate = + "[{@t:yy-MM-dd HH:mm:ss.fff} {@l:u3}] {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)}: {@m} {#if Length(Status) > 0}#{Status} <{UserName}>{#if Length(IP) > 0}@{IP}{#end}{#end}\n{@x}"; + + const string InitLogTemplate = "[{@t:yy-MM-dd HH:mm:ss.fff} {@l:u3}] {@m}\n{@x}"; + + static IDictionary ColumnWriters => new Dictionary + { + { "Message", new RenderedMessageColumnWriter() }, + { "Level", new LevelColumnWriter(true, NpgsqlDbType.Varchar) }, + { "TimeUTC", new TimeColumnWriter() }, + { "Exception", new ExceptionColumnWriter() }, + { "Logger", new SinglePropertyColumnWriter("SourceContext", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) }, + { "UserName", new SinglePropertyColumnWriter("UserName", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) }, + { "Status", new SinglePropertyColumnWriter("Status", PropertyWriteMethod.ToString, NpgsqlDbType.Varchar) }, + { "RemoteIP", new SinglePropertyColumnWriter("IP", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) } + }; + /// /// 记录一条系统日志(无用户信息,默认Info) /// @@ -22,8 +39,9 @@ public static class LogHelper /// Log 消息 /// 操作执行结果 /// Log 级别 - public static void SystemLog(this ILogger logger, string msg, TaskStatus status = TaskStatus.Success, LogLevel? level = null) - => Log(logger, msg, "System", string.Empty, status, level ?? LogLevel.Information); + public static void SystemLog(this ILogger logger, string msg, TaskStatus status = TaskStatus.Success, + LogLevel? level = null) => + Log(logger, msg, "System", string.Empty, status, level ?? LogLevel.Information); /// /// 登记一条 Log 记录 @@ -33,8 +51,9 @@ public static void SystemLog(this ILogger logger, string msg, TaskStatus s /// 用户对象 /// 操作执行结果 /// Log 级别 - public static void Log(this ILogger logger, string msg, UserInfo? user, TaskStatus status, LogLevel? level = null) - => Log(logger, msg, user?.UserName ?? "Anonymous", user?.IP ?? "0.0.0.0", status, level); + public static void Log(this ILogger logger, string msg, UserInfo? user, TaskStatus status, + LogLevel? level = null) => + Log(logger, msg, user?.UserName ?? "Anonymous", user?.IP ?? "0.0.0.0", status, level); /// /// 登记一条 Log 记录 @@ -44,10 +63,11 @@ public static void Log(this ILogger logger, string msg, UserInfo? user, Ta /// Http上下文 /// 操作执行结果 /// Log 级别 - public static void Log(this ILogger logger, string msg, HttpContext? context, TaskStatus status, LogLevel? level = null) + public static void Log(this ILogger logger, string msg, HttpContext? context, TaskStatus status, + LogLevel? level = null) { - var ip = context?.Connection?.RemoteIpAddress?.ToString() ?? IPAddress.Loopback.ToString(); - var username = context?.User?.Identity?.Name ?? "Anonymous"; + var ip = context?.Connection.RemoteIpAddress?.ToString() ?? IPAddress.Loopback.ToString(); + var username = context?.User.Identity?.Name ?? "Anonymous"; Log(logger, msg, username, ip, status, level); } @@ -60,8 +80,8 @@ public static void Log(this ILogger logger, string msg, HttpContext? conte /// 连接IP /// 操作执行结果 /// Log 级别 - public static void Log(this ILogger logger, string msg, string ip, TaskStatus status, LogLevel? level = null) - => Log(logger, msg, "Anonymous", ip, status, level); + public static void Log(this ILogger logger, string msg, string ip, TaskStatus status, LogLevel? level = null) => + Log(logger, msg, "Anonymous", ip, status, level); /// /// 登记一条 Log 记录 @@ -72,7 +92,8 @@ public static void Log(this ILogger logger, string msg, string ip, TaskSta /// 当前IP /// 操作执行结果 /// Log 级别 - public static void Log(this ILogger logger, string msg, string uname, string ip, TaskStatus status, LogLevel? level = null) + public static void Log(this ILogger logger, string msg, string uname, string ip, TaskStatus status, + LogLevel? level = null) { using (logger.BeginScope("{UserName}{Status}{IP}", uname, status, ip)) { @@ -80,53 +101,37 @@ public static void Log(this ILogger logger, string msg, string uname, stri } } - public static void UseRequestLogging(this WebApplication app) - { + public static void UseRequestLogging(this WebApplication app) => app.UseSerilogRequestLogging(options => { - options.MessageTemplate = "[{StatusCode}] {Elapsed,8:####0.00}ms HTTP {RequestMethod,-6} {RequestPath} @ {RemoteIP}"; + options.MessageTemplate = + "[{StatusCode}] {Elapsed,8:####0.00}ms HTTP {RequestMethod,-6} {RequestPath} @ {RemoteIP}"; options.GetLevel = (context, time, ex) => context.Response.StatusCode == 204 ? LogEventLevel.Verbose : time > 10000 && context.Response.StatusCode != 101 ? LogEventLevel.Warning : - (context.Response.StatusCode > 499 || ex is not null) ? LogEventLevel.Error : LogEventLevel.Debug; + context.Response.StatusCode > 499 || ex is not null ? LogEventLevel.Error : LogEventLevel.Debug; options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => { diagnosticContext.Set("RemoteIP", httpContext.Connection.RemoteIpAddress); }; }); - } - public static IDictionary ColumnWriters => new Dictionary() - { - {"Message", new RenderedMessageColumnWriter(NpgsqlDbType.Text) }, - {"Level", new LevelColumnWriter(true, NpgsqlDbType.Varchar) }, - {"TimeUTC", new TimeColumnWriter() }, - {"Exception", new ExceptionColumnWriter(NpgsqlDbType.Text) }, - {"Logger", new SinglePropertyColumnWriter("SourceContext", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) }, - {"UserName", new SinglePropertyColumnWriter("UserName", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) }, - {"Status", new SinglePropertyColumnWriter("Status", PropertyWriteMethod.ToString, NpgsqlDbType.Varchar) }, - {"RemoteIP", new SinglePropertyColumnWriter("IP", PropertyWriteMethod.Raw, NpgsqlDbType.Varchar) } - }; - - private const string LogTemplate = "[{@t:yy-MM-dd HH:mm:ss.fff} {@l:u3}] {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)}: {@m} {#if Length(Status) > 0}#{Status} <{UserName}>{#if Length(IP) > 0}@{IP}{#end}{#end}\n{@x}"; - private const string InitLogTemplate = "[{@t:yy-MM-dd HH:mm:ss.fff} {@l:u3}] {@m}\n{@x}"; - - public static Serilog.ILogger GetInitLogger() - => new LoggerConfiguration() + public static ILogger GetInitLogger() => + new LoggerConfiguration() .Enrich.FromLogContext() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("AspNetCoreRateLimit", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning) .WriteTo.Async(t => t.Console( - formatter: new ExpressionTemplate(InitLogTemplate, theme: TemplateTheme.Literate), - restrictedToMinimumLevel: LogEventLevel.Debug + new ExpressionTemplate(InitLogTemplate, theme: TemplateTheme.Literate), + LogEventLevel.Debug )) .CreateBootstrapLogger(); - public static Serilog.ILogger GetLogger(IConfiguration configuration, IServiceProvider serviceProvider) - => new LoggerConfiguration() + public static ILogger GetLogger(IConfiguration configuration, IServiceProvider serviceProvider) => + new LoggerConfiguration() .Enrich.FromLogContext() .Filter.ByExcluding( Matching.WithProperty("RequestPath", v => @@ -136,14 +141,14 @@ public static Serilog.ILogger GetLogger(IConfiguration configuration, IServicePr ) .MinimumLevel.Debug() .Filter.ByExcluding(logEvent => - logEvent.Exception != null && - logEvent.Exception.GetType() == typeof(OperationCanceledException)) + logEvent.Exception != null && + logEvent.Exception.GetType() == typeof(OperationCanceledException)) .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("AspNetCoreRateLimit", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning) .WriteTo.Async(t => t.Console( - formatter: new ExpressionTemplate(LogTemplate, theme: TemplateTheme.Literate), - restrictedToMinimumLevel: LogEventLevel.Debug + new ExpressionTemplate(LogTemplate, theme: TemplateTheme.Literate), + LogEventLevel.Debug )) .WriteTo.Async(t => t.File( path: $"{FilePath.Logs}/log_.log", @@ -156,8 +161,8 @@ public static Serilog.ILogger GetLogger(IConfiguration configuration, IServicePr hooks: new ArchiveHooks(CompressionLevel.Optimal, $"{FilePath.Logs}/archive/{{UtcDate:yyyy-MM}}") )) .WriteTo.Async(t => t.PostgreSQL( - connectionString: configuration.GetConnectionString("Database"), - tableName: "Logs", + configuration.GetConnectionString("Database"), + "Logs", respectCase: true, columnOptions: ColumnWriters, restrictedToMinimumLevel: LogEventLevel.Information, @@ -167,12 +172,7 @@ public static Serilog.ILogger GetLogger(IConfiguration configuration, IServicePr .CreateLogger(); } -public class TimeColumnWriter : ColumnWriterBase +public class TimeColumnWriter() : ColumnWriterBase(NpgsqlDbType.TimestampTz) { - public TimeColumnWriter() : base(NpgsqlDbType.TimestampTz) - { - } - - public override object GetValue(LogEvent logEvent, IFormatProvider? formatProvider = null) - => logEvent.Timestamp.ToUniversalTime(); -} + public override object GetValue(LogEvent logEvent, IFormatProvider? formatProvider = null) => logEvent.Timestamp.ToUniversalTime(); +} \ No newline at end of file diff --git a/src/GZCTF/Utils/PrelaunchHelper.cs b/src/GZCTF/Utils/PrelaunchHelper.cs index 8b1f8917f..dd15b1726 100644 --- a/src/GZCTF/Utils/PrelaunchHelper.cs +++ b/src/GZCTF/Utils/PrelaunchHelper.cs @@ -1,5 +1,4 @@ using GZCTF.Models.Internal; -using IdentityModel.OidcClient; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; @@ -9,9 +8,9 @@ namespace GZCTF.Utils; public static class PrelaunchHelper { - public async static Task RunPrelaunchWork(this WebApplication app) + public static async Task RunPrelaunchWork(this WebApplication app) { - using var serviceScope = app.Services.GetRequiredService().CreateScope(); + using IServiceScope serviceScope = app.Services.GetRequiredService().CreateScope(); var logger = serviceScope.ServiceProvider.GetRequiredService>(); var context = serviceScope.ServiceProvider.GetRequiredService(); @@ -37,10 +36,11 @@ await context.Posts.AddAsync(new() if (app.Environment.IsDevelopment() || app.Configuration.GetSection("ADMIN_PASSWORD").Exists()) { - var usermanager = serviceScope.ServiceProvider.GetRequiredService>(); - var admin = await usermanager.FindByNameAsync("Admin"); - var password = app.Environment.IsDevelopment() ? "Admin@2022" : - app.Configuration.GetValue("ADMIN_PASSWORD"); + var userManager = serviceScope.ServiceProvider.GetRequiredService>(); + UserInfo? admin = await userManager.FindByNameAsync("Admin"); + var password = app.Environment.IsDevelopment() + ? "Admin@2022" + : app.Configuration.GetValue("ADMIN_PASSWORD"); if (admin is null && password is not null) { @@ -53,21 +53,23 @@ await context.Posts.AddAsync(new() RegisterTimeUTC = DateTimeOffset.UtcNow }; - var result = await usermanager.CreateAsync(admin, password); + IdentityResult result = await userManager.CreateAsync(admin, password); if (!result.Succeeded) - logger.SystemLog($"管理员账户创建失败,错误信息:{result.Errors.FirstOrDefault()?.Description}", TaskStatus.Failed, LogLevel.Debug); + logger.SystemLog($"管理员账户创建失败,错误信息:{result.Errors.FirstOrDefault()?.Description}", TaskStatus.Failed, + LogLevel.Debug); } } var containerConfig = serviceScope.ServiceProvider.GetRequiredService>(); - if (containerConfig.Value.EnableTrafficCapture && containerConfig.Value.PortMappingType != ContainerPortMappingType.PlatformProxy) - logger.SystemLog($"在不使用平台代理模式时无法进行流量捕获!", TaskStatus.Failed, LogLevel.Warning); + if (containerConfig.Value.EnableTrafficCapture && + containerConfig.Value.PortMappingType != ContainerPortMappingType.PlatformProxy) + logger.SystemLog("在不使用平台代理模式时无法进行流量捕获!", TaskStatus.Failed, LogLevel.Warning); if (!cache.CacheCheck()) Program.ExitWithFatalMessage("缓存配置无效,请检查 RedisCache 字段配置。如不使用 Redis 请将配置项置空。"); } - public static bool CacheCheck(this IDistributedCache cache) + static bool CacheCheck(this IDistributedCache cache) { try { @@ -79,4 +81,4 @@ public static bool CacheCheck(this IDistributedCache cache) return false; } } -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/CapturableNetworkStream.cs b/src/GZCTF/Utils/RecordableNetworkStream.cs similarity index 69% rename from src/GZCTF/Utils/CapturableNetworkStream.cs rename to src/GZCTF/Utils/RecordableNetworkStream.cs index 8d55f1f10..a02e1c064 100644 --- a/src/GZCTF/Utils/CapturableNetworkStream.cs +++ b/src/GZCTF/Utils/RecordableNetworkStream.cs @@ -8,40 +8,41 @@ namespace GZCTF.Utils; -public class CapturableNetworkStreamOptions +public class RecordableNetworkStreamOptions { /// /// 流量源地址 /// - public IPEndPoint Source { get; set; } = new(0, 0); + public IPEndPoint Source { get; init; } = new(0, 0); /// /// 流量目的地址 /// - public IPEndPoint Dest { get; set; } = new(0, 0); + public IPEndPoint Dest { get; init; } = new(0, 0); /// /// 记录文件位置 /// - public string FilePath { get; set; } = string.Empty; + public string FilePath { get; init; } = string.Empty; /// /// 启用文件流量捕获 /// - public bool EnableCapture { get; set; } = false; + public bool EnableCapture { get; init; } } /// -/// 能够被捕获的网络流(Socket) +/// 捕获网络流(Socket) /// -public sealed class CapturableNetworkStream : NetworkStream +public sealed class RecordableNetworkStream : NetworkStream { - private readonly CapturableNetworkStreamOptions _options; - private readonly CaptureFileWriterDevice? _device = null; - private readonly PhysicalAddress _dummyPhysicalAddress = PhysicalAddress.Parse("00-11-00-11-00-11"); - private readonly IPEndPoint _host = new(0, 65535); + readonly CaptureFileWriterDevice? _device; + readonly PhysicalAddress _dummyPhysicalAddress = PhysicalAddress.Parse("00-11-00-11-00-11"); + readonly IPEndPoint _host = new(0, 65535); + readonly RecordableNetworkStreamOptions _options; - public CapturableNetworkStream(Socket socket, byte[]? metadata, CapturableNetworkStreamOptions options) : base(socket) + public RecordableNetworkStream(Socket socket, byte[]? metadata, RecordableNetworkStreamOptions options) : + base(socket) { _options = options; @@ -55,7 +56,7 @@ public CapturableNetworkStream(Socket socket, byte[]? metadata, CapturableNetwor Directory.CreateDirectory(dir); _device = new(_options.FilePath, FileMode.Open); - _device.Open(LinkLayers.Ethernet); + _device.Open(); if (metadata is not null) WriteCapturedData(_host, _options.Source, metadata); @@ -74,7 +75,8 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation return count; } - public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, + CancellationToken cancellationToken = default) { if (_options.EnableCapture) WriteCapturedData(_options.Source, _options.Dest, buffer); @@ -88,12 +90,9 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella /// 源地址 /// 目的地址 /// 数据 - internal void WriteCapturedData(IPEndPoint source, IPEndPoint dest, ReadOnlyMemory buffer) + void WriteCapturedData(IPEndPoint source, IPEndPoint dest, ReadOnlyMemory buffer) { - var udp = new UdpPacket((ushort)source.Port, (ushort)dest.Port) - { - PayloadDataSegment = new ByteArraySegment(buffer.ToArray()) - }; + var udp = new UdpPacket((ushort)source.Port, (ushort)dest.Port) { PayloadDataSegment = new ByteArraySegment(buffer.ToArray()) }; var packet = new EthernetPacket(_dummyPhysicalAddress, _dummyPhysicalAddress, EthernetType.IPv6) { @@ -110,4 +109,4 @@ public override void Close() base.Close(); _device?.Close(); } -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/Shared.cs b/src/GZCTF/Utils/Shared.cs index c95c56052..4d88195d0 100644 --- a/src/GZCTF/Utils/Shared.cs +++ b/src/GZCTF/Utils/Shared.cs @@ -3,6 +3,8 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +// ReSharper disable NotAccessedPositionalProperty.Global + namespace GZCTF.Utils; public static class ChannelService @@ -55,8 +57,7 @@ public record VerifyResult(SubmissionType SubType, AnswerResult AnsRes); /// 队伍头像 public record TeamModel(int Id, string Name, string? Avatar) { - internal static TeamModel FromTeam(Team team) - => new(team.Id, team.Name, team.AvatarUrl); + internal static TeamModel FromTeam(Team team) => new(team.Id, team.Name, team.AvatarUrl); } /// @@ -67,8 +68,7 @@ internal static TeamModel FromTeam(Team team) /// 题目标签 public record ChallengeModel(int Id, string Title, ChallengeTag Tag) { - internal static ChallengeModel FromChallenge(Challenge chal) - => new(chal.Id, chal.Title, chal.Tag); + internal static ChallengeModel FromChallenge(Challenge chal) => new(chal.Id, chal.Title, chal.Tag); } /// @@ -80,27 +80,22 @@ internal static ChallengeModel FromChallenge(Challenge chal) /// 队伍所属组织 public record ParticipationModel(int Id, TeamModel Team, ParticipationStatus Status, string? Organization) { - internal static ParticipationModel FromParticipation(Participation part) - => new(part.Id, TeamModel.FromTeam(part.Team), part.Status, part.Organization); + internal static ParticipationModel FromParticipation(Participation part) => + new(part.Id, TeamModel.FromTeam(part.Team), part.Status, part.Organization); } /// /// 列表响应 /// /// -public class ArrayResponse where T : class +public class ArrayResponse(T[] array, int? tot = null) + where T : class { - public ArrayResponse(T[] array, int? tot = null) - { - Data = array; - Total = tot ?? array.Length; - } - /// /// 数据 /// [Required] - public T[] Data { get; set; } + public T[] Data { get; set; } = array; /// /// 数据长度 @@ -111,7 +106,7 @@ public ArrayResponse(T[] array, int? tot = null) /// /// 总长度 /// - public int Total { get; set; } + public int Total { get; set; } = tot ?? array.Length; } /// @@ -127,20 +122,14 @@ public class FileRecord /// /// 文件大小 /// - public long Size { get; set; } = 0; + public long Size { get; set; } /// /// 文件修改日期 /// public DateTimeOffset UpdateTime { get; set; } = DateTimeOffset.Now; - internal static FileRecord FromFileInfo(FileInfo info) - => new() - { - FileName = info.Name, - UpdateTime = info.LastWriteTimeUtc, - Size = info.Length, - }; + internal static FileRecord FromFileInfo(FileInfo info) => new() { FileName = info.Name, UpdateTime = info.LastWriteTimeUtc, Size = info.Length }; } /// @@ -149,8 +138,8 @@ internal static FileRecord FromFileInfo(FileInfo info) public struct BloodBonus(long init = BloodBonus.DefaultValue) { public const long DefaultValue = (50 << 20) + (30 << 10) + 10; - public const int Mask = 0x3ff; - public const int Base = 1000; + const int Mask = 0x3ff; + const int Base = 1000; public static BloodBonus Default => new(); @@ -180,4 +169,4 @@ public static BloodBonus FromValue(long value) public static ValueConverter Converter => new(v => v.Val, v => new(v)); public static ValueComparer Comparer => new((a, b) => a.Val == b.Val, c => c.Val.GetHashCode()); -} +} \ No newline at end of file diff --git a/src/GZCTF/Utils/TranslatedIdentityErrorDescriber.cs b/src/GZCTF/Utils/TranslatedIdentityErrorDescriber.cs index 6b942f397..a6f18b0eb 100644 --- a/src/GZCTF/Utils/TranslatedIdentityErrorDescriber.cs +++ b/src/GZCTF/Utils/TranslatedIdentityErrorDescriber.cs @@ -4,201 +4,50 @@ namespace GZCTF.Utils; public class TranslatedIdentityErrorDescriber : IdentityErrorDescriber { - public override IdentityError ConcurrencyFailure() - { - return new IdentityError - { - Code = nameof(ConcurrencyFailure), - Description = "发生并发错误,请稍后再试" - }; - } - - public override IdentityError DefaultError() - { - return new IdentityError - { - Code = nameof(DefaultError), - Description = "发生错误,请稍后再试" - }; - } - - public override IdentityError DuplicateEmail(string email) - { - return new IdentityError - { - Code = nameof(DuplicateEmail), - Description = $"邮箱地址 {email} 已存在" - }; - } - - public override IdentityError DuplicateRoleName(string role) - { - return new IdentityError - { - Code = nameof(DuplicateRoleName), - Description = $"角色名 {role} 已存在" - }; - } - - public override IdentityError DuplicateUserName(string userName) - { - return new IdentityError - { - Code = nameof(DuplicateUserName), - Description = $"用户名 {userName} 已存在" - }; - } - - public override IdentityError InvalidEmail(string? email) - { - return new IdentityError - { - Code = nameof(InvalidEmail), - Description = $"邮箱地址 {email} 无效" - }; - } - - public override IdentityError InvalidRoleName(string? role) - { - return new IdentityError - { - Code = nameof(InvalidRoleName), - Description = $"角色名 {role} 无效" - }; - } - - public override IdentityError InvalidToken() - { - return new IdentityError - { - Code = nameof(InvalidToken), - Description = "验证码无效" - }; - } - - public override IdentityError InvalidUserName(string? userName) - { - return new IdentityError - { - Code = nameof(InvalidUserName), - Description = $"用户名 {userName} 无效" - }; - } - - public override IdentityError LoginAlreadyAssociated() - { - return new IdentityError - { - Code = nameof(LoginAlreadyAssociated), - Description = "登录已经关联" - }; - } - - public override IdentityError PasswordMismatch() - { - return new IdentityError - { - Code = nameof(PasswordMismatch), - Description = "密码输入错误" - }; - } - - public override IdentityError PasswordRequiresDigit() - { - return new IdentityError - { - Code = nameof(PasswordRequiresDigit), - Description = "密码中需要数字" - }; - } - - public override IdentityError PasswordRequiresLower() - { - return new IdentityError - { - Code = nameof(PasswordRequiresLower), - Description = "密码中需要小写字母" - }; - } - - public override IdentityError PasswordRequiresNonAlphanumeric() - { - return new IdentityError - { - Code = nameof(PasswordRequiresNonAlphanumeric), - Description = "密码中需要符号" - }; - } - - public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) - { - return new IdentityError - { - Code = nameof(PasswordRequiresUniqueChars), - Description = $"密码中至少需要 {uniqueChars} 种不同的字符" - }; - } - - public override IdentityError PasswordRequiresUpper() - { - return new IdentityError - { - Code = nameof(PasswordRequiresUpper), - Description = "密码中需要大写字母" - }; - } - - public override IdentityError PasswordTooShort(int length) - { - return new IdentityError - { - Code = nameof(PasswordTooShort), - Description = $"密码长度 {length} 太短" - }; - } - - public override IdentityError RecoveryCodeRedemptionFailed() - { - return new IdentityError - { - Code = nameof(RecoveryCodeRedemptionFailed), - Description = "恢复代码找回失败" - }; - } - - public override IdentityError UserAlreadyHasPassword() - { - return new IdentityError - { - Code = nameof(UserAlreadyHasPassword), - Description = "用户密码已存在" - }; - } - - public override IdentityError UserAlreadyInRole(string role) - { - return new IdentityError - { - Code = nameof(UserAlreadyInRole), - Description = $"用户已在角色 {role} 中" - }; - } - - public override IdentityError UserLockoutNotEnabled() - { - return new IdentityError - { - Code = nameof(UserLockoutNotEnabled), - Description = "用户锁定未启用" - }; - } - - public override IdentityError UserNotInRole(string role) - { - return new IdentityError - { - Code = nameof(UserNotInRole), - Description = $"用户在角色 {role} 中不存在" - }; - } -} + public override IdentityError ConcurrencyFailure() => new() { Code = nameof(ConcurrencyFailure), Description = "发生并发错误,请稍后再试" }; + + public override IdentityError DefaultError() => new() { Code = nameof(DefaultError), Description = "发生错误,请稍后再试" }; + + public override IdentityError DuplicateEmail(string email) => new() { Code = nameof(DuplicateEmail), Description = $"邮箱地址 {email} 已存在" }; + + public override IdentityError DuplicateRoleName(string role) => new() { Code = nameof(DuplicateRoleName), Description = $"角色名 {role} 已存在" }; + + public override IdentityError DuplicateUserName(string userName) => + new() { Code = nameof(DuplicateUserName), Description = $"用户名 {userName} 已存在" }; + + public override IdentityError InvalidEmail(string? email) => new() { Code = nameof(InvalidEmail), Description = $"邮箱地址 {email} 无效" }; + + public override IdentityError InvalidRoleName(string? role) => new() { Code = nameof(InvalidRoleName), Description = $"角色名 {role} 无效" }; + + public override IdentityError InvalidToken() => new() { Code = nameof(InvalidToken), Description = "验证码无效" }; + + public override IdentityError InvalidUserName(string? userName) => new() { Code = nameof(InvalidUserName), Description = $"用户名 {userName} 无效" }; + + public override IdentityError LoginAlreadyAssociated() => new() { Code = nameof(LoginAlreadyAssociated), Description = "登录已经关联" }; + + public override IdentityError PasswordMismatch() => new() { Code = nameof(PasswordMismatch), Description = "密码输入错误" }; + + public override IdentityError PasswordRequiresDigit() => new() { Code = nameof(PasswordRequiresDigit), Description = "密码中需要数字" }; + + public override IdentityError PasswordRequiresLower() => new() { Code = nameof(PasswordRequiresLower), Description = "密码中需要小写字母" }; + + public override IdentityError PasswordRequiresNonAlphanumeric() => + new() { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "密码中需要符号" }; + + public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) => + new() { Code = nameof(PasswordRequiresUniqueChars), Description = $"密码中至少需要 {uniqueChars} 种不同的字符" }; + + public override IdentityError PasswordRequiresUpper() => new() { Code = nameof(PasswordRequiresUpper), Description = "密码中需要大写字母" }; + + public override IdentityError PasswordTooShort(int length) => new() { Code = nameof(PasswordTooShort), Description = $"密码长度 {length} 太短" }; + + public override IdentityError RecoveryCodeRedemptionFailed() => new() { Code = nameof(RecoveryCodeRedemptionFailed), Description = "恢复代码找回失败" }; + + public override IdentityError UserAlreadyHasPassword() => new() { Code = nameof(UserAlreadyHasPassword), Description = "用户密码已存在" }; + + public override IdentityError UserAlreadyInRole(string role) => new() { Code = nameof(UserAlreadyInRole), Description = $"用户已在角色 {role} 中" }; + + public override IdentityError UserLockoutNotEnabled() => new() { Code = nameof(UserLockoutNotEnabled), Description = "用户锁定未启用" }; + + public override IdentityError UserNotInRole(string role) => new() { Code = nameof(UserNotInRole), Description = $"用户在角色 {role} 中不存在" }; +} \ No newline at end of file