Repository: Liu233w/acm-statistics Branch: master Commit: 850666df36ce Files: 529 Total size: 4.7 MB Directory structure: gitextract_va1v6f6n/ ├── .all-contributorsrc ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── .vscode/ │ │ └── settings.json │ ├── mergify.yml │ └── workflows/ │ ├── auto-cancellation.yml │ ├── deploy.yml │ ├── e2e-test-pr.yml │ ├── e2e-test-push.yml │ ├── html-test.yml │ ├── sonar-cloud.yml │ ├── unit-test.yml │ ├── update-e2e-snapshot.yml │ └── update-html-snapshot.yml ├── .gitignore ├── .imgbotconfig ├── .renovaterc.json ├── LICENSE ├── Makefile ├── README.md ├── README_zh-hans.md ├── backend/ │ ├── .config/ │ │ └── dotnet-tools.json │ ├── .dockerignore │ ├── .gitattributes │ ├── .gitignore │ ├── AcmStatisticsBackend.sln │ ├── AcmStatisticsBackend.sln.DotSettings │ ├── Directory.Build.props │ ├── Makefile │ ├── README.md │ ├── StyleCop.ruleset │ ├── dev.Dockerfile │ ├── global.json │ ├── src/ │ │ ├── AcmStatisticsBackend.Application/ │ │ │ ├── Accounts/ │ │ │ │ ├── AccountAppService.cs │ │ │ │ ├── Dto/ │ │ │ │ │ ├── ChangePasswordInput.cs │ │ │ │ │ ├── RegisterInput.cs │ │ │ │ │ └── RegisterOutput.cs │ │ │ │ └── IAccountAppService.cs │ │ │ ├── AcmStatisticsBackend.Application.csproj │ │ │ ├── AcmStatisticsBackendAppServiceBase.cs │ │ │ ├── AcmStatisticsBackendApplicationModule.cs │ │ │ ├── Authorization/ │ │ │ │ └── AbpLoginResultTypeHelper.cs │ │ │ ├── Crawlers/ │ │ │ │ ├── DefaultQueryAppService.cs │ │ │ │ ├── Dto/ │ │ │ │ │ ├── DefaultQueryDto.cs │ │ │ │ │ ├── DeleteQueryHistoryInput.cs │ │ │ │ │ ├── GetAcWorkerHistoryInput.cs │ │ │ │ │ ├── GetQueryHistoryAndSummaryOutput.cs │ │ │ │ │ ├── GetQueryHistoryOutput.cs │ │ │ │ │ ├── GetQuerySummaryInput.cs │ │ │ │ │ ├── QueryCrawlerSummaryDto.cs │ │ │ │ │ ├── QuerySummaryDto.cs │ │ │ │ │ ├── QueryWorkerHistoryDto.cs │ │ │ │ │ ├── SaveOrReplaceQueryHistoryInput.cs │ │ │ │ │ ├── SaveOrReplaceQueryHistoryOutput.cs │ │ │ │ │ └── UsernameInCrawlerDto.cs │ │ │ │ ├── IDefaultQueryAppService.cs │ │ │ │ ├── IQueryHistoryAppService.cs │ │ │ │ └── QueryHistoryAppService.cs │ │ │ ├── Net/ │ │ │ │ └── MimeTypes/ │ │ │ │ └── MimeTypeNames.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── Sessions/ │ │ │ │ ├── Dto/ │ │ │ │ │ ├── ApplicationInfoDto.cs │ │ │ │ │ ├── GetCurrentLoginInformationsOutput.cs │ │ │ │ │ ├── TenantLoginInfoDto.cs │ │ │ │ │ └── UserLoginInfoDto.cs │ │ │ │ ├── ISessionAppService.cs │ │ │ │ └── SessionAppService.cs │ │ │ └── Settings/ │ │ │ ├── Dto/ │ │ │ │ ├── UpdateAutoSaveHistoryInput.cs │ │ │ │ ├── UserSettingsConfigDto.cs │ │ │ │ └── UserTimeZoneDto.cs │ │ │ ├── IUserConfigAppService.cs │ │ │ └── UserConfigAppService.cs │ │ ├── AcmStatisticsBackend.Core/ │ │ │ ├── AcmStatisticsBackend.Core.csproj │ │ │ ├── AcmStatisticsBackendConsts.cs │ │ │ ├── AcmStatisticsBackendCoreModule.cs │ │ │ ├── AcmStatisticsBackendExtensions.cs │ │ │ ├── AppVersionHelper.cs │ │ │ ├── Authorization/ │ │ │ │ ├── AcmStatisticsBackendAuthorizationProvider.cs │ │ │ │ ├── LoginManager.cs │ │ │ │ ├── PermissionChecker.cs │ │ │ │ ├── PermissionNames.cs │ │ │ │ ├── Roles/ │ │ │ │ │ ├── AppRoleConfig.cs │ │ │ │ │ ├── Role.cs │ │ │ │ │ ├── RoleManager.cs │ │ │ │ │ ├── RoleStore.cs │ │ │ │ │ └── StaticRoleNames.cs │ │ │ │ └── Users/ │ │ │ │ ├── User.cs │ │ │ │ ├── UserClaimsPrincipalFactory.cs │ │ │ │ ├── UserDeletingEventHandler.cs │ │ │ │ ├── UserManager.cs │ │ │ │ ├── UserRegistrationManager.cs │ │ │ │ └── UserStore.cs │ │ │ ├── Configuration/ │ │ │ │ ├── AppConfigurations.cs │ │ │ │ ├── AppEnvironmentVariables.cs │ │ │ │ ├── AppSettingNames.cs │ │ │ │ └── AppSettingProvider.cs │ │ │ ├── Crawlers/ │ │ │ │ ├── DefaultQuery.cs │ │ │ │ ├── QueryCrawlerSummary.cs │ │ │ │ ├── QueryHistory.cs │ │ │ │ ├── QuerySummary.cs │ │ │ │ ├── QueryWorkerHistory.cs │ │ │ │ ├── SummaryGenerator.cs │ │ │ │ ├── SummaryWarning.cs │ │ │ │ └── UsernameInCrawler.cs │ │ │ ├── Editions/ │ │ │ │ └── EditionManager.cs │ │ │ ├── Features/ │ │ │ │ └── FeatureValueStore.cs │ │ │ ├── Identity/ │ │ │ │ ├── IdentityRegistrar.cs │ │ │ │ ├── SecurityStampValidator.cs │ │ │ │ └── SignInManager.cs │ │ │ ├── Localization/ │ │ │ │ ├── AcmStatisticsBackendLocalizationConfigurer.cs │ │ │ │ └── SourceFiles/ │ │ │ │ ├── AcmStatisticsBackend-es.xml │ │ │ │ ├── AcmStatisticsBackend-fr.xml │ │ │ │ ├── AcmStatisticsBackend-it.xml │ │ │ │ ├── AcmStatisticsBackend-ja.xml │ │ │ │ ├── AcmStatisticsBackend-lt.xml │ │ │ │ ├── AcmStatisticsBackend-nl.xml │ │ │ │ ├── AcmStatisticsBackend-pt-BR.xml │ │ │ │ ├── AcmStatisticsBackend-tr.xml │ │ │ │ ├── AcmStatisticsBackend-zh-Hans.xml │ │ │ │ └── AcmStatisticsBackend.xml │ │ │ ├── MultiTenancy/ │ │ │ │ ├── Tenant.cs │ │ │ │ └── TenantManager.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── ServiceClients/ │ │ │ │ ├── CaptchaServiceClient.cs │ │ │ │ ├── CaptchaServiceValidateResult.cs │ │ │ │ ├── CrawlerApiBackendClient.cs │ │ │ │ ├── CrawlerMetaItem.cs │ │ │ │ ├── ICaptchaServiceClient.cs │ │ │ │ └── ICrawlerApiBackendClient.cs │ │ │ ├── Settings/ │ │ │ │ └── UserSettingAttribute.cs │ │ │ ├── Timing/ │ │ │ │ └── AppTimes.cs │ │ │ ├── Validation/ │ │ │ │ └── ValidationHelper.cs │ │ │ └── Web/ │ │ │ └── WebContentFolderHelper.cs │ │ ├── AcmStatisticsBackend.EntityFrameworkCore/ │ │ │ ├── AcmStatisticsBackend.EntityFrameworkCore.csproj │ │ │ ├── EntityFrameworkCore/ │ │ │ │ ├── AbpZeroDbMigrator.cs │ │ │ │ ├── AcmStatisticsBackendDbContext.cs │ │ │ │ ├── AcmStatisticsBackendDbContextConfigurer.cs │ │ │ │ ├── AcmStatisticsBackendDbContextFactory.cs │ │ │ │ ├── AcmStatisticsBackendEntityFrameworkModule.cs │ │ │ │ ├── Repositories/ │ │ │ │ │ └── AcmStatisticsBackendRepositoryBase.cs │ │ │ │ └── Seed/ │ │ │ │ ├── Host/ │ │ │ │ │ ├── DefaultEditionCreator.cs │ │ │ │ │ ├── DefaultLanguagesCreator.cs │ │ │ │ │ ├── DefaultSettingsCreator.cs │ │ │ │ │ ├── HostRoleAndUserCreator.cs │ │ │ │ │ └── InitialHostDbBuilder.cs │ │ │ │ ├── SeedHelper.cs │ │ │ │ └── Tenants/ │ │ │ │ ├── DefaultTenantBuilder.cs │ │ │ │ └── TenantRoleAndUserBuilder.cs │ │ │ └── Migrations/ │ │ │ ├── 20200325035348_Init.Designer.cs │ │ │ ├── 20200325035348_Init.cs │ │ │ ├── 20200410093107_AddDefaultQuery.Designer.cs │ │ │ ├── 20200410093107_AddDefaultQuery.cs │ │ │ ├── 20200414102908_AddAcHistory.Designer.cs │ │ │ ├── 20200414102908_AddAcHistory.cs │ │ │ ├── 20200419031052_UseQueryHistory.Designer.cs │ │ │ ├── 20200419031052_UseQueryHistory.cs │ │ │ ├── 20200522145416_AddSettings.Designer.cs │ │ │ ├── 20200522145416_AddSettings.cs │ │ │ ├── 20200604111842_AddSummary.Designer.cs │ │ │ ├── 20200604111842_AddSummary.cs │ │ │ ├── 20210429095008_UpgradeAbp.Designer.cs │ │ │ ├── 20210429095008_UpgradeAbp.cs │ │ │ ├── 20210627092246_RemoveRoleDescription.Designer.cs │ │ │ ├── 20210627092246_RemoveRoleDescription.cs │ │ │ ├── 20210627092411_UpgradeDriver.Designer.cs │ │ │ ├── 20210627092411_UpgradeDriver.cs │ │ │ ├── 20250813025256_UpgradeAbp840.Designer.cs │ │ │ ├── 20250813025256_UpgradeAbp840.cs │ │ │ └── AcmStatisticsBackendDbContextModelSnapshot.cs │ │ ├── AcmStatisticsBackend.Web.Core/ │ │ │ ├── AcmStatisticsBackend.Web.Core.csproj │ │ │ ├── AcmStatisticsBackendWebCoreModule.cs │ │ │ ├── Authentication/ │ │ │ │ └── JwtBearer/ │ │ │ │ ├── JwtTokenMiddleware.cs │ │ │ │ └── TokenAuthConfiguration.cs │ │ │ ├── Configuration/ │ │ │ │ └── HostingEnvironmentExtensions.cs │ │ │ ├── Controllers/ │ │ │ │ ├── AcmStatisticsBackendControllerBase.cs │ │ │ │ └── TokenAuthController.cs │ │ │ ├── Middleware/ │ │ │ │ └── CookieAuthMiddleware.cs │ │ │ ├── Models/ │ │ │ │ └── TokenAuth/ │ │ │ │ ├── AuthenticateModel.cs │ │ │ │ └── AuthenticateResultModel.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ └── AcmStatisticsBackend.Web.Host/ │ │ ├── AcmStatisticsBackend.Web.Host.csproj │ │ ├── Controllers/ │ │ │ └── AntiForgeryController.cs │ │ ├── Dockerfile │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── Startup/ │ │ │ ├── AcmStatisticsBackendWebHostModule.cs │ │ │ ├── AuthConfigurer.cs │ │ │ ├── Program.cs │ │ │ └── Startup.cs │ │ ├── app.config │ │ ├── appsettings.Staging.json │ │ ├── appsettings.json │ │ ├── log4net.config │ │ └── web.config │ ├── stylecop.json │ └── test/ │ └── AcmStatisticsBackend.Tests/ │ ├── Accounts/ │ │ ├── AccountAppService_Tests.cs │ │ └── FakeCaptchaServiceClient.cs │ ├── AcmStatisticsBackend.Tests.csproj │ ├── AcmStatisticsBackendTestBase.cs │ ├── AcmStatisticsBackendTestModule.cs │ ├── Crawlers/ │ │ ├── DefaultQueryAppService_Tests.cs │ │ ├── QueryHistoryAppService_Tests.cs │ │ ├── QuerySummary_ModelTests.cs │ │ └── SummaryGenerator_Tests.cs │ ├── DependencyInjection/ │ │ ├── ServiceCollectionRegistrar.cs │ │ ├── TestClockProvider.cs │ │ └── TestCrawlerApiBackendClient.cs │ ├── MultiTenantFactAttribute.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ServiceClients/ │ │ ├── CaptchaServiceClient_Tests.cs │ │ └── CrawlerApiBackendClient_Tests.cs │ ├── Sessions/ │ │ └── SessionAppService_Tests.cs │ ├── Settings/ │ │ └── UserConfigAppService_TimeZone_Tests.cs │ └── TestExtensions.cs ├── build/ │ ├── .dockerignore │ ├── .gitignore │ ├── commitlint.Dockerfile │ ├── commitlint.mk │ ├── docker-compose.dcproj │ ├── docker-compose.dev-backend.yml │ ├── docker-compose.dev-frontend.yml │ ├── docker-compose.e2e.yml │ ├── docker-compose.mk │ ├── docker-compose.yml │ ├── node-base.Dockerfile │ ├── node-base.mk │ ├── share.mk │ ├── shell.Dockerfile │ ├── shell.mk │ └── template.env ├── captcha-service/ │ ├── .dockerignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── __mocks__/ │ │ └── svg-captcha.js │ ├── __test__/ │ │ ├── app.spec.js │ │ └── interface.test.js │ ├── base.Dockerfile │ ├── package.json │ ├── release.Dockerfile │ └── src/ │ ├── app.js │ ├── index.js │ └── restHelper.js ├── codecov.yml ├── commitlint.config.js ├── crawler/ │ ├── .dockerignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .vscode/ │ │ └── launch.json │ ├── Makefile │ ├── README.md │ ├── __mocks__/ │ │ └── fs.js │ ├── __test__/ │ │ ├── __snapshots__/ │ │ │ └── crawlers.test.js.snap │ │ ├── configReader.test.js │ │ ├── crawlers.test.js │ │ └── functionGenerator.test.js │ ├── base.Dockerfile │ ├── config.yml │ ├── crawlers/ │ │ ├── .eslintrc.js │ │ ├── LICENSE │ │ ├── aizu.js │ │ ├── atcoder.js │ │ ├── bnu.js │ │ ├── codechef.js │ │ ├── codeforces.js │ │ ├── codewars.js │ │ ├── csu.js │ │ ├── dashiye.js │ │ ├── dmoj.js │ │ ├── eljudge.js │ │ ├── fzu.js │ │ ├── hdu.js │ │ ├── leetcode_cn.js │ │ ├── loj.js │ │ ├── luogu.js │ │ ├── nbut.js │ │ ├── nit.js │ │ ├── nod.js │ │ ├── nowcoder.js │ │ ├── poj.js │ │ ├── sdutoj.js │ │ ├── spoj.js │ │ ├── timus.js │ │ ├── uestc.js │ │ ├── uoj.js │ │ ├── uva.js │ │ ├── uvalive.js │ │ ├── vjudge.js │ │ └── zoj.js │ ├── index.js │ ├── lib/ │ │ ├── __mocks__/ │ │ │ └── configReader.js │ │ ├── configReader.js │ │ ├── functionGenerator.js │ │ └── globalProxy.js │ ├── package.json │ └── release.Dockerfile ├── crawler-api-backend/ │ ├── .dockerignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── __mocks__/ │ │ └── crawler.js │ ├── __test__/ │ │ ├── __snapshots__/ │ │ │ └── apiRouter.test.js.snap │ │ └── apiRouter.test.js │ ├── apiRouter.js │ ├── app.js │ ├── base.Dockerfile │ ├── config/ │ │ └── log.js │ ├── index.js │ ├── package.json │ ├── release.Dockerfile │ ├── swagger.json │ └── utils/ │ ├── logUtil.js │ ├── rateLimit.js │ └── restHelper.js ├── e2e/ │ ├── .dockerignore │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmrc │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── __test__/ │ │ └── pages/ │ │ ├── __snapshots__/ │ │ │ └── pages_snapshot.test.js.snap │ │ └── pages_snapshot.test.js │ ├── cypress/ │ │ ├── fixtures/ │ │ │ ├── example.json │ │ │ ├── history_list-max5.json │ │ │ ├── history_list-skip10.json │ │ │ ├── history_list.json │ │ │ ├── poj_notExist.txt │ │ │ ├── poj_ok.txt │ │ │ ├── summary_hdu.txt │ │ │ ├── summary_leetcode.txt │ │ │ └── summary_vjudge.txt │ │ ├── integration/ │ │ │ ├── application/ │ │ │ │ ├── auth-redirect.spec.js │ │ │ │ ├── auto-save-history.spec.js │ │ │ │ ├── default-query.spec.js │ │ │ │ ├── login-and-register.spec.js │ │ │ │ └── swagger.spec.js │ │ │ └── frontend/ │ │ │ ├── about.spec.js │ │ │ ├── history.spec.js │ │ │ ├── index.spec.js │ │ │ ├── login-register.spec.js │ │ │ ├── settings.spec.js │ │ │ ├── side-bar.spec.js │ │ │ └── statistics.spec.js │ │ └── support/ │ │ ├── commands.js │ │ └── e2e.js │ ├── cypress.config.js │ ├── http-mocks/ │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── package.json │ │ └── src/ │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── mock.js │ │ │ └── restClient.js │ │ ├── mocks/ │ │ │ ├── busuanzi.js │ │ │ ├── googleAds.js │ │ │ ├── googleAnalysis.js │ │ │ ├── history-snapshot.js │ │ │ ├── oj.js │ │ │ ├── reset.js │ │ │ └── tajs.js │ │ └── preActivation.js │ ├── jsconfig.json │ └── package.json ├── frontend/ │ ├── .dockerignore │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmrc │ ├── .nuxtignore │ ├── Makefile │ ├── README.md │ ├── __test__/ │ │ ├── StoreContextSimulator.js │ │ ├── components/ │ │ │ ├── MessagePanel.test.js │ │ │ ├── WorkerCard.test.js │ │ │ ├── __snapshots__/ │ │ │ │ ├── MessagePanel.test.js.snap │ │ │ │ └── WorkerCard.test.js.snap │ │ │ ├── statisticsLayoutBuilder.test.js │ │ │ └── statisticsUtils.test.js │ │ ├── e2eMocks/ │ │ │ └── crawler.js │ │ └── store/ │ │ └── statistics.test.js │ ├── app.html │ ├── assets/ │ │ ├── README.md │ │ └── style/ │ │ └── app.scss │ ├── babel.config.js │ ├── base.Dockerfile │ ├── components/ │ │ ├── GithubButton.vue │ │ ├── MessagePanel.vue │ │ ├── README.md │ │ ├── ResultOverlay.vue │ │ ├── UserStatus.vue │ │ ├── WorkerCard.vue │ │ ├── consts.js │ │ ├── rulesMixin.js │ │ ├── statisticsLayoutBuilder.js │ │ ├── statisticsUtils.js │ │ └── utils.js │ ├── configs/ │ │ └── sensitive-url-router.js │ ├── layouts/ │ │ ├── README.md │ │ ├── default.vue │ │ ├── error.vue │ │ ├── login.vue │ │ └── none.vue │ ├── middleware/ │ │ ├── README.md │ │ └── auth.js │ ├── modules/ │ │ └── crawlerLoader/ │ │ ├── README.md │ │ ├── cors.js │ │ └── index.js │ ├── nuxt.config.js │ ├── package.json │ ├── pages/ │ │ ├── README.md │ │ ├── about.vue │ │ ├── history/ │ │ │ ├── _id/ │ │ │ │ ├── -GoHistoryPage.vue │ │ │ │ ├── -HistoryToolbar.vue │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── index.vue │ │ ├── jojo.vue │ │ ├── login.vue │ │ ├── register.vue │ │ ├── settings.vue │ │ └── statistics.vue │ ├── plugins/ │ │ ├── README.md │ │ ├── chartjs.js │ │ ├── debug.js │ │ └── font.js │ ├── release.Dockerfile │ ├── static/ │ │ ├── google90cac42981c276fb.html │ │ └── swagger/ │ │ ├── abp.js │ │ ├── abp.swagger.js │ │ ├── index.html │ │ ├── oauth2-redirect.html │ │ ├── swagger-ui-bundle.js │ │ ├── swagger-ui-standalone-preset.js │ │ ├── swagger-ui.css │ │ └── swagger-ui.js │ ├── store/ │ │ ├── -dynamic/ │ │ │ └── statistics.js │ │ ├── README.md │ │ ├── index.js │ │ ├── message.js │ │ └── session.js │ └── vuetify.options.js ├── ohunt/ │ ├── .config/ │ │ └── dotnet-tools.json │ ├── .dockerignore │ ├── .gitignore │ ├── Makefile │ ├── OHunt.Tests/ │ │ ├── Crawlers/ │ │ │ ├── BnuMappingCrawlerTests.cs │ │ │ ├── NitMappingCrawlerTests.cs │ │ │ ├── UvaMappingCrawlersTests.cs │ │ │ ├── ZojSubmissionCrawlerTests.cs │ │ │ └── __snapshots__/ │ │ │ └── ZojSubmissionCrawlerTests.It_ShouldGetCorrectResult.snap │ │ ├── Dataflow/ │ │ │ ├── CrawlerPropagatorTests.cs │ │ │ ├── DatabaseInserterTests.cs │ │ │ └── SubmissionCrawlerCoordinatorTests.cs │ │ ├── Dependency/ │ │ │ ├── NullDbBuilder.cs │ │ │ ├── OHuntTestBase.cs │ │ │ └── TestWebApplicationFactory.cs │ │ ├── OHunt.Tests.csproj │ │ ├── Services/ │ │ │ └── ProblemLabelManagerTests.cs │ │ ├── TestExtensions.cs │ │ ├── Utils.cs │ │ └── Web/ │ │ ├── ProblemControllerTests.cs │ │ ├── StartupTests.cs │ │ ├── SubmissionControllerTests.cs │ │ ├── SwaggerTests.cs │ │ └── __snapshots__/ │ │ └── SwaggerTests.It_ShouldOutputDocument.snap │ ├── OHunt.Web/ │ │ ├── Controllers/ │ │ │ ├── Dto/ │ │ │ │ ├── ResolveLabelInput.cs │ │ │ │ └── ResolveLabelOutput.cs │ │ │ ├── HomeController.cs │ │ │ ├── ProblemController.cs │ │ │ └── SubmissionsController.cs │ │ ├── Crawlers/ │ │ │ ├── BnuMappingCrawler.cs │ │ │ ├── CrawlerBase.cs │ │ │ ├── CrawlerMessage.cs │ │ │ ├── IMappingCrawler.cs │ │ │ ├── ISubmissionCrawler.cs │ │ │ ├── NitMappingCrawler.cs │ │ │ ├── UvaCrawlers.cs │ │ │ └── ZojSubmissionCrawler.cs │ │ ├── Database/ │ │ │ ├── IDbBuilder.cs │ │ │ ├── OHuntDbBuilder.cs │ │ │ └── OHuntDbContext.cs │ │ ├── Dataflow/ │ │ │ ├── CrawlerPropagator.cs │ │ │ ├── DatabaseInserter.cs │ │ │ ├── DatabaseInserterFactory.cs │ │ │ ├── DatabaseInserterMessage.cs │ │ │ └── SubmissionCrawlerCoordinator.cs │ │ ├── Dockerfile │ │ ├── GlobalConfigurer.cs │ │ ├── Migrations/ │ │ │ ├── 20200701054200_Init.Designer.cs │ │ │ ├── 20200701054200_Init.cs │ │ │ ├── 20200701112402_AddSubmission.Designer.cs │ │ │ ├── 20200701112402_AddSubmission.cs │ │ │ ├── 20200702060356_AddIndex.Designer.cs │ │ │ ├── 20200702060356_AddIndex.cs │ │ │ ├── 20200702142254_AddCrawlerError.Designer.cs │ │ │ ├── 20200702142254_AddCrawlerError.cs │ │ │ ├── 20200802072749_AddProblemLabelMapping.Designer.cs │ │ │ ├── 20200802072749_AddProblemLabelMapping.cs │ │ │ ├── 20210627092639_UpgradeDriver.Designer.cs │ │ │ ├── 20210627092639_UpgradeDriver.cs │ │ │ └── OHuntWebContextModelSnapshot.cs │ │ ├── Models/ │ │ │ ├── CrawlerError.cs │ │ │ ├── MappingOnlineJudge.cs │ │ │ ├── OnlineJudge.cs │ │ │ ├── ProblemLabelMapping.cs │ │ │ ├── RunResult.cs │ │ │ └── Submission.cs │ │ ├── OHunt.Web.csproj │ │ ├── Options/ │ │ │ └── DatabaseInserterOptions.cs │ │ ├── Program.cs │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── Services/ │ │ │ ├── ProblemLabelManager.cs │ │ │ └── ScheduleCrawlerService.cs │ │ ├── Startup.cs │ │ ├── Utils/ │ │ │ ├── Extensions.cs │ │ │ └── QueryParameterFilter.cs │ │ ├── appsettings.Development.json │ │ └── appsettings.json │ ├── README.md │ ├── dev.Dockerfile │ ├── global.json │ └── ohunt.sln ├── sonar-project.properties └── tools/ ├── acm-statistics.service ├── history-test.sql └── remote-docker-up.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "files": [ "README.md" ], "imageSize": 100, "commit": false, "contributors": [ { "login": "Liu233w", "name": "Liu233w", "avatar_url": "https://avatars2.githubusercontent.com/u/16333687?v=4", "profile": "https://liu233w.github.io", "contributions": [ "code", "ideas", "infra", "test" ] }, { "login": "kidozh", "name": "Kido Zhang", "avatar_url": "https://avatars3.githubusercontent.com/u/11661760?v=4", "profile": "https://kidozh.com", "contributions": [ "infra", "ideas" ] }, { "login": "flylai", "name": "flylai", "avatar_url": "https://avatars2.githubusercontent.com/u/9880740?v=4", "profile": "https://github.com/flylai", "contributions": [ "code", "bug" ] }, { "login": "fzu-h4cky", "name": "fzu-h4cky", "avatar_url": "https://avatars3.githubusercontent.com/u/36151020?v=4", "profile": "https://github.com/fzu-h4cky", "contributions": [ "bug" ] }, { "login": "2512821228", "name": "Zhao", "avatar_url": "https://avatars1.githubusercontent.com/u/11994295?v=4", "profile": "http://zhao.wtf", "contributions": [ "bug" ] }, { "login": "cometeme", "name": "Adelard Collins", "avatar_url": "https://avatars0.githubusercontent.com/u/22635759?v=4", "profile": "https://www.cometeme.tech", "contributions": [ "bug" ] }, { "login": "ctuu", "name": "ct", "avatar_url": "https://avatars3.githubusercontent.com/u/22322656?v=4", "profile": "https://github.com/ctuu", "contributions": [ "bug" ] }, { "login": "Geekxiong", "name": "Geekxiong", "avatar_url": "https://avatars3.githubusercontent.com/u/25352156?v=4", "profile": "https://github.com/Geekxiong", "contributions": [ "ideas" ] }, { "login": "Halorv", "name": "Halorv", "avatar_url": "https://avatars2.githubusercontent.com/u/39403985?v=4", "profile": "https://github.com/settings/profile", "contributions": [ "ideas" ] }, { "login": "bodhisatan", "name": "Bodhisatan_Yao", "avatar_url": "https://avatars0.githubusercontent.com/u/35862184?v=4", "profile": "https://github.com/bodhisatan", "contributions": [ "bug" ] }, { "login": "Meulsama", "name": "Meulsama", "avatar_url": "https://avatars1.githubusercontent.com/u/55663936?v=4", "profile": "https://github.com/Meulsama", "contributions": [ "ideas" ] }, { "login": "UserUnknownX", "name": "Michael Xiang", "avatar_url": "https://avatars3.githubusercontent.com/u/50655871?v=4", "profile": "https://github.com/UserUnknownX", "contributions": [ "bug" ] }, { "login": "zby0327", "name": "zby", "avatar_url": "https://avatars2.githubusercontent.com/u/43291744?v=4", "profile": "https://github.com/zby0327", "contributions": [ "ideas", "bug" ] }, { "login": "BackSlashDelta", "name": "BackSlashDelta", "avatar_url": "https://avatars1.githubusercontent.com/u/64258212?v=4", "profile": "https://github.com/BackSlashDelta", "contributions": [ "bug" ] }, { "login": "bluebear4", "name": "bluebear4", "avatar_url": "https://avatars.githubusercontent.com/u/49401963?v=4", "profile": "https://github.com/bluebear4", "contributions": [ "bug" ] }, { "login": "wwawwaww", "name": "wwawwaww", "avatar_url": "https://avatars.githubusercontent.com/u/42441490?v=4", "profile": "https://github.com/wwawwaww", "contributions": [ "bug" ] }, { "login": "dreamerblue", "name": "bLue", "avatar_url": "https://avatars.githubusercontent.com/u/19774268?v=4", "profile": "https://dreamer.blue/", "contributions": [ "code" ] } ], "contributorsPerLine": 6, "contributorTemplate": "\" width=\"<%= options.imageSize %>px;\" alt=\"\"/>
\"><%= contributor.name %>\">🔗
<%= contributions %>", "contributorsSortAlphabetically": true, "projectName": "acm-statistics", "projectOwner": "Liu233w", "repoType": "github", "repoHost": "https://github.com", "skipCi": true, "commitConvention": "none", "commitType": "docs" } ================================================ FILE: .editorconfig ================================================ [*.js] indent_size = 2 ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain # 忽略Migration文件 /backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/* linguist-vendored /ohunt/OHunt.Web/Migrations/* linguist-vendored ================================================ FILE: .github/.vscode/settings.json ================================================ { "cSpell.words": [ "endgroup" ] } ================================================ FILE: .github/mergify.yml ================================================ pull_request_rules: - name: automatic merge on CI success and tag conditions: - label=ready-to-be-merged # checks ===== - check-success=Html Snapshot Test - check-success=E2E on push - check-success=E2E on pull request - check-success=Test Backend - check-success=Test Crawler - check-success=Test Crawler Api Backend - check-success=Test Frontend - check-success=Test Captcha Service - check-success=Test OHunt - check-success=Commitlint # ============= actions: merge: method: rebase # rebase_fallback: merge - name: refactored queue action rule conditions: [] actions: queue: queue_rules: - name: default queue_conditions: - label=ready-to-be-merged - check-success=Html Snapshot Test - check-success=E2E on push - check-success=E2E on pull request - check-success=Test Backend - check-success=Test Crawler - check-success=Test Crawler Api Backend - check-success=Test Frontend - check-success=Test Captcha Service - check-success=Test OHunt - check-success=Commitlint merge_conditions: # Conditions to get out of the queue (= merged) # checks ===== - check-success=Html Snapshot Test - check-success=E2E on push - check-success=E2E on pull request - check-success=Test Backend - check-success=Test Crawler - check-success=Test Crawler Api Backend - check-success=Test Frontend - check-success=Test Captcha Service - check-success=Test OHunt - check-success=Commitlint # ============= merge_method: rebase ================================================ FILE: .github/workflows/auto-cancellation.yml ================================================ name: Cancelling Duplicates on: workflow_run: workflows: ['Test E2E'] types: ['requested'] jobs: cancel-duplicate-workflow-runs: name: "Cancel duplicate workflow runs" runs-on: ubuntu-latest steps: - uses: potiuk/cancel-workflow-runs@master name: "Cancel duplicate workflow runs" with: cancelMode: allDuplicates token: ${{ secrets.GITHUB_TOKEN }} sourceRunId: ${{ github.event.workflow_run.id }} ================================================ FILE: .github/workflows/deploy.yml ================================================ name: auto deploy on master on: push: branches: - master jobs: deploy: runs-on: ubuntu-latest steps: - name: 'Checkout' uses: actions/checkout@v3 - name: Wait for status checks id: check uses: WyriHaximus/github-action-wait-for-status@v1.8 with: ignoreActions: codecov/project,codecov/patch,deploy,E2E on pull request,update-snapshot,Update HTML Snapshot when comment on pr,Update E2E Snapshot when comment on pr,crawler-check,检查爬虫可用性(不准确) checkInterval: 60 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - name: Deploy if: steps.check.outputs.status == 'success' run: | echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin make tag-and-push - name: Failed if: steps.check.outputs.status != 'success' run: | echo deploy check status "${{ steps.check.outputs.status }}" exit 1 ================================================ FILE: .github/workflows/e2e-test-pr.yml ================================================ name: Test E2E on pull request on: pull_request jobs: e2e-pr: name: E2E on pull request runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd e2e echo ::group::build make server compose-args="--detach" make wait-server echo ::endgroup::build make ci-no-record make run run-cmd="npm run lint" make-args="no-interactive no-tty" - uses: actions/upload-artifact@v4 if: failure() with: name: e2e-screenshots path: e2e/cypress/screenshots - uses: actions/upload-artifact@v4 if: failure() with: name: e2e-snapshots path: e2e/cypress/snapshots - uses: actions/upload-artifact@v4 if: failure() with: name: e2e-videos path: e2e/cypress/videos ================================================ FILE: .github/workflows/e2e-test-push.yml ================================================ name: Test E2E on push on: push jobs: e2e-push: name: E2E on push runs-on: ubuntu-latest env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} steps: - uses: actions/checkout@master - run: | cd e2e echo ::group::build make server compose-args="--detach" make wait-server echo ::endgroup::build make ci make run run-cmd="npm run lint" make-args="no-interactive no-tty" - run: | cd build docker compose -f docker-compose.yml -f docker-compose.e2e.yml logs --no-color > e2e.log if: failure() - uses: actions/upload-artifact@v4 if: failure() with: name: server-logs path: build/e2e.log ================================================ FILE: .github/workflows/html-test.yml ================================================ name: Html Snapshot Tests on: [push, pull_request] jobs: html-snapshot-test: name: Html Snapshot Test runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd e2e echo ::group::build make server compose-args="--detach" make wait-server echo ::endgroup::build make test-html-ci ================================================ FILE: .github/workflows/sonar-cloud.yml ================================================ name: Sonar Cloud Analysis on: push: branches: - '**' jobs: sonarCloudTrigger: name: SonarCloud Trigger runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} ================================================ FILE: .github/workflows/unit-test.yml ================================================ name: Unit Tests on: [push, pull_request] jobs: backend: name: Test Backend runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd backend # smoke test and lint make run run-cmd="dotnet build" make-args="no-interactive no-tty" make test-ci crawler: name: Test Crawler runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd crawler make run run-cmd="npm run lint" make-args="no-interactive no-tty" make test-ci crawler-api-backend: name: Test Crawler Api Backend runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd crawler-api-backend make run run-cmd="npm run lint" make-args="no-interactive no-tty" make test-ci frontend: name: Test Frontend runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd frontend make run run-cmd="npm run lint" make-args="no-interactive no-tty" make test-ci captcha-service: name: Test Captcha Service runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd captcha-service make run run-cmd="npm run lint" make-args="no-interactive no-tty" make test-ci ohunt: name: Test OHunt runs-on: ubuntu-latest steps: - uses: actions/checkout@master - run: | cd ohunt # smoke test and lint make run run-cmd="dotnet build" make-args="no-interactive no-tty" make test-ci commitlint: name: Commitlint runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@master with: fetch-depth: 0 - uses: wagoid/commitlint-github-action@9763196e10f27aef304c9b8b660d31d97fce0f99 # v5 ================================================ FILE: .github/workflows/update-e2e-snapshot.yml ================================================ name: Update E2E Snapshot when comment on pr on: issue_comment: types: [created] jobs: update-snapshot: # The type of runner that the job will run on runs-on: ubuntu-latest if: contains(github.event.comment.html_url, '/pull/') && contains(github.event.comment.body, '/update-e2e-snapshot') # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: listen for PR Comments uses: machine-learning-apps/actions-chatops@master with: TRIGGER_PHRASE: "/update-e2e-snapshot" env: # you must supply GITHUB_TOKEN GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} id: prcomm # This step clones the branch of the PR associated with the triggering phrase, but only if it is triggered. - name: clone branch of PR if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: actions/checkout@master with: ref: ${{ steps.prcomm.outputs.BRANCH_NAME }} - name: Show current running workflows' id if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3 with: token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} body: | Update E2E Snapshot Triggered! Address: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - name: Try update snapshot if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' run: | cd e2e echo ::group::build make server compose-args="--detach" make wait-server echo ::endgroup::build make update-snapshot make test # ensure test pass after update - name: Commit result if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' run: | git pull git config --global user.name ${{ github.event.comment.user.login }} git config --global user.email ${{ github.event.comment.user.login }}@github.fake git add . git commit -am 'test(e2e): update snapshot' - name: Push changes if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: ad-m/github-push-action@master with: # use my own token instead of GITHUB_TOKEN to trigger future workflows github_token: ${{ secrets.WORKFLOW_TOKEN }} branch: ${{ steps.prcomm.outputs.BRANCH_NAME }} - name: Upload artifact if failed uses: actions/upload-artifact@v4 if: failure() && steps.prcomm.outputs.BOOL_TRIGGERED == 'true' with: name: e2e-snapshots path: e2e/cypress/snapshots - name: Upload artifact if failed uses: actions/upload-artifact@v4 if: failure() && steps.prcomm.outputs.BOOL_TRIGGERED == 'true' with: name: e2e-videos path: e2e/cypress/videos ================================================ FILE: .github/workflows/update-html-snapshot.yml ================================================ name: Update HTML Snapshot when comment on pr on: issue_comment: types: [created] jobs: update-snapshot: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: listen for PR Comments uses: machine-learning-apps/actions-chatops@master with: TRIGGER_PHRASE: "/update-html-snapshot" env: # you must supply GITHUB_TOKEN GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} id: prcomm # This step clones the branch of the PR associated with the triggering phrase, but only if it is triggered. - name: clone branch of PR if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: actions/checkout@master with: ref: ${{ steps.prcomm.outputs.BRANCH_NAME }} - name: Show current running workflows' id if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3 with: token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} body: | Update HTML Snapshot Triggered! Address: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - name: Try update snapshot if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' run: | cd e2e echo ::group::build make server compose-args="--detach" make wait-server echo ::endgroup::build make update-html-snapshot make test-html-ci # ensure test pass after update - name: Commit result if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' run: | git pull git config --global user.name ${{ github.event.comment.user.login }} git config --global user.email ${{ github.event.comment.user.login }}@github.fake git add . git commit -am 'test(e2e): update html snapshot' - name: Push changes if: steps.prcomm.outputs.BOOL_TRIGGERED == 'true' uses: ad-m/github-push-action@master with: # use my own token instead of GITHUB_TOKEN to trigger future workflows github_token: ${{ secrets.WORKFLOW_TOKEN }} branch: ${{ steps.prcomm.outputs.BRANCH_NAME }} ================================================ FILE: .gitignore ================================================ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries # Sensitive or high-churn files: .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml # Gradle: .idea/**/gradle.xml .idea/**/libraries # CMake cmake-build-debug/ cmake-build-release/ # Mongo Explorer plugin: .idea/**/mongoSettings.xml ## File-based project format: *.iws ## Plugin-specific files: # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Created by https://www.gitignore.io/api/visualstudiocode # Edit at https://www.gitignore.io/?templates=visualstudiocode ### VisualStudioCode ### .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ### VisualStudioCode Patch ### # Ignore all local history of files .history # End of https://www.gitignore.io/api/visualstudiocode # ionide of vscode .ionide # macOS .DS_Store # idea in root /.idea ================================================ FILE: .imgbotconfig ================================================ { "ignoredFiles": [ "e2e/*", ] } ================================================ FILE: .renovaterc.json ================================================ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base", "docker:enableMajor", "monorepo:dotnet" ], "packageRules": [ { "groupName": "aspnetboilerplate", "packagePatterns": ["^Abp\\.|^Abp$"] }, { "groupName": "chartjs", "matchPackageNames": [ "vue-chartjs", "chart.js" ] } ], "ignorePresets": [ ":ignoreModulesAndTests" ], "commitMessagePrefix": "chore(*):", "labels": ["dependencies", "ready-to-be-merged"], "automerge": false, "dockerfile": { "fileMatch": ["(^|/|\\.)Dockerfile$"] } } ================================================ FILE: LICENSE ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) {{ year }} {{ organization }} This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ================================================ FILE: Makefile ================================================ ## root makefile include ./build/share.mk .PHONY: default default: .short-help ; # == common suffix == # use command like `make target=crawler test clean` to invoke `make -C crawler test clean` # support command like `make target="crawler frontend" build` TargetList = crawler frontend crawler-api-backend backend captcha-service e2e ohunt AllTarget := $(if $(target),$(target),$(TargetList)) test: @echo testing target: $(AllTarget) for dir in $(AllTarget); do \ $(MAKE) -C $$dir test; \ done build: @echo building target: $(AllTarget) for dir in $(AllTarget); do \ $(MAKE) -C $$dir build; \ done run: @echo running target: $(AllTarget) for dir in $(AllTarget); do \ $(MAKE) -C $$dir run; \ done clean: # remove all stopped containers docker rm $(shell docker ps -a -q); true for dir in $(AllTarget); do \ $(MAKE) -C $$dir clean; \ done ifeq ($(target),) cd ./build && $(MAKE) -f node-base.mk clean cd ./build && $(MAKE) -f commitlint.mk clean cd ./build && $(MAKE) -f shell.mk clean @echo cleaned all target @echo running docker system prune docker system prune -f else @echo cleaned $(target) endif test-ci: @echo testing ci on target: $(AllTarget) for dir in $(AllTarget); do \ $(MAKE) -C $$dir test-ci; \ done # === commitlint === .PHONY: test-commit test-commit: cd ./build && $(MAKE) -f commitlint.mk test-commit # === publish image === .PHONY: tag-and-push tag-and-push: cd ./build && $(MAKE) -f docker-compose.mk push # === run all === .PHONY: up up: cd ./build && $(MAKE) -f docker-compose.mk up # === util command == .PHONY: show-image-size shell # 输出项目中 latest 标签标记的镜像的大小 show-image-size: docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" --filter=reference='acm-statistics*:latest' shell: cd build && $(MAKE) -f shell.mk shell # === help === .PHONY: help define HELP_MESSAGE Makefile of acm-statistics Available goals: test build run clean test-ci test-commit commitlint-travis tag-and-push up view-image-size shell help You can use `target` variable to set target module when using test, build, run, clean, and test-ci commands. E.g. `make test target="frontend crawler"` means running test only in frontend and crawler module. If target is not specified, run the command on all modules. Besides, the dependency is automatically resolved by makefile. So you do not need to run build before test. Documents of available goals: test Running all tests build build the project or certain modules. If argument `build-args` is specified, it is attached to all `docker build` commands run Run shell command in modules. E.g. `make run run-cmd="pnpm run lint"` runs `npm run lint` in all modules. Available parameters: run-cmd: The command to be run. run-args: The extra arguments sent to docker. E.g. run following commands in fontend directory to send argument -v '...' to docker: >> make run run-cmd="pnpm test -- --update-snapshot" run-args="-v './__test__:/var/project/__test__'" make-args: run-args will automatically send following switches to docker: --rm, --interactive, --tty, which can be turned off by following switches: `r`/`no-rm`, `i`/`no-interactive`, `t`/`no-tty`. E.g. the following command turns `run-args` into `--tty` (`--rm` and `--interactive` are disabled): >> make run make-args="r i" Noticed that commands should be separated even they are single letters. clean Clean images that are built test-ci Run tests in CI environment. It behaves differently than normal tests. E.g. Specifying `--ci` to jest and disabling tests that require network. test-commit Lint commits from master branch to HEAD by commitlint. tag-and-push Tag the built images and publish. By default, it uses `liu233w` as namespace. You may refer to `./build/docker-compose.mk` to change this behaviour. up Run the project using docker-compose. It automatically creates config file `./build/.env`. It is recommended to modify the file based on the comments inside. If you run it on windows, it is recommended to use msys2 shell after configure it to accept the path of windows show-image-size Show the size of all images built by the project. It does not create new images. shell Spawn a shell inside docker container and mount the whole project into it. So you can run commands and modify the project in Linux environment. help Show this doc. Most of the sub-directory supports make commands like the root directory. View the `Makefile` for more information. endef .short-help: @echo run \"make help\" to get help export HELP_MESSAGE help: @echo "$$HELP_MESSAGE" | more ================================================ FILE: README.md ================================================ # This Project will be deprecated. Please use [OJHunt Lite](https://github.com/Liu233w/ojhunt-lite) instead. # This repo contains the source code of OJ Analyzer 简体中文版:[README_zh-hans.md](./README_zh-hans.md) [![Powered by ZenHub](https://img.shields.io/badge/Powered_by-ZenHub-5e60ba.svg)](https://app.zenhub.com/workspace/o/liu233w/acm-statistics/boards?repos=125616473) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=acm-statistics&metric=alert_status)](https://sonarcloud.io/dashboard?id=acm-statistics) [![codecov](https://codecov.io/gh/Liu233w/acm-statistics/branch/master/graph/badge.svg)](https://codecov.io/gh/Liu233w/acm-statistics) [![Cypress.io](https://img.shields.io/badge/cypress.io-tests-green.svg)](https://dashboard.cypress.io/#/projects/4s32o7/runs) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://app.renovatebot.com/dashboard#github/Liu233w/acm-statistics) [![Mergify Status](https://img.shields.io/badge/Mergify-enabled-green.svg)](https://mergify.io) [![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors-) #### Build status ![Unit Tests](https://github.com/Liu233w/acm-statistics/workflows/Unit%20Tests/badge.svg) ![Test E2E](https://github.com/Liu233w/acm-statistics/workflows/Test%20E2E/badge.svg) #### Features - Querying ac/submissions of oj - Storing querying history #### Under development - Email support - Ranks - …… ## Directory structure - frontend: The front end - crawler: Crawlers to query OJs. Being used by both frontend and backend - crawler-api-backend: A microservice that provides querying api - e2e: E2E tests - backend: The back end, a monoservice - captcha-service: A microservice that provides captcha support - ohunt: A stateful, standalone crawler microservice used to support certain OJs such as ZOJ. - build: Codes to build and deploy the project. Tool chain: docker, docker-compose, GNU make. - tools: Utility scripts and config files in operation See the README file in each module for specific documents. ## Developing and deploying in docker - The project needs docker and docker-compose to function correctly. ### Development - This project uses makefile to manage dependency between modules. Execute `make help` in repository root to view document. - GNU make is required. ### Deploy There are two ways to deploy this project in a server. #### One-liner Execute following code in shell to deploy the project to port 3000. `curl -s https://raw.githubusercontent.com/Liu233w/acm-statistics/master/tools/remote-docker-up.sh | bash` Vjudge crawler is not available in this way. #### Config file version In this way you are able to customise the configuration, enabling all features. ```bash # Create a folder to store config files mkdir -p ~/www/acm-statistics cd ~/www/acm-statistics # Download runner script and add permissions curl https://raw.githubusercontent.com/Liu233w/acm-statistics/master/tools/remote-docker-up.sh -o run.sh chmod +x run.sh # Run the script once to generate configuration file. It will exit after the line `.env file created, remember to edit it` is shown. ./run.sh # Edit the config file following the description in it. vim .env # Now we can run the project by the script ./run.sh ``` Then you can use tools such as systemd to run `./run.sh`. [./tools/acm-statistics.service](./tools/acm-statistics.service) is a template config file of systemd. `run.sh` checks updates when it is starting. If there are updates to `template.env`, `run.sh` will exit and ask you to compare these two files. **The script compares the line count of the two files to check update, please make sure they are identical when editing.** ## Management - Set the url of adminer in `.env` file. It is `/adminer` by default. - You can view and edit database via adminer. - The name of the database is `acm_statistics`. Username is `root`. You can set password in `.env` - Backups are created automatically in 3:00am each day, stored in `db-backup` folder, which is in the folder that contains config files. ## License - All source code except the code in `crawler/crawlers` are under AGPL-3.0 license - The code in `crawler/crawlers` are under BSD 2-Clause license. ## Contribution - All contribution especially crawlers are welcomed. - Please follow [Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) when writing git commit messages. - You may use [cz-cli](https://github.com/commitizen/cz-cli) to help writing commit messages. ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

Adelard Collins🔗
🐛

BackSlashDelta🔗
🐛

Bodhisatan_Yao🔗
🐛

Geekxiong🔗
🤔

Halorv🔗
🤔

Kido Zhang🔗
🚇 🤔

Liu233w🔗
💻 🤔 🚇 ⚠️

Meulsama🔗
🤔

Michael Xiang🔗
🐛

Zhao🔗
🐛

bLue🔗
💻

bluebear4🔗
🐛

ct🔗
🐛

flylai🔗
💻 🐛

fzu-h4cky🔗
🐛

wwawwaww🔗
🐛

zby🔗
🤔 🐛
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ================================================ FILE: README_zh-hans.md ================================================ 新版 NWPU-ACM 查询系统 === 中文版文档可能有不准确之处,请以英文版文档为准。 [![Powered by ZenHub](https://img.shields.io/badge/Powered_by-ZenHub-5e60ba.svg)](https://app.zenhub.com/workspace/o/liu233w/acm-statistics/boards?repos=125616473) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=acm-statistics&metric=alert_status)](https://sonarcloud.io/dashboard?id=acm-statistics) [![codecov](https://codecov.io/gh/Liu233w/acm-statistics/branch/master/graph/badge.svg)](https://codecov.io/gh/Liu233w/acm-statistics) [![Cypress.io](https://img.shields.io/badge/cypress.io-tests-green.svg)](https://dashboard.cypress.io/#/projects/4s32o7/runs) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://app.renovatebot.com/dashboard#github/Liu233w/acm-statistics) [![Mergify Status](https://img.shields.io/badge/Mergify-enabled-green.svg)](https://mergify.io) [![All Contributors](https://img.shields.io/badge/all_contributors-14-orange.svg?style=flat-square)](#contributors-) #### 构建状态 ![Unit Tests](https://github.com/Liu233w/acm-statistics/workflows/Unit%20Tests/badge.svg) ![Test E2E](https://github.com/Liu233w/acm-statistics/workflows/Test%20E2E/badge.svg) #### 功能 - 题量查询 #### 开发中 - 历史记录 - 题量追踪 - 邮件提醒 - 排行榜 - 查重 - …… ## 目录结构 - frontend: 前端 - crawler: 题量查询爬虫,可以同时被前端和后端使用 - crawler-api-backend: 题量查询后端,提供了查询API - e2e: 关于 e2e 测试相关的代码。 - backend: 后端代码 - captcha-service: 验证码微服务 - ohunt: 有状态爬虫微服务。负责一些需要用数据库储存状态的爬虫。 - build: 存储了 docker 和 make 相关的代码和配置文件,用于构建和部署 - tools: 存储了部分脚本,各种用途都有 每个模块的具体内容请参考模块内的 README ## docker 方式部署、开发 - 目前的跨模块调用已经改成了基于docker的代码,因此有些功能(比如调用 crawler-api-backend)必须使用 docker 来启动 - 要使用这个功能,必须安装 docker 和 docker-compose ### 开发 - 本项目使用了 makefile 来管理模块间的依赖,请在根目录执行 `make help` 来查看说明。 - 要使用此方式进行开发,开发机还必须安装有 GNU make ### 部署 docker 方式简化了部署难度,这里有两种部署方式。请确保服务器安装了最新版本的 docker 和 docker-compose #### 一行代码版 在 shell 中执行 `curl -s https://raw.githubusercontent.com/Liu233w/acm-statistics/master/tools/remote-docker-up.sh | bash` 即可将整个项目部署到 3000 端口。 这样做的话将无法使用 vjudge 爬虫,所以还是建议使用下面的配置文件版本。 #### 配置文件版 上面的一行代码版无法更改配置,建议用下面的这个配置文件版,按下面的步骤进行部署: ```bash # 建立一个存放脚本和配置文件的文件夹,这里可以随便挑你喜欢的路径 mkdir -p ~/www/acm-statistics cd ~/www/acm-statistics # 下载脚本、添加权限 curl https://raw.githubusercontent.com/Liu233w/acm-statistics/master/tools/remote-docker-up.sh -o run.sh chmod +x run.sh # 试运行脚本以生成配置文件,在显示 `.env file created, remember to edit it` 之后会自动退出脚本 ./run.sh # 编辑配置文件,按照上面的说明进行修改即可 vim .env # 现在即可正常运行脚本 ./run.sh ``` 设置成功之后即可使用单独的 `./run.sh` 来运行脚本,使用 systemd 或者其他工具均可。 `./tools/acm-statistics.service` 里是一个 systemd 配置文件的参考。 如果默认的 `template.env` 有更新,`run.sh` 会自动退出并提示您更新 `.env`。**脚本通过比较两个文件的行数来判断是否有更新,在编辑文件时请确保行数一致** ## 管理 - 在 .env 文件中设定 adminer 的url,默认为 `/adminer` - 可以查看并修改数据库 - 数据库名称为 acm_statistics,用户名为 root,密码在 .env 中设定 - 数据库会在每天3:00am自动进行备份,保存在 `/db-backup` 中 ## 开源协议 - 如无特殊声明,均为 AGPL-3.0 协议 - crawler 模块中的 `crawlers` 目录中的文件为 BSD 2-Clause 协议 ## 贡献代码 - 欢迎任何人贡献代码(尤其是爬虫部分)。 - git 的提交格式遵循 [Git Commit Angular 规范](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) ([中文版](http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html)) - 您可以使用 [cz-cli](https://github.com/commitizen/cz-cli) 来辅助提交 commit ================================================ FILE: backend/.config/dotnet-tools.json ================================================ { "version": 1, "isRoot": true, "tools": { "dotnet-ef": { "version": "7.0.20", "commands": [ "dotnet-ef" ] } } } ================================================ FILE: backend/.dockerignore ================================================ **/.classpath **/.dockerignore **/.env **/.git **/.gitignore **/.project **/.settings **/.toolstarget **/.vs **/.vscode **/*.*proj.user **/*.dbmdl **/*.jfm **/azds.yaml **/bin **/charts **/docker-compose* **/Dockerfile* **/node_modules **/npm-debug.log **/obj **/secrets.dev.yaml **/values.dev.yaml LICENSE README.md **/App_Data # coverage file coverage.cobertura.xml ================================================ FILE: backend/.gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: backend/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignoreable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # App_Data /src/AcmStatisticsBackend.Web.Host/App_Data/* # coverage file coverage.cobertura.xml ================================================ FILE: backend/AcmStatisticsBackend.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29911.84 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F10AA149-2626-486E-85BB-9CD5365F3016}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.Core", "src\AcmStatisticsBackend.Core\AcmStatisticsBackend.Core.csproj", "{0FA75A5B-AB83-4FD0-B545-279774C01E87}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.Application", "src\AcmStatisticsBackend.Application\AcmStatisticsBackend.Application.csproj", "{3870C648-4AEA-4B85-BA3F-F2F63B96136A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.Tests", "test\AcmStatisticsBackend.Tests\AcmStatisticsBackend.Tests.csproj", "{0D4C5D00-C144-4213-A007-4B8944113AB1}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.Web.Host", "src\AcmStatisticsBackend.Web.Host\AcmStatisticsBackend.Web.Host.csproj", "{38E184BD-E874-4633-A947-AED4FDB73F40}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.Web.Core", "src\AcmStatisticsBackend.Web.Core\AcmStatisticsBackend.Web.Core.csproj", "{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AcmStatisticsBackend.EntityFrameworkCore", "src\AcmStatisticsBackend.EntityFrameworkCore\AcmStatisticsBackend.EntityFrameworkCore.csproj", "{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}" EndProject Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "..\build\docker-compose.dcproj", "{5AE26E44-7AFE-4443-AA6E-F3FDF9519BFD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1CD24D5F-EC67-4825-B43D-031CD8027031}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props stylecop.json = stylecop.json StyleCop.ruleset = StyleCop.ruleset EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0FA75A5B-AB83-4FD0-B545-279774C01E87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0FA75A5B-AB83-4FD0-B545-279774C01E87}.Debug|Any CPU.Build.0 = Debug|Any CPU {0FA75A5B-AB83-4FD0-B545-279774C01E87}.Release|Any CPU.ActiveCfg = Release|Any CPU {0FA75A5B-AB83-4FD0-B545-279774C01E87}.Release|Any CPU.Build.0 = Release|Any CPU {3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Debug|Any CPU.Build.0 = Debug|Any CPU {3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Release|Any CPU.ActiveCfg = Release|Any CPU {3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Release|Any CPU.Build.0 = Release|Any CPU {0D4C5D00-C144-4213-A007-4B8944113AB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D4C5D00-C144-4213-A007-4B8944113AB1}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D4C5D00-C144-4213-A007-4B8944113AB1}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D4C5D00-C144-4213-A007-4B8944113AB1}.Release|Any CPU.Build.0 = Release|Any CPU {38E184BD-E874-4633-A947-AED4FDB73F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {38E184BD-E874-4633-A947-AED4FDB73F40}.Debug|Any CPU.Build.0 = Debug|Any CPU {38E184BD-E874-4633-A947-AED4FDB73F40}.Release|Any CPU.ActiveCfg = Release|Any CPU {38E184BD-E874-4633-A947-AED4FDB73F40}.Release|Any CPU.Build.0 = Release|Any CPU {22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Debug|Any CPU.Build.0 = Debug|Any CPU {22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Release|Any CPU.ActiveCfg = Release|Any CPU {22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Release|Any CPU.Build.0 = Release|Any CPU {E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Release|Any CPU.Build.0 = Release|Any CPU {5AE26E44-7AFE-4443-AA6E-F3FDF9519BFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5AE26E44-7AFE-4443-AA6E-F3FDF9519BFD}.Debug|Any CPU.Build.0 = Debug|Any CPU {5AE26E44-7AFE-4443-AA6E-F3FDF9519BFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5AE26E44-7AFE-4443-AA6E-F3FDF9519BFD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {0FA75A5B-AB83-4FD0-B545-279774C01E87} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {3870C648-4AEA-4B85-BA3F-F2F63B96136A} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {0D4C5D00-C144-4213-A007-4B8944113AB1} = {F10AA149-2626-486E-85BB-9CD5365F3016} {38E184BD-E874-4633-A947-AED4FDB73F40} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {22CFE0D2-8DCA-42D7-AD7D-784C3862493F} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {E0580562-F8F2-4EBB-B07A-ABFC6F2C314F} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8C07C326-4D17-4200-88B1-4DD423C6392C} EndGlobalSection EndGlobal ================================================ FILE: backend/AcmStatisticsBackend.sln.DotSettings ================================================  False True True True True True True ================================================ FILE: backend/Directory.Build.props ================================================ ../../StyleCop.ruleset false all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: backend/Makefile ================================================ ## makefile for backend include ../build/share.mk help: @echo run \"make help\" in root directory to get help .base: docker build . \ -f dev.Dockerfile \ -t $(BackendBaseTag) \ $(build-args) build: docker build . \ -f src/AcmStatisticsBackend.Web.Host/Dockerfile \ -t $(BackendTag) \ $(build-args) test: .base docker run --rm -t $(BackendBaseTag) dotnet test run: .base docker run $(run-args) $(BackendBaseTag) $(run-cmd) clean: docker image rm $(BackendTag) $(BackendBaseTag); true test-ci: .base docker run --rm \ -v "$(CURDIR)/test/AcmStatisticsBackend.Tests/TestResults:/src/test/AcmStatisticsBackend.Tests/TestResults" \ $(BackendBaseTag) \ dotnet test --collect:"XPlat Code Coverage" ================================================ FILE: backend/README.md ================================================ # 后端代码 (abp实现) ## 运行环境 - docker docker-compose ## 开发环境 - docker docker-compose (必要) - dotnet core 3.1 - Visual Studio 2019 (安装docker支持) ## 运行方式 本项目不能脱离docker运行。 ### 仅运行 - 仅运行时不需要装有vs 2019或者dotnet core开发环境 - 与其他项目相同,使用 `make build` 进行构建,`make test`进行测试 ### 开发 - 可以直接使用visual studio 2019的container tool进行调试 - 使用vs打开sln文件,将 docker-compose 设为启动项目,然后直接调试即可 - 在进行调试之前,需要先在本目录的上级目录运行 `make build` 来构建其他依赖项 - 在调试状态下,可以从 `localhost:8080` 访问数据库信息 - 在 `../build/.env` 文件中查看和修改默认密码等数据 ================================================ FILE: backend/StyleCop.ruleset ================================================  ================================================ FILE: backend/dev.Dockerfile ================================================ FROM mcr.microsoft.com/dotnet/sdk:8.0 # needed in sln file RUN mkdir /build && echo '' > /build/docker-compose.dcproj WORKDIR /src COPY ["src/AcmStatisticsBackend.Web.Host/AcmStatisticsBackend.Web.Host.csproj", "src/AcmStatisticsBackend.Web.Host/"] COPY ["src/AcmStatisticsBackend.Web.Core/AcmStatisticsBackend.Web.Core.csproj", "src/AcmStatisticsBackend.Web.Core/"] COPY ["src/AcmStatisticsBackend.EntityFrameworkCore/AcmStatisticsBackend.EntityFrameworkCore.csproj", "src/AcmStatisticsBackend.EntityFrameworkCore/"] COPY ["src/AcmStatisticsBackend.Core/AcmStatisticsBackend.Core.csproj", "src/AcmStatisticsBackend.Core/"] COPY ["src/AcmStatisticsBackend.Application/AcmStatisticsBackend.Application.csproj", "src/AcmStatisticsBackend.Application/"] COPY ["test/AcmStatisticsBackend.Tests/AcmStatisticsBackend.Tests.csproj", "test/AcmStatisticsBackend.Tests/"] RUN dotnet restore "src/AcmStatisticsBackend.Web.Host/AcmStatisticsBackend.Web.Host.csproj" RUN dotnet restore "test/AcmStatisticsBackend.Tests/AcmStatisticsBackend.Tests.csproj" COPY . . ================================================ FILE: backend/global.json ================================================ { "sdk": { "version": "8.0.418", "rollForward": "latestMajor", "allowPrerelease": false } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Accounts/AccountAppService.cs ================================================ using System.Diagnostics; using System.Text.RegularExpressions; using System.Threading.Tasks; using Abp.Authorization; using Abp.IdentityFramework; using Abp.Runtime.Session; using Abp.UI; using AcmStatisticsBackend.Accounts.Dto; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.ServiceClients; using Microsoft.AspNetCore.Identity; namespace AcmStatisticsBackend.Accounts { public class AccountAppService : AcmStatisticsBackendAppServiceBase, IAccountAppService { private readonly UserRegistrationManager _userRegistrationManager; private readonly ICaptchaServiceClient _captchaServiceClient; private readonly UserManager _userManager; private readonly IAbpSession _abpSession; private readonly LogInManager _logInManager; private readonly IPasswordHasher _passwordHasher; public AccountAppService( UserRegistrationManager userRegistrationManager, ICaptchaServiceClient captchaServiceClient, UserManager userManager, IAbpSession abpSession, LogInManager logInManager, IPasswordHasher passwordHasher) { _userRegistrationManager = userRegistrationManager; _captchaServiceClient = captchaServiceClient; _userManager = userManager; _abpSession = abpSession; _logInManager = logInManager; _passwordHasher = passwordHasher; } public async Task Register(RegisterInput input) { var captchaResult = await _captchaServiceClient.ValidateAsync(input.CaptchaId, input.CaptchaText); if (!captchaResult.Correct) { throw new UserFriendlyException(captchaResult.ErrorMessage); } await _userRegistrationManager.RegisterAsync( input.UserName, input.Password); return new RegisterOutput { CanLogin = true, }; } /// [AbpAuthorize] public async Task SelfDelete() { var user = await _userManager.GetUserByIdAsync(_abpSession.GetUserId()); var identityResult = await _userManager.DeleteAsync(user); identityResult.CheckErrors(); } /// [AbpAuthorize] public async Task ChangePassword(ChangePasswordInput input) { Debug.Assert(_abpSession.UserId != null, "_abpSession.UserId != null"); var userId = _abpSession.UserId.Value; var user = await _userManager.GetUserByIdAsync(userId); var loginAsync = await _logInManager.LoginAsync(user.UserName, input.CurrentPassword, shouldLockout: false); if (loginAsync.Result != AbpLoginResultType.Success) { throw new UserFriendlyException( "Your 'Existing Password' did not match the one on record. Please try again or contact an administrator for assistance in resetting your password."); } user.Password = _passwordHasher.HashPassword(user, input.NewPassword); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Accounts/Dto/ChangePasswordInput.cs ================================================ using System.ComponentModel.DataAnnotations; namespace AcmStatisticsBackend.Accounts.Dto { public class ChangePasswordInput { [Required] public string CurrentPassword { get; set; } [Required] public string NewPassword { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Accounts/Dto/RegisterInput.cs ================================================ using System.ComponentModel.DataAnnotations; using Abp.Auditing; using Abp.Authorization.Users; namespace AcmStatisticsBackend.Accounts.Dto { public class RegisterInput { [Required] [StringLength(AbpUserBase.MaxUserNameLength)] public string UserName { get; set; } [Required] [StringLength(AbpUserBase.MaxPlainPasswordLength)] [DisableAuditing] public string Password { get; set; } [Required] public string CaptchaText { get; set; } [Required] public string CaptchaId { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Accounts/Dto/RegisterOutput.cs ================================================ namespace AcmStatisticsBackend.Accounts.Dto { public class RegisterOutput { public bool CanLogin { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Accounts/IAccountAppService.cs ================================================ using System.Threading.Tasks; using Abp.Application.Services; using AcmStatisticsBackend.Accounts.Dto; namespace AcmStatisticsBackend.Accounts { public interface IAccountAppService : IApplicationService { Task Register(RegisterInput input); /// /// Delete this account /// Task SelfDelete(); /// /// Change password of current user /// Task ChangePassword(ChangePasswordInput input); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/AcmStatisticsBackend.Application.csproj ================================================ 1.0.0.0 net8.0 AcmStatisticsBackend.Application AcmStatisticsBackend.Application false false false AcmStatisticsBackend bin\AcmStatisticsBackend.Application.xml bin\AcmStatisticsBackend.Application.xml all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: backend/src/AcmStatisticsBackend.Application/AcmStatisticsBackendAppServiceBase.cs ================================================ using System; using System.Threading.Tasks; using Abp.Application.Services; using Abp.IdentityFramework; using Abp.Runtime.Session; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Identity; namespace AcmStatisticsBackend { /// /// Derive your application services from this class. /// public abstract class AcmStatisticsBackendAppServiceBase : ApplicationService { public TenantManager TenantManager { get; set; } public UserManager UserManager { get; set; } protected AcmStatisticsBackendAppServiceBase() { LocalizationSourceName = AcmStatisticsBackendConsts.LocalizationSourceName; } protected virtual async Task GetCurrentUserAsync() { var user = await UserManager.FindByIdAsync(AbpSession.GetUserId().ToString()); if (user == null) { throw new Exception("There is no current user!"); } return user; } protected virtual Task GetCurrentTenantAsync() { return TenantManager.GetByIdAsync(AbpSession.GetTenantId()); } protected virtual void CheckErrors(IdentityResult identityResult) { identityResult.CheckErrors(LocalizationManager); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/AcmStatisticsBackendApplicationModule.cs ================================================ using Abp.AutoMapper; using Abp.Modules; using Abp.Reflection.Extensions; using AcmStatisticsBackend.Authorization; namespace AcmStatisticsBackend { [DependsOn( typeof(AcmStatisticsBackendCoreModule), typeof(AbpAutoMapperModule))] public class AcmStatisticsBackendApplicationModule : AbpModule { public override void PreInitialize() { Configuration.Authorization.Providers.Add(); } public override void Initialize() { var thisAssembly = typeof(AcmStatisticsBackendApplicationModule).GetAssembly(); IocManager.RegisterAssemblyByConvention(thisAssembly); // Scan the assembly for classes which inherit from AutoMapper.Profile Configuration.Modules.AbpAutoMapper().Configurators.Add( cfg => cfg.AddMaps(thisAssembly)); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Authorization/AbpLoginResultTypeHelper.cs ================================================ using System; using Abp; using Abp.Authorization; using Abp.Dependency; using Abp.UI; namespace AcmStatisticsBackend.Authorization { public class AbpLoginResultTypeHelper : AbpServiceBase, ITransientDependency { public AbpLoginResultTypeHelper() { LocalizationSourceName = AcmStatisticsBackendConsts.LocalizationSourceName; } public Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName) { switch (result) { case AbpLoginResultType.Success: return new Exception("Don't call this method with a success result!"); case AbpLoginResultType.InvalidUserNameOrEmailAddress: case AbpLoginResultType.InvalidPassword: return new UserFriendlyException(L("InvalidUserNameOrPassword")); case AbpLoginResultType.InvalidTenancyName: return new UserFriendlyException(L("ThereIsNoTenantDefinedWithName{0}", tenancyName)); case AbpLoginResultType.TenantIsNotActive: return new UserFriendlyException(L("TenantIsNotActive", tenancyName)); case AbpLoginResultType.UserIsNotActive: return new UserFriendlyException(L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress)); case AbpLoginResultType.UserEmailIsNotConfirmed: return new UserFriendlyException(L("UserEmailIsNotConfirmedAndCanNotLogin")); case AbpLoginResultType.LockedOut: return new UserFriendlyException(L("UserLockedOutMessage")); default: // Can not fall to default actually. But other result types can be added in the future and we may forget to handle it Logger.Warn("Unhandled login fail reason: " + result); return new UserFriendlyException(L("LoginFailed")); } } public string CreateLocalizedMessageForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName) { switch (result) { case AbpLoginResultType.Success: throw new Exception("Don't call this method with a success result!"); case AbpLoginResultType.InvalidUserNameOrEmailAddress: case AbpLoginResultType.InvalidPassword: return L("InvalidUserNameOrPassword"); case AbpLoginResultType.InvalidTenancyName: return L("ThereIsNoTenantDefinedWithName{0}", tenancyName); case AbpLoginResultType.TenantIsNotActive: return L("TenantIsNotActive", tenancyName); case AbpLoginResultType.UserIsNotActive: return L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress); case AbpLoginResultType.UserEmailIsNotConfirmed: return L("UserEmailIsNotConfirmedAndCanNotLogin"); default: // Can not fall to default actually. But other result types can be added in the future and we may forget to handle it Logger.Warn("Unhandled login fail reason: " + result); return L("LoginFailed"); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/DefaultQueryAppService.cs ================================================ using System.Diagnostics; using System.Threading.Tasks; using Abp.Authorization; using Abp.Domain.Repositories; using Abp.Extensions; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Crawlers.Dto; namespace AcmStatisticsBackend.Crawlers { /// [AbpAuthorize(PermissionNames.Statistics_DefaultQuery)] public class DefaultQueryAppService : AcmStatisticsBackendAppServiceBase, IDefaultQueryAppService { private readonly IRepository _defaultQueryRepository; public DefaultQueryAppService(IRepository defaultQueryRepository) { _defaultQueryRepository = defaultQueryRepository; } /// public async Task GetDefaultQueries() { var res = await _defaultQueryRepository.FirstOrDefaultAsync(e => e.UserId == AbpSession.UserId.Value); return res == null ? new DefaultQueryDto() : ObjectMapper.Map(res); } /// public async Task SetDefaultQueries(DefaultQueryDto dto) { var entity = ObjectMapper.Map(dto); Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); var userId = AbpSession.UserId.Value; var existEntity = await _defaultQueryRepository.FirstOrDefaultAsync(e => e.UserId == userId); if (existEntity == null) { entity.UserId = userId; await _defaultQueryRepository.InsertAsync(entity); } else { existEntity.MainUsername = entity.MainUsername; existEntity.UsernamesInCrawlers = entity.UsernamesInCrawlers; } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/DefaultQueryDto.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.AutoMapper; using Abp.Runtime.Validation; namespace AcmStatisticsBackend.Crawlers.Dto { /// /// Store default query usernames /// [AutoMap(typeof(DefaultQuery))] public class DefaultQueryDto : ICustomValidate { /// /// main username /// [MinLength(0)] public string MainUsername { get; set; } = ""; /// /// Usernames in each crawlers. Key is the name of crawler, value is a list that contains /// all usernames in this crawler. /// public Dictionary> UsernamesInCrawlers { get; set; } = new Dictionary>(); public void AddValidationErrors(CustomValidationContext context) { foreach (var usernamesInCrawler in UsernamesInCrawlers) { if (usernamesInCrawler.Value == null) { context.Results.Add(new ValidationResult("Items in UsernamesInCrawlers should not be null.")); } } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/DeleteQueryHistoryInput.cs ================================================ using System.Diagnostics.CodeAnalysis; namespace AcmStatisticsBackend.Crawlers.Dto { public class DeleteQueryHistoryInput { /// /// Delete history by certain id. /// public long? Id { get; set; } /// /// Delete histories in the list. /// [MaybeNull] public long[] Ids { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/GetAcWorkerHistoryInput.cs ================================================ using System.ComponentModel.DataAnnotations; namespace AcmStatisticsBackend.Crawlers.Dto { public class GetAcWorkerHistoryInput { [Range(1, long.MaxValue)] public long QueryHistoryId { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/GetQueryHistoryAndSummaryOutput.cs ================================================ using System; using System.ComponentModel.DataAnnotations; namespace AcmStatisticsBackend.Crawlers.Dto { public class GetQueryHistoryAndSummaryOutput { [Range(1, long.MaxValue)] public long HistoryId { get; set; } /// /// The id of the summary. /// /// It can be null if the summary does not exist /// [Range(1, long.MaxValue)] public long? SummaryId { get; set; } [Required] public DateTime CreationTime { get; set; } /// /// Submission count /// /// Is null if summary does not exist. /// public int? Submission { get; set; } /// /// Solved count /// /// Is null if summary does not exist. /// public int? Solved { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/GetQueryHistoryOutput.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.AutoMapper; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMap(typeof(QueryHistory))] public class GetQueryHistoryOutput { [Range(1, long.MaxValue)] public long Id { get; set; } [Required] public DateTime CreationTime { get; set; } /// /// Main username of query history, can be null or empty /// public string MainUsername { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/GetQuerySummaryInput.cs ================================================ using System.ComponentModel.DataAnnotations; namespace AcmStatisticsBackend.Crawlers.Dto { public class GetQuerySummaryInput { [Range(1, long.MaxValue)] public long QueryHistoryId { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/QueryCrawlerSummaryDto.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using AutoMapper; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMap(typeof(QueryCrawlerSummary))] public class QueryCrawlerSummaryDto { /// /// The name of the crawler. Frontend can get its title by this field. /// [Required] public string CrawlerName { get; set; } /// /// Submission count. /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Solved count. /// [Range(0, int.MaxValue)] public int Solved { get; set; } /// /// Usernames used in this crawler /// public ICollection Usernames { get; set; } public bool IsVirtualJudge { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/QuerySummaryDto.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.AutoMapper; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMap(typeof(QuerySummary))] public class QuerySummaryDto { [Range(1, long.MaxValue)] public long QueryHistoryId { get; set; } /// /// When the summary is generated /// public DateTime GenerateTime { get; set; } /// /// Main username, can be null or empty /// public string MainUsername { get; set; } /// /// Query summaries of each crawler. /// [Required] public ICollection QueryCrawlerSummaries { get; set; } /// /// Warnings in summary generation. /// [Required] public ICollection SummaryWarnings { get; set; } /// /// Total submission count /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Total solved count, redundant problems (including problems in virtual_judge) are removed. /// [Range(0, int.MaxValue)] public int Solved { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/QueryWorkerHistoryDto.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using Abp.AutoMapper; using Abp.Runtime.Validation; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMap(typeof(QueryWorkerHistory))] public class QueryWorkerHistoryDto : ICustomValidate { /// /// The name of the crawler. Frontend can get its title by this field. /// [Required] public string CrawlerName { get; set; } /// /// The username used to query this crawler. /// [Required] public string Username { get; set; } /// /// Error message of the crawler. If it's not null, current query is failed, and /// and are all 0. /// [MaybeNull] public string ErrorMessage { get; set; } /// /// Submission count. /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Solved count. /// [Range(0, int.MaxValue)] public int Solved { get; set; } /// /// The list of problem ids that user solved. /// /// Can be null if crawler does not support it. /// [MaybeNull] public string[] SolvedList { get; set; } /// /// Whether current crawler is virtual judge. /// public bool IsVirtualJudge { get; set; } /// /// If is false, this field is null. /// Otherwise, this field contains submissions count in each crawler. /// [MaybeNull] public Dictionary SubmissionsByCrawlerName { get; set; } public void AddValidationErrors(CustomValidationContext context) { if (!string.IsNullOrEmpty(ErrorMessage)) { if (SolvedList != null || SubmissionsByCrawlerName != null) { context.Results.Add( new ValidationResult( "These fields must be null when error message exists", new[] { nameof(SolvedList), nameof(SubmissionsByCrawlerName) })); } return; } if (IsVirtualJudge) { if (SolvedList == null || SubmissionsByCrawlerName == null) { context.Results.Add( new ValidationResult( "These fields should not be null when crawler is virtual judge", new[] { nameof(SolvedList), nameof(SubmissionsByCrawlerName) })); } } else { if (SubmissionsByCrawlerName != null) { context.Results.Add(new ValidationResult( "This field should bu null when crawler is not virtual judge", new[] { nameof(SubmissionsByCrawlerName) })); } } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/SaveOrReplaceQueryHistoryInput.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.AutoMapper; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMapTo(typeof(QueryHistory))] public class SaveOrReplaceQueryHistoryInput { /// /// Main username of query history, can be null or empty /// public string MainUsername { get; set; } /// /// Query history of each crawler. /// public ICollection QueryWorkerHistories { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/SaveOrReplaceQueryHistoryOutput.cs ================================================ using System.ComponentModel.DataAnnotations; namespace AcmStatisticsBackend.Crawlers.Dto { public class SaveOrReplaceQueryHistoryOutput { [Range(1, long.MaxValue)] public long QueryHistoryId { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/Dto/UsernameInCrawlerDto.cs ================================================ using System.ComponentModel.DataAnnotations; using AutoMapper; namespace AcmStatisticsBackend.Crawlers.Dto { [AutoMap(typeof(UsernameInCrawler))] public class UsernameInCrawlerDto { /// /// Which crawler (virtual judge) the username is from. /// /// If it is null or empty string, the username is from /// its own crawler. /// public string FromCrawlerName { get; set; } [Required] public string Username { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/IDefaultQueryAppService.cs ================================================ using System.Threading.Tasks; using Abp.Application.Services; using AcmStatisticsBackend.Crawlers.Dto; namespace AcmStatisticsBackend.Crawlers { /// /// Manage user's default usernames which will be automatically entered in /// statistics page. /// public interface IDefaultQueryAppService : IApplicationService { /// /// Get user's default usernames which will be automatically entered in /// statistics page. /// Task GetDefaultQueries(); /// /// Set user's default usernames which will be automatically entered in /// statistics page. /// Task SetDefaultQueries(DefaultQueryDto dto); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/IQueryHistoryAppService.cs ================================================ using System.Threading.Tasks; using Abp.Application.Services; using Abp.Application.Services.Dto; using AcmStatisticsBackend.Crawlers.Dto; namespace AcmStatisticsBackend.Crawlers { /// /// Manage users' crawler query history /// public interface IQueryHistoryAppService : IApplicationService { /// /// Save a crawler query history, does not validate data. /// /// If there is another record in the same day, the old one is replaced. /// /// The new query history id Task SaveOrReplaceQueryHistory(SaveOrReplaceQueryHistoryInput input); /// /// Delete a query history /// Task DeleteQueryHistory(DeleteQueryHistoryInput input); /// /// Get a list of current user's query history, sorted from newest to oldest. /// Task> GetQueryHistories(PagedResultRequestDto input); /// /// Get all that belong to certain . /// Task> GetQueryWorkerHistories(GetAcWorkerHistoryInput input); /// /// Get query summary of certain query history /// /// input the id of query history Task GetQuerySummary(GetQuerySummaryInput input); /// /// Get a list of current user's query history, sorted from newest to oldest. /// The submission and solved number are also included. /// Task> GetQueryHistoriesAndSummaries(PagedResultRequestDto input); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Crawlers/QueryHistoryAppService.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Abp.Application.Services.Dto; using Abp.Authorization; using Abp.Domain.Repositories; using Abp.Linq.Extensions; using Abp.Timing; using Abp.Timing.Timezone; using Abp.UI; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Crawlers.Dto; using AcmStatisticsBackend.ServiceClients; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.Crawlers { /// [AbpAuthorize(PermissionNames.AcHistory_Histories)] public class QueryHistoryAppService : AcmStatisticsBackendAppServiceBase, IQueryHistoryAppService { private readonly IRepository _acHistoryRepository; private readonly IRepository _acWorkerHistoryRepository; private readonly IRepository _querySummaryRepository; private readonly IRepository _queryCrawlerSummaryRepository; private readonly IClockProvider _clockProvider; private readonly ITimeZoneConverter _timeZoneConverter; private readonly ICrawlerApiBackendClient _crawlerApiBackendClient; private readonly SummaryGenerator _summaryGenerator; public QueryHistoryAppService( IRepository acHistoryRepository, IRepository acWorkerHistoryRepository, IClockProvider clockProvider, ITimeZoneConverter timeZoneConverter, ICrawlerApiBackendClient crawlerApiBackendClient, IRepository querySummaryRepository, IRepository queryCrawlerSummaryRepository, SummaryGenerator summaryGenerator) { _acHistoryRepository = acHistoryRepository; _acWorkerHistoryRepository = acWorkerHistoryRepository; _clockProvider = clockProvider; _timeZoneConverter = timeZoneConverter; _crawlerApiBackendClient = crawlerApiBackendClient; _querySummaryRepository = querySummaryRepository; _queryCrawlerSummaryRepository = queryCrawlerSummaryRepository; _summaryGenerator = summaryGenerator; } /// public async Task SaveOrReplaceQueryHistory( SaveOrReplaceQueryHistoryInput input) { // 添加新记录 var acHistory = ObjectMapper.Map(input); // AutoMapper will change empty array to null. The code below is used to restore them foreach (var (entity, dto) in acHistory.QueryWorkerHistories.Zip(input.QueryWorkerHistories)) { if (dto.SolvedList == null) { entity.SolvedList = null; } if (dto.SubmissionsByCrawlerName == null) { entity.SubmissionsByCrawlerName = null; } } Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); acHistory.UserId = AbpSession.UserId.Value; acHistory.CreationTime = _clockProvider.Now; acHistory.IsReliableSource = false; var crawlerMeta = await _crawlerApiBackendClient.GetCrawlerMeta(); var querySummary = _summaryGenerator.Generate( crawlerMeta, acHistory.QueryWorkerHistories.AsReadOnly()); await RemoveLatestHistoryTheSameDayOf(acHistory.CreationTime); var historyId = await _acHistoryRepository.InsertAndGetIdAsync(acHistory); querySummary.QueryHistoryId = historyId; await _querySummaryRepository.InsertAsync(querySummary); return new SaveOrReplaceQueryHistoryOutput { QueryHistoryId = historyId, }; } private async Task RemoveLatestHistoryTheSameDayOf(DateTime day) { var latestItem = await _acHistoryRepository.GetAll() .Where(e => e.UserId == AbpSession.UserId.Value) .OrderByDescending(e => e.CreationTime) .FirstOrDefaultAsync(); if (latestItem != null) { Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); var currentLocalTime = _timeZoneConverter.Convert( day, AbpSession.TenantId, AbpSession.UserId.Value); var latestItemCreationTimeLocal = _timeZoneConverter.Convert( latestItem.CreationTime, AbpSession.TenantId, AbpSession.UserId.Value); Debug.Assert(currentLocalTime != null, nameof(currentLocalTime) + " != null"); Debug.Assert(latestItemCreationTimeLocal != null, nameof(latestItemCreationTimeLocal) + " != null"); if (latestItemCreationTimeLocal.Value.Date == currentLocalTime.Value.Date) { await DoDeleteHistory(latestItem); } } } /// [HttpPost] public async Task DeleteQueryHistory(DeleteQueryHistoryInput input) { if (input.Id.HasValue) { var entity = await GetAuthorizedEntity(input.Id.Value); await DoDeleteHistory(entity); } if (input.Ids != null) { foreach (var id in input.Ids) { var entity = await GetAuthorizedEntity(id); await DoDeleteHistory(entity); } } } /// public async Task> GetQueryHistories(PagedResultRequestDto input) { var list = await QueryHistoriesOfCurrentUser() .OrderByDescending(e => e.CreationTime) .PageBy(input) .ToListAsync(); var count = await QueryHistoriesOfCurrentUser().CountAsync(); var resultList = ObjectMapper.Map>(list); return new PagedResultDto(count, resultList); } private IQueryable QueryHistoriesOfCurrentUser() { return _acHistoryRepository.GetAll() .Where(e => e.UserId == AbpSession.UserId.Value); } /// public async Task> GetQueryWorkerHistories(GetAcWorkerHistoryInput input) { var queryHistory = await GetAuthorizedEntity(input.QueryHistoryId); var entityList = await _acWorkerHistoryRepository.GetAll() .Where(e => e.QueryHistoryId == queryHistory.Id) .ToListAsync(); var list = ObjectMapper.Map>(entityList); // AutoMapper will change empty array to null. The code below is used to restore them foreach (var (dto, entity) in list.Zip(entityList)) { if (entity.SolvedList == null) { dto.SolvedList = null; } if (entity.SubmissionsByCrawlerName == null) { dto.SubmissionsByCrawlerName = null; } } return new ListResultDto(list); } /// public async Task GetQuerySummary(GetQuerySummaryInput input) { var history = await GetAuthorizedEntity(input.QueryHistoryId); var summary = await _querySummaryRepository.FirstOrDefaultAsync( e => e.QueryHistoryId == history.Id); if (summary == null) { throw new UserFriendlyException("This query history does not have summary"); } var queryCrawlerSummary = await _queryCrawlerSummaryRepository.GetAllIncluding( e => e.Usernames) .Where(e => e.QuerySummaryId == summary.Id) .ToListAsync(); var querySummaryDto = ObjectMapper.Map(summary); querySummaryDto.QueryCrawlerSummaries = ObjectMapper.Map>(queryCrawlerSummary); querySummaryDto.MainUsername = history.MainUsername; return querySummaryDto; } /// public async Task> GetQueryHistoriesAndSummaries( PagedResultRequestDto input) { var list = await (from h in QueryHistoriesOfCurrentUser() .OrderByDescending(e => e.CreationTime) .PageBy(input) join s in _querySummaryRepository.GetAll() on h.Id equals s.Id into grouping from s in grouping.DefaultIfEmpty() select new GetQueryHistoryAndSummaryOutput { HistoryId = h.Id, SummaryId = s.Id, CreationTime = h.CreationTime, Solved = s.Solved == 0 && s.Submission == 0 ? null : s.Solved, Submission = s.Solved == 0 && s.Submission == 0 ? null : s.Submission, }).ToListAsync(); var count = await QueryHistoriesOfCurrentUser().CountAsync(); return new PagedResultDto(count, list); } /// /// 根据ID获取对象,并检查权限。 /// /// AcHistory的ID /// AcHistory /// 如果该对象不是由此用户创建,抛出异常 private async Task GetAuthorizedEntity(long id) { var acHistory = await _acHistoryRepository.GetAsync(id); if (acHistory.UserId != AbpSession.UserId) { throw new AbpAuthorizationException("You do not have permissions to visit the entity."); } return acHistory; } /// /// 移除 AcHistory 和与其关联的 AcWorkerHistory,不检查用户是否有权限访问这个Entity /// private async Task DoDeleteHistory(QueryHistory entity) { await _acHistoryRepository.DeleteAsync(entity); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Net/MimeTypes/MimeTypeNames.cs ================================================ using System; namespace AcmStatisticsBackend.Net.MimeTypes { /* Copied from: * http://stackoverflow.com/questions/10362140/asp-mvc-are-there-any-constants-for-the-default-content-types */ /// /// Common mime types. /// public static class MimeTypeNames { /// Used to denote the encoding necessary for files containing JavaScript source code. The alternative MIME type for this file type is text/javascript. public const string ApplicationXJavascript = "application/x-javascript"; /// 24bit Linear PCM audio at 8-48kHz, 1-N channels; Defined in RFC 3190. public const string AudioL24 = "audio/L24"; /// Adobe Flash files for example with the extension .swf. public const string ApplicationXShockwaveFlash = "application/x-shockwave-flash"; /// Arbitrary binary data.[5] Generally speaking this type identifies files that are not associated with a specific application. Contrary to past assumptions by software packages such as Apache this is not a type that should be applied to unknown files. In such a case, a server or application should not indicate a content type, as it may be incorrect, but rather, should omit the type in order to allow the recipient to guess the type.[6]. public const string ApplicationOctetStream = "application/octet-stream"; /// Atom feeds. public const string ApplicationAtomXml = "application/atom+xml"; /// Cascading Style Sheets; Defined in RFC 2318. public const string TextCss = "text/css"; /// commands; subtype resident in Gecko browsers like Firefox 3.5. public const string TextCmd = "text/cmd"; /// Comma-separated values; Defined in RFC 4180. public const string TextCsv = "text/csv"; /// deb (file format), a software package format used by the Debian project. public const string ApplicationXDeb = "application/x-deb"; /// Defined in RFC 1847. public const string MultipartEncrypted = "multipart/encrypted"; /// Defined in RFC 1847. public const string MultipartSigned = "multipart/signed"; /// Defined in RFC 2616. public const string MessageHttp = "message/http"; /// Defined in RFC 4735. public const string ModelExample = "model/example"; /// device-independent document in DVI format. public const string ApplicationXDvi = "application/x-dvi"; /// DTD files; Defined by RFC 3023. public const string ApplicationXmlDtd = "application/xml-dtd"; /// ECMAScript/JavaScript; Defined in RFC 4329 (equivalent to application/ecmascript but with looser processing rules) It is not accepted in IE 8 or earlier - text/javascript is accepted but it is defined as obsolete in RFC 4329. The "type" attribute of the. <script> tag in HTML5 is optional and in practice omitting the media type of JavaScript programs is the most interoperable solution since all browsers have always assumed the correct default even before HTML5. public const string ApplicationJavascript = "application/javascript"; /// ECMAScript/JavaScript; Defined in RFC 4329 (equivalent to application/javascript but with stricter processing rules). public const string ApplicationEcmascript = "application/ecmascript"; /// EDI EDIFACT data; Defined in RFC 1767. public const string ApplicationEdifact = "application/EDIFACT"; /// EDI X12 data; Defined in RFC 1767. public const string ApplicationEdiX12 = "application/EDI-X12"; /// Email; Defined in RFC 2045 and RFC 2046. public const string MessagePartial = "message/partial"; /// Email; EML files, MIME files, MHT files, MHTML files; Defined in RFC 2045 and RFC 2046. public const string MessageRfc822 = "message/rfc822"; /// Extensible Markup Language; Defined in RFC 3023. public const string TextXml = "text/xml"; /// Flash video (FLV files). public const string VideoXFlv = "video/x-flv"; /// GIF image; Defined in RFC 2045 and RFC 2046. public const string ImageGif = "image/gif"; /// GoogleWebToolkit data. public const string TextXGwtRpc = "text/x-gwt-rpc"; /// Gzip. public const string ApplicationXGzip = "application/x-gzip"; /// HTML; Defined in RFC 2854. public const string TextHtml = "text/html"; /// ICO image; Registered[9]. public const string ImageVndMicrosoftIcon = "image/vnd.microsoft.icon"; /// IGS files, IGES files; Defined in RFC 2077. public const string ModelIges = "model/iges"; /// IMDN Instant Message Disposition Notification; Defined in RFC 5438. public const string MessageImdnXml = "message/imdn+xml"; /// JavaScript Object Notation JSON; Defined in RFC 4627. public const string ApplicationJson = "application/json"; /// JavaScript Object Notation (JSON) Patch; Defined in RFC 6902. public const string ApplicationJsonPatch = "application/json-patch+json"; /// JavaScript - Defined in and obsoleted by RFC 4329 in order to discourage its usage in favor of application/javascript. However,text/javascript is allowed in HTML 4 and 5 and, unlike application/javascript, has cross-browser support. The "type" attribute of the. <script> tag in HTML5 is optional and there is no need to use it at all since all browsers have always assumed the correct default (even in HTML 4 where it was required by the specification). [Obsolete] public const string TextJavascript = "text/javascript"; /// JPEG JFIF image; Associated with Internet Explorer; Listed in ms775147(v=vs.85) - Progressive JPEG, initiated before global browser support for progressive JPEGs (Microsoft and Firefox). public const string ImagePjpeg = "image/pjpeg"; /// JPEG JFIF image; Defined in RFC 2045 and RFC 2046. public const string ImageJpeg = "image/jpeg"; /// jQuery template data. public const string TextXJqueryTmpl = "text/x-jquery-tmpl"; /// KML files (e.g. for Google Earth). public const string ApplicationVndGoogleEarthKmlXml = "application/vnd.google-earth.kml+xml"; /// LaTeX files. public const string ApplicationXLatex = "application/x-latex"; /// Matroska open media format. public const string VideoXMatroska = "video/x-matroska"; /// Microsoft Excel 2007 files. public const string ApplicationVndOpenxmlformatsOfficedocumentSpreadsheetmlSheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; /// Microsoft Excel files. public const string ApplicationVndMsExcel = "application/vnd.ms-excel"; /// Microsoft Powerpoint 2007 files. public const string ApplicationVndOpenxmlformatsOfficedocumentPresentationmlPresentation = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; /// Microsoft Powerpoint files. public const string ApplicationVndMsPowerpoint = "application/vnd.ms-powerpoint"; /// Microsoft Word 2007 files. public const string ApplicationVndOpenxmlformatsOfficedocumentWordprocessingmlDocument = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; /// Microsoft Word files[15]. public const string ApplicationMsword = "application/msword"; /// MIME Email; Defined in RFC 2045 and RFC 2046. public const string MultipartAlternative = "multipart/alternative"; /// MIME Email; Defined in RFC 2045 and RFC 2046. public const string MultipartMixed = "multipart/mixed"; /// MIME Email; Defined in RFC 2387 and used by MHTML (HTML mail). public const string MultipartRelated = "multipart/related"; /// MIME Webform; Defined in RFC 2388. public const string MultipartFormData = "multipart/form-data"; /// Mozilla XUL files. public const string ApplicationVndMozillaXulXml = "application/vnd.mozilla.xul+xml"; /// MP3 or other MPEG audio; Defined in RFC 3003. public const string AudioMpeg = "audio/mpeg"; /// MP4 audio. public const string AudioMp4 = "audio/mp4"; /// MP4 video; Defined in RFC 4337. public const string VideoMp4 = "video/mp4"; /// MPEG-1 video with multiplexed audio; Defined in RFC 2045 and RFC 2046. public const string VideoMpeg = "video/mpeg"; /// MSH files, MESH files; Defined in RFC 2077, SILO files. public const string ModelMesh = "model/mesh"; /// mulaw audio at 8 kHz, 1 channel; Defined in RFC 2046. public const string AudioBasic = "audio/basic"; /// Ogg Theora or other video (with audio); Defined in RFC 5334. public const string VideoOgg = "video/ogg"; /// Ogg Vorbis, Speex, Flac and other audio; Defined in RFC 5334. public const string AudioOgg = "audio/ogg"; /// Ogg, a multimedia bitstream container format; Defined in RFC 5334. public const string ApplicationOgg = "application/ogg"; /// OP. public const string ApplicationXopXml = "application/xop+xml"; /// OpenDocument Graphics; Registered[14]. public const string ApplicationVndOasisOpendocumentGraphics = "application/vnd.oasis.opendocument.graphics"; /// OpenDocument Presentation; Registered[13]. public const string ApplicationVndOasisOpendocumentPresentation = "application/vnd.oasis.opendocument.presentation"; /// OpenDocument Spreadsheet; Registered[12]. public const string ApplicationVndOasisOpendocumentSpreadsheet = "application/vnd.oasis.opendocument.spreadsheet"; /// OpenDocument Text; Registered[11]. public const string ApplicationVndOasisOpendocumentText = "application/vnd.oasis.opendocument.text"; /// p12 files. public const string ApplicationXPkcs12 = "application/x-pkcs12"; /// p7b and spc files. public const string ApplicationXPkcs7Certificates = "application/x-pkcs7-certificates"; /// p7c files. public const string ApplicationXPkcs7Mime = "application/x-pkcs7-mime"; /// p7r files. public const string ApplicationXPkcs7Certreqresp = "application/x-pkcs7-certreqresp"; /// p7s files. public const string ApplicationXPkcs7Signature = "application/x-pkcs7-signature"; /// Portable Document Format, PDF has been in use for document exchange on the Internet since 1993; Defined in RFC 3778. public const string ApplicationPdf = "application/pdf"; /// Portable Network Graphics; Registered,[8] Defined in RFC 2083. public const string ImagePng = "image/png"; /// PostScript; Defined in RFC 2046. public const string ApplicationPostscript = "application/postscript"; /// QuickTime video; Registered[10]. public const string VideoQuicktime = "video/quicktime"; /// RAR archive files. public const string ApplicationXRarCompressed = "application/x-rar-compressed"; /// RealAudio; Documented in RealPlayer Customer Support Answer 2559. public const string AudioVndRnRealaudio = "audio/vnd.rn-realaudio"; /// Resource Description Framework; Defined by RFC 3870. public const string ApplicationRdfXml = "application/rdf+xml"; /// RSS feeds. public const string ApplicationRssXml = "application/rss+xml"; /// SOAP; Defined by RFC 3902. public const string ApplicationSoapXml = "application/soap+xml"; /// StuffIt archive files. public const string ApplicationXStuffit = "application/x-stuffit"; /// SVG vector image; Defined in SVG Tiny 1.2 Specification Appendix M. public const string ImageSvgXml = "image/svg+xml"; /// Tag Image File Format (only for Baseline TIFF); Defined in RFC 3302. public const string ImageTiff = "image/tiff"; /// Tarball files. public const string ApplicationXTar = "application/x-tar"; /// Textual data; Defined in RFC 2046 and RFC 3676. public const string TextPlain = "text/plain"; /// TrueType Font No registered MIME type, but this is the most commonly used. public const string ApplicationXFontTtf = "application/x-font-ttf"; /// vCard (contact information); Defined in RFC 6350. public const string TextVcard = "text/vcard"; /// Vorbis encoded audio; Defined in RFC 5215. public const string AudioVorbis = "audio/vorbis"; /// WAV audio; Defined in RFC 2361. public const string AudioVndWave = "audio/vnd.wave"; /// Web Open Font Format; (candidate recommendation; use application/x-font-woff until standard is official). public const string ApplicationFontWoff = "application/font-woff"; /// WebM Matroska-based open media format. public const string VideoWebm = "video/webm"; /// WebM open media format. public const string AudioWebm = "audio/webm"; /// Windows Media Audio Redirector; Documented in Microsoft help page. public const string AudioXMsWax = "audio/x-ms-wax"; /// Windows Media Audio; Documented in Microsoft KB 288102. public const string AudioXMsWma = "audio/x-ms-wma"; /// Windows Media Video; Documented in Microsoft KB 288102. public const string VideoXMsWmv = "video/x-ms-wmv"; /// WRL files, VRML files; Defined in RFC 2077. public const string ModelVrml = "model/vrml"; /// X3D ISO standard for representing 3D computer graphics, X3D XML files. public const string ModelX3DXml = "model/x3d+xml"; /// X3D ISO standard for representing 3D computer graphics, X3DB binary files. public const string ModelX3DBinary = "model/x3d+binary"; /// X3D ISO standard for representing 3D computer graphics, X3DV VRML files. public const string ModelX3DVrml = "model/x3d+vrml"; /// XHTML; Defined by RFC 3236. public const string ApplicationXhtmlXml = "application/xhtml+xml"; /// ZIP archive files; Registered[7]. public const string ApplicationZip = "application/zip"; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AcmStatisticsBackend.Application")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("3870c648-4aea-4b85-ba3f-f2f63b96136a")] ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/Dto/ApplicationInfoDto.cs ================================================ using System; using System.Collections.Generic; namespace AcmStatisticsBackend.Sessions.Dto { public class ApplicationInfoDto { public string Version { get; set; } public DateTime ReleaseDate { get; set; } public Dictionary Features { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/Dto/GetCurrentLoginInformationsOutput.cs ================================================ namespace AcmStatisticsBackend.Sessions.Dto { public class GetCurrentLoginInformationsOutput { public ApplicationInfoDto Application { get; set; } public UserLoginInfoDto User { get; set; } public TenantLoginInfoDto Tenant { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/Dto/TenantLoginInfoDto.cs ================================================ using Abp.Application.Services.Dto; using Abp.AutoMapper; using AcmStatisticsBackend.MultiTenancy; namespace AcmStatisticsBackend.Sessions.Dto { [AutoMapFrom(typeof(Tenant))] public class TenantLoginInfoDto : EntityDto { public string TenancyName { get; set; } public string Name { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/Dto/UserLoginInfoDto.cs ================================================ using Abp.Application.Services.Dto; using Abp.AutoMapper; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Sessions.Dto { [AutoMapFrom(typeof(User))] public class UserLoginInfoDto : EntityDto { public string Name { get; set; } public string Surname { get; set; } public string UserName { get; set; } public string EmailAddress { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/ISessionAppService.cs ================================================ using System.Threading.Tasks; using Abp.Application.Services; using AcmStatisticsBackend.Sessions.Dto; namespace AcmStatisticsBackend.Sessions { public interface ISessionAppService : IApplicationService { Task GetCurrentLoginInformations(); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Sessions/SessionAppService.cs ================================================ using System.Collections.Generic; using System.Threading.Tasks; using Abp.Auditing; using AcmStatisticsBackend.Sessions.Dto; namespace AcmStatisticsBackend.Sessions { public class SessionAppService : AcmStatisticsBackendAppServiceBase, ISessionAppService { [DisableAuditing] public async Task GetCurrentLoginInformations() { var output = new GetCurrentLoginInformationsOutput { Application = new ApplicationInfoDto { Version = AppVersionHelper.Version, ReleaseDate = AppVersionHelper.ReleaseDate, Features = new Dictionary(), }, }; if (AbpSession.TenantId.HasValue) { output.Tenant = ObjectMapper.Map(await GetCurrentTenantAsync()); } if (AbpSession.UserId.HasValue) { output.User = ObjectMapper.Map(await GetCurrentUserAsync()); } return output; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Settings/Dto/UpdateAutoSaveHistoryInput.cs ================================================ namespace AcmStatisticsBackend.Settings.Dto { public class UpdateAutoSaveHistoryInput { public bool AutoSaveHistory { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Settings/Dto/UserSettingsConfigDto.cs ================================================ using System.Collections.Generic; namespace AcmStatisticsBackend.Settings.Dto { public class UserSettingsConfigDto { public IDictionary Values { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Settings/Dto/UserTimeZoneDto.cs ================================================ using System.ComponentModel.DataAnnotations; using System.Linq; using Abp.Runtime.Validation; using TimeZoneConverter; namespace AcmStatisticsBackend.Settings.Dto { public class UserTimeZoneDto : ICustomValidate { /// /// Time zone of the user. It is a windows time zone name. /// See /// for all possible values. /// [Required] public string TimeZone { get; set; } public void AddValidationErrors(CustomValidationContext context) { if (!TZConvert.KnownWindowsTimeZoneIds.Contains(TimeZone)) { context.Results.Add(new ValidationResult("TimeZone must be valid!")); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Settings/IUserConfigAppService.cs ================================================ using System.Threading.Tasks; using AcmStatisticsBackend.Settings.Dto; namespace AcmStatisticsBackend.Settings { /// /// Manage user config /// public interface IUserConfigAppService { /// /// Get all user settings available to frontend /// Task GetUserSettings(); /// /// Update config about whether the history should be auto-saved /// Task UpdateAutoSaveHistory(UpdateAutoSaveHistoryInput input); /// /// Set time zone of current user. /// Task SetUserTimeZone(UserTimeZoneDto dto); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Application/Settings/UserConfigAppService.cs ================================================ using System.Collections.Generic; using System.Threading.Tasks; using Abp.Authorization; using Abp.Configuration; using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Runtime.Session; using Abp.Timing; using Abp.UI; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Configuration; using AcmStatisticsBackend.Settings.Dto; namespace AcmStatisticsBackend.Settings { /// [AbpAuthorize] public class UserConfigAppService : AcmStatisticsBackendAppServiceBase, IUserConfigAppService { private readonly ISettingDefinitionManager _settingDefinitionManager; private readonly IIocResolver _iocResolver; private readonly IClockProvider _clockProvider; private readonly IRepository _userSettingAttributeRepository; public UserConfigAppService(ISettingDefinitionManager settingDefinitionManager, IIocResolver iocResolver, IClockProvider clockProvider, IRepository userSettingAttributeRepository) { _settingDefinitionManager = settingDefinitionManager; _iocResolver = iocResolver; _clockProvider = clockProvider; _userSettingAttributeRepository = userSettingAttributeRepository; } /// public async Task GetUserSettings() { var config = new UserSettingsConfigDto { Values = new Dictionary(), }; var settings = await SettingManager.GetAllSettingValuesAsync(SettingScopes.All); using var scope = _iocResolver.CreateScope(); foreach (var settingValue in settings) { if (!await _settingDefinitionManager.GetSettingDefinition(settingValue.Name) .ClientVisibilityProvider .CheckVisible(scope)) { continue; } config.Values.Add(settingValue.Name, settingValue.Value); } return config; } /// [AbpAuthorize(PermissionNames.Settings_Update)] public async Task UpdateAutoSaveHistory(UpdateAutoSaveHistoryInput input) { await SettingManager.ChangeSettingForUserAsync( AbpSession.ToUserIdentifier(), AppSettingNames.AutoSaveHistory, input.AutoSaveHistory ? "true" : "false"); } /// [AbpAuthorize(PermissionNames.Settings_Update)] public async Task SetUserTimeZone(UserTimeZoneDto dto) { var settings = await GetOrCreateUserSettingAttribute(); if (settings.LastTimeZoneChangedTime.HasValue && settings.LastTimeZoneChangedTime.Value.AddDays(1) > _clockProvider.Now) { throw new UserFriendlyException("Please wait 24 hours to set time zone again!"); } await SettingManager.ChangeSettingForUserAsync( AbpSession.ToUserIdentifier(), TimingSettingNames.TimeZone, dto.TimeZone); settings.LastTimeZoneChangedTime = _clockProvider.Now; } private async Task GetOrCreateUserSettingAttribute() { return await _userSettingAttributeRepository.FirstOrDefaultAsync( item => item.UserId == AbpSession.UserId.Value) ?? await _userSettingAttributeRepository.InsertAsync( new UserSettingAttribute { UserId = AbpSession.GetUserId(), }); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/AcmStatisticsBackend.Core.csproj ================================================ 1.0.0.0 net8.0 AcmStatisticsBackend.Core AcmStatisticsBackend.Core false false false AbpCompanyName-AcmStatisticsBackend-56C2EF2F-ABD6-4EFC-AAF2-2E81C34E8FB1 AcmStatisticsBackend ================================================ FILE: backend/src/AcmStatisticsBackend.Core/AcmStatisticsBackendConsts.cs ================================================ namespace AcmStatisticsBackend { public class AcmStatisticsBackendConsts { public const string LocalizationSourceName = "AcmStatisticsBackend"; public const string ConnectionStringName = "Default"; public const bool MultiTenancyEnabled = false; /// /// 用户没有输入邮箱时,使用这个后缀作为邮箱名 /// public const string NoEmailSuffix = "@noemail.fake"; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/AcmStatisticsBackendCoreModule.cs ================================================ using Abp.Dependency; using Abp.Modules; using Abp.Reflection.Extensions; using Abp.Timing; using Abp.Zero; using Abp.Zero.Configuration; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Configuration; using AcmStatisticsBackend.Localization; using AcmStatisticsBackend.MultiTenancy; using AcmStatisticsBackend.Timing; using Castle.MicroKernel.Registration; namespace AcmStatisticsBackend { [DependsOn(typeof(AbpZeroCoreModule))] public class AcmStatisticsBackendCoreModule : AbpModule { public override void PreInitialize() { Clock.Provider = ClockProviders.Utc; IocManager.IocContainer.Register( Component.For() .Instance(ClockProviders.Utc) .LifestyleSingleton()); Configuration.Auditing.IsEnabledForAnonymousUsers = true; // Declare entity types Configuration.Modules.Zero().EntityTypes.Tenant = typeof(Tenant); Configuration.Modules.Zero().EntityTypes.Role = typeof(Role); Configuration.Modules.Zero().EntityTypes.User = typeof(User); AcmStatisticsBackendLocalizationConfigurer.Configure(Configuration.Localization); // Enable this line to create a multi-tenant application. Configuration.MultiTenancy.IsEnabled = AcmStatisticsBackendConsts.MultiTenancyEnabled; // Configure roles AppRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement); Configuration.Settings.Providers.Add(); } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AcmStatisticsBackendCoreModule).GetAssembly()); } public override void PostInitialize() { IocManager.Resolve().StartupTime = Clock.Now; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/AcmStatisticsBackendExtensions.cs ================================================ using System; using System.Collections; using System.Collections.Generic; namespace AcmStatisticsBackend { public static class AcmStatisticsBackendExtensions { #pragma warning disable SA1618 /// /// 用法: /// /// Get().A().Object().WithIn(it => { /// it.methodA(); /// it.methodB(); /// }) /// /// public static TR WithIn(this TT obj, Func func) where TT : class { return func(obj); } #pragma warning restore SA1618 public static TR WithIn(this ref TT obj, Func func) where TT : struct { return func(obj); } public static void WithIn(this T obj, Action action) where T : class { action(obj); } public static void WithIn(this ref T obj, Action action) where T : struct { action(obj); } // from https://stackoverflow.com/a/47815787 public static void Deconstruct(this T[] items, out T t0) { t0 = items.Length > 0 ? items[0] : default; } public static void Deconstruct(this T[] items, out T t0, out T t1) { t0 = items.Length > 0 ? items[0] : default; t1 = items.Length > 1 ? items[1] : default; } // from https://stackoverflow.com/a/34362585 public static IReadOnlyCollection AsReadOnly(this ICollection source) { if (source == null) { throw new ArgumentNullException("source"); } return source as IReadOnlyCollection ?? new ReadOnlyCollectionAdapter(source); } private sealed class ReadOnlyCollectionAdapter : IReadOnlyCollection { private readonly ICollection _source; public ReadOnlyCollectionAdapter(ICollection source) => this._source = source; public int Count => _source.Count; public IEnumerator GetEnumerator() => _source.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/AppVersionHelper.cs ================================================ using System; using System.IO; using Abp.Reflection.Extensions; namespace AcmStatisticsBackend { /// /// Central point for application version. /// public class AppVersionHelper { /// /// Gets current version of the application. /// It's also shown in the web page. /// public const string Version = "5.1.0.0"; /// /// Gets release (last build) date of the application. /// It's shown in the web page. /// public static DateTime ReleaseDate => LzyReleaseDate.Value; private static readonly Lazy LzyReleaseDate = new Lazy(() => new FileInfo(typeof(AppVersionHelper).GetAssembly().Location).LastWriteTime); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/AcmStatisticsBackendAuthorizationProvider.cs ================================================ using Abp.Authorization; using Abp.Localization; using Abp.MultiTenancy; namespace AcmStatisticsBackend.Authorization { public class AcmStatisticsBackendAuthorizationProvider : AuthorizationProvider { public override void SetPermissions(IPermissionDefinitionContext context) { context.CreatePermission(PermissionNames.Pages_Users, L("Users")); context.CreatePermission(PermissionNames.Pages_Roles, L("Roles")); context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host); context.CreatePermission(PermissionNames.Statistics_DefaultQuery, F("Default query username")); context.CreatePermission(PermissionNames.AcHistory_Histories, F("Query history")); context.CreatePermission(PermissionNames.Settings_Update, F("Change user's own settings")); } private static ILocalizableString L(string name) { return new LocalizableString(name, AcmStatisticsBackendConsts.LocalizationSourceName); } private static ILocalizableString F(string content) { return new FixedLocalizableString(content); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/LoginManager.cs ================================================ using Abp.Authorization; using Abp.Authorization.Users; using Abp.Configuration; using Abp.Configuration.Startup; using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Zero.Configuration; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Identity; namespace AcmStatisticsBackend.Authorization { public class LogInManager : AbpLogInManager { public LogInManager( UserManager userManager, IMultiTenancyConfig multiTenancyConfig, IRepository tenantRepository, IUnitOfWorkManager unitOfWorkManager, ISettingManager settingManager, IRepository userLoginAttemptRepository, IUserManagementConfig userManagementConfig, IIocResolver iocResolver, IPasswordHasher passwordHasher, RoleManager roleManager, UserClaimsPrincipalFactory claimsPrincipalFactory) : base( userManager, multiTenancyConfig, tenantRepository, unitOfWorkManager, settingManager, userLoginAttemptRepository, userManagementConfig, iocResolver, passwordHasher, roleManager, claimsPrincipalFactory) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/PermissionChecker.cs ================================================ using Abp.Authorization; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Authorization { public class PermissionChecker : PermissionChecker { public PermissionChecker(UserManager userManager) : base(userManager) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/PermissionNames.cs ================================================ namespace AcmStatisticsBackend.Authorization { public static class PermissionNames { #pragma warning disable SA1310 // Field names should not contain underscore public const string Pages_Tenants = "Pages.Tenants"; public const string Pages_Users = "Pages.Users"; public const string Pages_Roles = "Pages.Roles"; public const string Statistics_DefaultQuery = "Statistics.DefaultQuery"; public const string AcHistory_Histories = "AcHistory.Histories"; public const string Settings_Update = "Settings.Update"; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Roles/AppRoleConfig.cs ================================================ using Abp.MultiTenancy; using Abp.Zero.Configuration; namespace AcmStatisticsBackend.Authorization.Roles { public static class AppRoleConfig { public static void Configure(IRoleManagementConfig roleManagementConfig) { // Static host roles roleManagementConfig.StaticRoles.Add( new StaticRoleDefinition( StaticRoleNames.Host.Admin, MultiTenancySides.Host)); // Static tenant roles roleManagementConfig.StaticRoles.Add( new StaticRoleDefinition( StaticRoleNames.Tenants.Admin, MultiTenancySides.Tenant)); roleManagementConfig.StaticRoles.Add( new StaticRoleDefinition( StaticRoleNames.Tenants.User, MultiTenancySides.Tenant)); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Roles/Role.cs ================================================ using System.ComponentModel.DataAnnotations; using Abp.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Authorization.Roles { public class Role : AbpRole { public Role() { } public Role(int? tenantId, string displayName) : base(tenantId, displayName) { } public Role(int? tenantId, string name, string displayName) : base(tenantId, name, displayName) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Roles/RoleManager.cs ================================================ using System.Collections.Generic; using Abp.Authorization; using Abp.Authorization.Roles; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Organizations; using Abp.Runtime.Caching; using Abp.Zero.Configuration; using AcmStatisticsBackend.Authorization.Users; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; namespace AcmStatisticsBackend.Authorization.Roles { public class RoleManager : AbpRoleManager { public RoleManager( RoleStore store, IEnumerable> roleValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, ILogger> logger, IPermissionManager permissionManager, ICacheManager cacheManager, IUnitOfWorkManager unitOfWorkManager, IRoleManagementConfig roleManagementConfig, IRepository organizationUnitRepository, IRepository organizationUnitRoleRepository) : base( store, roleValidators, keyNormalizer, errors, logger, permissionManager, cacheManager, unitOfWorkManager, roleManagementConfig, organizationUnitRepository, organizationUnitRoleRepository) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Roles/RoleStore.cs ================================================ using Abp.Authorization.Roles; using Abp.Domain.Repositories; using Abp.Domain.Uow; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Authorization.Roles { public class RoleStore : AbpRoleStore { public RoleStore( IUnitOfWorkManager unitOfWorkManager, IRepository roleRepository, IRepository rolePermissionSettingRepository) : base( unitOfWorkManager, roleRepository, rolePermissionSettingRepository) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Roles/StaticRoleNames.cs ================================================ namespace AcmStatisticsBackend.Authorization.Roles { public static class StaticRoleNames { public static class Host { public const string Admin = "Admin"; } public static class Tenants { public const string Admin = "Admin"; public const string User = "User"; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/User.cs ================================================ using System; using System.Collections.Generic; using Abp.Authorization.Users; using Abp.Extensions; namespace AcmStatisticsBackend.Authorization.Users { public class User : AbpUser { public const string DefaultPassword = "123qwe"; public static string CreateRandomPassword() { return Guid.NewGuid().ToString("N").Truncate(16); } public static User CreateTenantAdminUser(int tenantId, string emailAddress) { var user = new User { TenantId = tenantId, UserName = AdminUserName, Name = AdminUserName, Surname = AdminUserName, EmailAddress = emailAddress, Roles = new List(), }; user.SetNormalizedNames(); return user; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/UserClaimsPrincipalFactory.cs ================================================ using Abp.Authorization; using Abp.Domain.Uow; using AcmStatisticsBackend.Authorization.Roles; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.Authorization.Users { public class UserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory { public UserClaimsPrincipalFactory( UserManager userManager, RoleManager roleManager, IOptions optionsAccessor, IUnitOfWorkManager unitOfWorkManager) : base( userManager, roleManager, optionsAccessor, unitOfWorkManager) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/UserDeletingEventHandler.cs ================================================ using System.Linq.Dynamic.Core; using System.Threading.Tasks; using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Events.Bus.Entities; using Abp.Events.Bus.Handlers; using AcmStatisticsBackend.Crawlers; namespace AcmStatisticsBackend.Authorization.Users { public class UserDeletingEventHandler : IAsyncEventHandler>, ITransientDependency { private readonly IRepository _defaultQueryRepository; private readonly IRepository _acHistoryRepository; public UserDeletingEventHandler(IRepository defaultQueryRepository, IRepository acHistoryRepository) { _defaultQueryRepository = defaultQueryRepository; _acHistoryRepository = acHistoryRepository; } public async Task HandleEventAsync(EntityDeletingEventData eventData) { await _defaultQueryRepository.HardDeleteAsync( e => e.UserId == eventData.Entity.Id); await _acHistoryRepository.DeleteAsync( e => e.UserId == eventData.Entity.Id); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/UserManager.cs ================================================ using System; using System.Collections.Generic; using Abp.Authorization; using Abp.Authorization.Roles; using Abp.Authorization.Users; using Abp.Configuration; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Organizations; using Abp.Runtime.Caching; using AcmStatisticsBackend.Authorization.Roles; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.Authorization.Users { public class UserManager : AbpUserManager { public UserManager(AbpRoleManager roleManager, AbpUserStore userStore, IOptions optionsAccessor, IPasswordHasher passwordHasher, IEnumerable> userValidators, IEnumerable> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger> logger, IPermissionManager permissionManager, IUnitOfWorkManager unitOfWorkManager, ICacheManager cacheManager, IRepository organizationUnitRepository, IRepository userOrganizationUnitRepository, IOrganizationUnitSettings organizationUnitSettings, ISettingManager settingManager, IRepository userLoginRepository) : base(roleManager, userStore, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, permissionManager, unitOfWorkManager, cacheManager, organizationUnitRepository, userOrganizationUnitRepository, organizationUnitSettings, settingManager, userLoginRepository) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/UserRegistrationManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Abp.Authorization.Users; using Abp.Domain.Services; using Abp.Domain.Uow; using Abp.IdentityFramework; using Abp.Runtime.Session; using Abp.UI; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.Authorization.Users { public class UserRegistrationManager : DomainService { public IAbpSession AbpSession { get; set; } private readonly TenantManager _tenantManager; private readonly UserManager _userManager; private readonly RoleManager _roleManager; private readonly IPasswordHasher _passwordHasher; public UserRegistrationManager( TenantManager tenantManager, UserManager userManager, RoleManager roleManager, IPasswordHasher passwordHasher) { _tenantManager = tenantManager; _userManager = userManager; _roleManager = roleManager; _passwordHasher = passwordHasher; AbpSession = NullAbpSession.Instance; } [UnitOfWork] public virtual async Task RegisterAsync(string userName, string plainPassword) { CheckForTenant(); var tenant = await GetActiveTenantAsync(); var user = new User { TenantId = tenant.Id, IsActive = true, UserName = userName, EmailAddress = userName + AcmStatisticsBackendConsts.NoEmailSuffix, IsEmailConfirmed = false, Roles = new List(), Name = "", Surname = "", }; user.SetNormalizedNames(); foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync()) { user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id)); } await _userManager.InitializeOptionsAsync(tenant.Id); CheckErrors(await _userManager.CreateAsync(user, plainPassword)); await CurrentUnitOfWork.SaveChangesAsync(); return user; } private void CheckForTenant() { if (!AbpSession.TenantId.HasValue) { throw new InvalidOperationException("Can not register host users!"); } } private async Task GetActiveTenantAsync() { if (!AbpSession.TenantId.HasValue) { return null; } return await GetActiveTenantAsync(AbpSession.TenantId.Value); } private async Task GetActiveTenantAsync(int tenantId) { var tenant = await _tenantManager.FindByIdAsync(tenantId); if (tenant == null) { throw new UserFriendlyException(L("UnknownTenantId{0}", tenantId)); } if (!tenant.IsActive) { throw new UserFriendlyException(L("TenantIdIsNotActive{0}", tenantId)); } return tenant; } protected virtual void CheckErrors(IdentityResult identityResult) { identityResult.CheckErrors(LocalizationManager); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Authorization/Users/UserStore.cs ================================================ using Abp.Authorization.Users; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Linq; using Abp.Organizations; using AcmStatisticsBackend.Authorization.Roles; namespace AcmStatisticsBackend.Authorization.Users { public class UserStore : AbpUserStore { public UserStore( IUnitOfWorkManager unitOfWorkManager, IRepository userRepository, IRepository roleRepository, IRepository userRoleRepository, IRepository userLoginRepository, IRepository userClaimRepository, IRepository userPermissionSettingRepository, IRepository userOrganizationUnitRepository, IRepository organizationUnitRoleRepository, IRepository userTokenRepository) : base( unitOfWorkManager, userRepository, roleRepository, userRoleRepository, userLoginRepository, userClaimRepository, userPermissionSettingRepository, userOrganizationUnitRepository, organizationUnitRoleRepository, userTokenRepository) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Configuration/AppConfigurations.cs ================================================ using System.Collections.Concurrent; using Abp.Extensions; using Abp.Reflection.Extensions; using Microsoft.Extensions.Configuration; namespace AcmStatisticsBackend.Configuration { public static class AppConfigurations { private static readonly ConcurrentDictionary _configurationCache; static AppConfigurations() { _configurationCache = new ConcurrentDictionary(); } public static IConfigurationRoot Get(string path, string environmentName = null, bool addUserSecrets = false) { var cacheKey = path + "#" + environmentName + "#" + addUserSecrets; return _configurationCache.GetOrAdd( cacheKey, _ => BuildConfiguration(path, environmentName, addUserSecrets)); } private static IConfigurationRoot BuildConfiguration(string path, string environmentName = null, bool addUserSecrets = false) { var builder = new ConfigurationBuilder() .SetBasePath(path) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); if (!environmentName.IsNullOrWhiteSpace()) { builder = builder.AddJsonFile($"appsettings.{environmentName}.json", optional: true); } builder = builder.AddEnvironmentVariables(); if (addUserSecrets) { builder.AddUserSecrets(typeof(AppConfigurations).GetAssembly()); } return builder.Build(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Configuration/AppEnvironmentVariables.cs ================================================ using System; namespace AcmStatisticsBackend.Configuration { public class AppEnvironmentVariables { public static string DefaultAdminPassword => Environment.GetEnvironmentVariable("BACKEND_ADMIN_DEFAULT_PASSWORD") ?? "123qwe"; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Configuration/AppSettingNames.cs ================================================ namespace AcmStatisticsBackend.Configuration { public static class AppSettingNames { public const string UiTheme = "App.UiTheme"; public const string AutoSaveHistory = "App.AutoSaveHistory"; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Configuration/AppSettingProvider.cs ================================================ using System.Collections.Generic; using Abp.Configuration; namespace AcmStatisticsBackend.Configuration { public class AppSettingProvider : SettingProvider { public override IEnumerable GetSettingDefinitions(SettingDefinitionProviderContext context) { return new[] { new SettingDefinition(AppSettingNames.UiTheme, "red", scopes: SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User, isVisibleToClients: true), new SettingDefinition(AppSettingNames.AutoSaveHistory, "true", scopes: SettingScopes.User, isVisibleToClients: true), }; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/DefaultQuery.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.Domain.Entities.Auditing; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Crawlers { /// /// 用户的默认查询。用户登录后,查题页面会自动填充此查询的内容 /// public class DefaultQuery : FullAuditedEntity { [Required] public User User { get; set; } public long UserId { get; set; } /// /// 主用户名 /// [Required] [MinLength(0)] public string MainUsername { get; set; } /// /// 在各个爬虫上的用户名。key为爬虫名称,value为一个用户名的列表,表示在该爬虫上的所有用户名。 /// [Required] public Dictionary> UsernamesInCrawlers { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/QueryCrawlerSummary.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.Domain.Entities; namespace AcmStatisticsBackend.Crawlers { /// /// Store the summary of a certain crawler. /// public class QueryCrawlerSummary : Entity { [Required] public QuerySummary QuerySummary { get; set; } public long QuerySummaryId { get; set; } /// /// The name of the crawler. Frontend can get its title by this field. /// [Required] public string CrawlerName { get; set; } /// /// Submission count. /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Solved count. /// [Range(0, int.MaxValue)] public int Solved { get; set; } /// /// Usernames used in this crawler /// public ICollection Usernames { get; set; } public bool IsVirtualJudge { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/QueryHistory.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.Domain.Entities; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Crawlers { /// /// 一次查询历史记录 /// public class QueryHistory : Entity { [Required] public DateTime CreationTime { get; set; } /// /// The user related to this entity /// public User User { get; set; } public long UserId { get; set; } /// /// Main username of query history, can be empty /// [Required] [MinLength(0)] public string MainUsername { get; set; } /// /// Query history of each crawler. /// [Required] public ICollection QueryWorkerHistories { get; set; } /// /// Is data source reliable (solved/submission are really from certain username) /// /// When get the history from user directly, it should be false; /// when get it from crawler-api-backend, it should be true. /// public bool IsReliableSource { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/QuerySummary.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Abp.Domain.Entities; namespace AcmStatisticsBackend.Crawlers { /// /// The summary of a certain query. /// public class QuerySummary : Entity { [Required] public QueryHistory QueryHistory { get; set; } public long QueryHistoryId { get; set; } /// /// When the summary is generated /// public DateTime GenerateTime { get; set; } /// /// Query summaries of each crawler. /// [Required] public ICollection QueryCrawlerSummaries { get; set; } /// /// Warnings in summary generation. /// [Required] public ICollection SummaryWarnings { get; set; } /// /// Total submission count /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Total solved count, redundant problems (including problems in virtual_judge) are removed. /// [Range(0, int.MaxValue)] public int Solved { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/QueryWorkerHistory.cs ================================================ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using Abp.Domain.Entities; namespace AcmStatisticsBackend.Crawlers { /// /// Query history in a certain crawler /// public class QueryWorkerHistory : Entity { /// /// QueryHistory the entity related to /// [Required] public QueryHistory QueryHistory { get; set; } public long QueryHistoryId { get; set; } /// /// The name of the crawler. Frontend can get its title by this field. /// [Required] public string CrawlerName { get; set; } /// /// The username used to query this crawler. /// [Required] public string Username { get; set; } /// /// Error message of the crawler. If it's not null, current query is failed, and /// and are all 0. /// [MaybeNull] public string ErrorMessage { get; set; } /// /// Submission count. /// [Range(0, int.MaxValue)] public int Submission { get; set; } /// /// Solved count. /// [Range(0, int.MaxValue)] public int Solved { get; set; } /// /// The list of problem ids that user solved. /// /// Can be null if crawler does not support it. /// [MaybeNull] public string[] SolvedList { get; set; } /// /// Whether current crawler is virtual judge when the history is submitted. /// public bool IsVirtualJudge { get; set; } /// /// If is false, this field is null. /// Otherwise, this field contains submissions count in each crawler. /// [MaybeNull] public IDictionary SubmissionsByCrawlerName { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/SummaryGenerator.cs ================================================ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Linq; using Abp.Dependency; using Abp.Extensions; using Abp.Timing; using Abp.UI; using AcmStatisticsBackend.ServiceClients; namespace AcmStatisticsBackend.Crawlers { /// /// Generate summarise from /// public class SummaryGenerator : ISingletonDependency { private readonly IClockProvider _clockProvider; public SummaryGenerator(IClockProvider clockProvider) { _clockProvider = clockProvider; } /// /// Generate summary from . /// should already be loaded. /// /// It will not modify the parameter. /// [Pure] public QuerySummary Generate( IReadOnlyCollection crawlerMeta, IReadOnlyCollection workerHistories) { var histories = workerHistories .Where(item => item.ErrorMessage.IsNullOrEmpty()) .ToList(); ResolveSummaryData(crawlerMeta, histories, out var summaries, out var warnings, out var directlyAddSolvedWorkerList); foreach (var worker in directlyAddSolvedWorkerList) { var summary = summaries[worker.CrawlerName]; summary.Usernames.Add(new UsernameInCrawler { Username = worker.Username, }); } var localJudgeDict = summaries .Where(it => it.Value.IsVirtualJudge == false) .ToDictionary( p => p.Key, p => new QueryCrawlerSummary { CrawlerName = p.Value.CrawlerName, Solved = p.Value.SolvedSet.Count, Submission = p.Value.Submissions, Usernames = p.Value.Usernames.ToList(), IsVirtualJudge = p.Value.IsVirtualJudge, }); // directlyAddSolvedWorkerList only exists in local judges foreach (var worker in directlyAddSolvedWorkerList) { var summary = localJudgeDict[worker.CrawlerName]; summary.Solved += worker.Solved; summary.Submission += worker.Submission; } var virtualJudgeList = summaries .Select(it => it.Value) .Where(it => it.IsVirtualJudge) .SelectMany(it => new[] { new QueryCrawlerSummary { CrawlerName = it.CrawlerName, Solved = it.SolvedSet.Count, Submission = it.Submissions, Usernames = it.Usernames.ToList(), IsVirtualJudge = false, }, new QueryCrawlerSummary { CrawlerName = it.CrawlerName, Solved = it.NotMergedSolvedSet.Count, Submission = it.NotMergedSubmissions, Usernames = it.NotMergedUsernames.ToList(), IsVirtualJudge = true, }, }); var summaryList = localJudgeDict .Select(p => p.Value) .Concat(virtualJudgeList) .Where(a => a.Usernames.Count > 0 && (a.Submission > 0 || a.Solved > 0)) .OrderBy(a => a.CrawlerName) .ToList(); return new QuerySummary { QueryCrawlerSummaries = summaryList, SummaryWarnings = warnings, Solved = summaryList.Sum(a => a.Solved), Submission = summaryList.Sum(a => a.Submission), GenerateTime = _clockProvider.Now, }; } /// /// Pre-process data /// private static void ResolveSummaryData( IReadOnlyCollection crawlerMeta, IReadOnlyCollection workerHistories, out Dictionary summaries, out List warnings, out List directlyAddSolvedWorkerList) { summaries = InitSummaries(crawlerMeta); warnings = new List(); directlyAddSolvedWorkerList = new List(); EnsureCrawlerType(crawlerMeta, summaries, workerHistories); foreach (var worker in workerHistories) { var summary = summaries[worker.CrawlerName]; summary.Usernames.Add(new UsernameInCrawler { Username = worker.Username, }); if (summary.IsVirtualJudge) { summary.NotMergedUsernames.Add(new UsernameInCrawler { Username = worker.Username, }); } if (worker.SolvedList == null) { Debug.Assert(worker.IsVirtualJudge == false, "All virtual judges should have solved list"); warnings.Add(new SummaryWarning( worker.CrawlerName, "This crawler does not have a solved list and " + "its result will be directly added to summary.")); directlyAddSolvedWorkerList.Add(worker); continue; } if (worker.IsVirtualJudge) { if (worker.SubmissionsByCrawlerName.Values.Sum() != worker.Submission) { warnings.Add(new SummaryWarning(worker.CrawlerName, "submissionByCrawler field of this crawler does not match its submission field, " + "and only results in submissionByCrawler are used.")); } HandleVirtualJudgeProblems(worker, summary, summaries); HandleVirtualJudgeSubmissions(worker, summary, summaries); } else { summary.Submissions += worker.Submission; summary.SolvedSet.UnionWith(worker.SolvedList); } } } private static void EnsureCrawlerType( IReadOnlyCollection crawlerMeta, IReadOnlyDictionary summaries, IReadOnlyCollection workerHistories) { var workerHasSolvedList = new Dictionary(); foreach (var history in workerHistories) { if (workerHasSolvedList.TryGetValue(history.CrawlerName, out var hasSolvedList)) { if (hasSolvedList != (history.SolvedList != null)) { var title = GetCrawlerTitle(crawlerMeta, history); throw new UserFriendlyException($"All workers of crawler {title} must have solved list!"); } } else { workerHasSolvedList.Add(history.CrawlerName, history.SolvedList != null); } if (!summaries.TryGetValue(history.CrawlerName, out var summary)) { throw new UserFriendlyException( $"The meta data of crawler {history.CrawlerName} does not exist."); } if (summary.IsVirtualJudge != history.IsVirtualJudge) { var title = GetCrawlerTitle(crawlerMeta, history); if (summary.IsVirtualJudge) { throw new UserFriendlyException( $"According to crawler meta, the type of crawler {title} should be a virtual judge."); } else { throw new UserFriendlyException( $"According to crawler meta, the type of crawler {title} should not be a virtual judge."); } } if (history.IsVirtualJudge && history.SolvedList == null) { var title = GetCrawlerTitle(crawlerMeta, history); throw new UserFriendlyException($"Virtual judge {title} should have a solved list."); } } } private static string GetCrawlerTitle( IReadOnlyCollection crawlerMeta, QueryWorkerHistory history) { var meta = crawlerMeta.First(item => item.CrawlerName == history.CrawlerName); return meta.CrawlerTitle; } private static void HandleVirtualJudgeProblems( QueryWorkerHistory worker, CrawlerSummaryData vjSummary, IReadOnlyDictionary summaries) { foreach (var problem in worker.SolvedList) { var (problemCrawlerName, problemId) = problem.Split('-'); if (summaries.TryGetValue(problemCrawlerName, out var problemCrawlerSummary)) { problemCrawlerSummary.Usernames.Add(new UsernameInCrawler { Username = worker.Username, FromCrawlerName = worker.CrawlerName == problemCrawlerName ? null : worker.CrawlerName, }); problemCrawlerSummary.SolvedSet.Add(problemId); } else { vjSummary.NotMergedSolvedSet.Add(problem); } } } private static void HandleVirtualJudgeSubmissions( QueryWorkerHistory worker, CrawlerSummaryData vjSummary, IReadOnlyDictionary summaries) { foreach (var (crawler, submissions) in worker.SubmissionsByCrawlerName) { if (summaries.TryGetValue(crawler, out var crawlerSummary)) { crawlerSummary.Submissions += submissions; crawlerSummary.Usernames.Add(new UsernameInCrawler { Username = worker.Username, FromCrawlerName = worker.CrawlerName == crawler ? null : worker.CrawlerName, }); } else { vjSummary.NotMergedSubmissions += submissions; } } } private static Dictionary InitSummaries( IReadOnlyCollection crawlerMeta) { return crawlerMeta .ToDictionary( crawlerMetaItem => crawlerMetaItem.CrawlerName, crawlerMetaItem => new CrawlerSummaryData { CrawlerName = crawlerMetaItem.CrawlerName, IsVirtualJudge = crawlerMetaItem.IsVirtualJudge, }); } /// /// Data structure to use inside the algorithm /// private class CrawlerSummaryData { public string CrawlerName { get; set; } public bool IsVirtualJudge { get; set; } // in virtual judge, the two items means its local judge result public HashSet SolvedSet { get; } = new HashSet(); public int Submissions { get; set; } public HashSet Usernames { get; } // only work in virtual judge public HashSet NotMergedSolvedSet { get; } = new HashSet(); public int NotMergedSubmissions { get; set; } public HashSet NotMergedUsernames { get; } public CrawlerSummaryData() { Usernames = new HashSet(new UsernameInCrawlerEqualityComparer()); NotMergedUsernames = new HashSet(new UsernameInCrawlerEqualityComparer()); } } private class UsernameInCrawlerEqualityComparer : IEqualityComparer { public bool Equals(UsernameInCrawler x, UsernameInCrawler y) { if (x == null && y == null) { return true; } if (x == null || y == null) { return false; } return x.Username == y.Username && x.FromCrawlerName == y.FromCrawlerName; } public int GetHashCode(UsernameInCrawler obj) { return $"{obj.FromCrawlerName ?? string.Empty}/{obj.Username ?? string.Empty}" .GetHashCode(); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/SummaryWarning.cs ================================================ using System.Collections.Generic; using Abp.Domain.Values; namespace AcmStatisticsBackend.Crawlers { /// /// A warning in /// public class SummaryWarning : ValueObject { public SummaryWarning(string crawlerName, string content) { CrawlerName = crawlerName; Content = content; } /// /// The crawler the warning is about /// public string CrawlerName { get; } /// /// Warning content /// public string Content { get; } protected override IEnumerable GetAtomicValues() { yield return CrawlerName; yield return Content; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Crawlers/UsernameInCrawler.cs ================================================ using System.ComponentModel.DataAnnotations; using System.Diagnostics; using Abp.Domain.Entities; namespace AcmStatisticsBackend.Crawlers { /// /// An username in a certain crawler. /// [DebuggerDisplay("FromCrawlerName = {FromCrawlerName}, Username = {Username}")] public class UsernameInCrawler : Entity { /// /// The QueryCrawlerSummary it related to. /// [Required] public QueryCrawlerSummary QueryCrawlerSummary { get; set; } /// /// Which crawler (virtual judge) the username is from. /// /// If it is null or empty string, the username is from /// its own crawler. /// public string FromCrawlerName { get; set; } [Required] public string Username { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Editions/EditionManager.cs ================================================ using Abp.Application.Editions; using Abp.Application.Features; using Abp.Domain.Repositories; using Abp.Domain.Uow; namespace AcmStatisticsBackend.Editions { public class EditionManager : AbpEditionManager { public const string DefaultEditionName = "Standard"; public EditionManager( IRepository editionRepository, IAbpZeroFeatureValueStore featureValueStore, IUnitOfWorkManager unitOfWorkManager) : base( editionRepository, featureValueStore, unitOfWorkManager) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Features/FeatureValueStore.cs ================================================ using Abp.Application.Features; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.MultiTenancy; using Abp.Runtime.Caching; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.MultiTenancy; namespace AcmStatisticsBackend.Features { public class FeatureValueStore : AbpFeatureValueStore { public FeatureValueStore( ICacheManager cacheManager, IRepository tenantFeatureRepository, IRepository tenantRepository, IRepository editionFeatureRepository, IFeatureManager featureManager, IUnitOfWorkManager unitOfWorkManager) : base( cacheManager, tenantFeatureRepository, tenantRepository, editionFeatureRepository, featureManager, unitOfWorkManager) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Identity/IdentityRegistrar.cs ================================================ using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Editions; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; namespace AcmStatisticsBackend.Identity { public static class IdentityRegistrar { public static IdentityBuilder Register(IServiceCollection services) { services.AddLogging(); return services.AddAbpIdentity() .AddAbpTenantManager() .AddAbpUserManager() .AddAbpRoleManager() .AddAbpEditionManager() .AddAbpUserStore() .AddAbpRoleStore() .AddAbpLogInManager() .AddAbpSignInManager() .AddAbpSecurityStampValidator() .AddAbpUserClaimsPrincipalFactory() .AddPermissionChecker() .AddDefaultTokenProviders(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Identity/SecurityStampValidator.cs ================================================ using Abp.Authorization; using Abp.Domain.Uow; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.Identity { public class SecurityStampValidator : AbpSecurityStampValidator { public SecurityStampValidator( IOptions options, SignInManager signInManager, ISystemClock systemClock, ILoggerFactory loggerFactory, IUnitOfWorkManager unitOfWorkManager) : base(options, signInManager, systemClock, loggerFactory, unitOfWorkManager) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Identity/SignInManager.cs ================================================ using Abp.Authorization; using Abp.Configuration; using Abp.Domain.Uow; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.Identity { public class SignInManager : AbpSignInManager { public SignInManager( UserManager userManager, IHttpContextAccessor contextAccessor, UserClaimsPrincipalFactory claimsFactory, IOptions optionsAccessor, ILogger> logger, IUnitOfWorkManager unitOfWorkManager, ISettingManager settingManager, IAuthenticationSchemeProvider schemes, IUserConfirmation userConfirmation) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, unitOfWorkManager, settingManager, schemes, userConfirmation) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/AcmStatisticsBackendLocalizationConfigurer.cs ================================================ using Abp.Configuration.Startup; using Abp.Localization.Dictionaries; using Abp.Localization.Dictionaries.Xml; using Abp.Reflection.Extensions; namespace AcmStatisticsBackend.Localization { public static class AcmStatisticsBackendLocalizationConfigurer { public static void Configure(ILocalizationConfiguration localizationConfiguration) { localizationConfiguration.Sources.Add( new DictionaryBasedLocalizationSource(AcmStatisticsBackendConsts.LocalizationSourceName, new XmlEmbeddedFileLocalizationDictionaryProvider( typeof(AcmStatisticsBackendLocalizationConfigurer).GetAssembly(), "AcmStatisticsBackend.Localization.SourceFiles"))); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-es.xml ================================================  Buscar... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-fr.xml ================================================  Rechercher... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-it.xml ================================================  Indirizzo email non registrato. Login non ammesso. L'account è momentaneamente bloccato. Riprovare più tardi. Cerca... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-ja.xml ================================================  ユーザのメールアドレスを入力しないでください。 ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-lt.xml ================================================  Jūsų el. pašto adresas nepatvirtintas. Jūs negalite prisijungti. Vartotojo paskyra buvo užblokuota. Pabandykite dar kartą vėliau. Neveskite el. pašto adreso kaip vartotojo vardo. Palikite tuščią, kad perjungtumėte į priimantįjį Dabartinis savininkas Nepasirinkta Keisti Keisti savininką Multi Level Menu Atgal Sėkmingai užregistruota Jūsų el. pašto adresas turi būti aktyvuotas. Rolės Rodomas vardas Keisti Trinti Kurti naują rolę Rolės pavadinimas Veiksmai Prisijungimo veiksmas nepavyko. Pabandykite vėliau. Nepavyko patikrinti išorinio vartotojo Keisti rolę Keisti savininką Keisti vartotoją Savininkas su Id {0} yra neaktyvus Nežinomas savininko Id {0} Šis laukas yra privalomas Prašome palaukti... Administration Išvalyti visus Išvalyti kitus Etiketės nustatymai Leidimai Rolės aprašymas Atnaujinti Sukurti Vartotojo detalės Vartotojo rolės Patvirtinti slaptažodį Versija Įjungta Išjungta Ar tikrai norite pašalinti {0}? Pradėkite rašyti Apvalkalai Nustatymai ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-nl.xml ================================================  Uw email adres is nog niet bevestigd. U kan niet inloggen. De gebruikersaccount is geblokkeerd. Gelieve later opnieuw te proberen. Voer a.u.b. geen e-mailadres in als gebruikersnaam. Laat leeg om naar de host te gaan Huidige huurder Niet geselecteerd Wijzig Wijzig huurder Multi Level Menu Terug Met success geregistreerd Uw email adres moet geactiveerd worden Rollen Weergavenaam Bewerk Verwijder Maak nieuwe rol Rol Naam Acties De login operatie kon niet afgewerkt worden. Gelieve later opnieuw te proberen. De externe gebruiker kon niet gevalideerd worden Bewerk rol Bewerk huurder Bewerk gebruiker HuurderId {0} is niet actief Onbekend huurderId {0} ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-pt-BR.xml ================================================  Seu email não foi confirmado. Você não pode fazer login. Usuário bloqueado. Por favor, tente mais tarde. Por favor, não entre um email no nome de usuário. Deixe em branco para mudar para o host. Tenant atual Não selecionado Alterar Alterar tenant Menu multinível Voltar Registrado com sucesso Seu endereço de email deve ser ativado Funções Nome de apresentação Editar Excluir Criar nova função Nome da função Ações Operação de login não foi completada. Tente novamente mais tarde. Não foi possível validar um usuário externo Editar Função Editar tenant Editar usuário TenantId {0} não está ativo TenantId {0} não foi encontrado Campo obrigatório Aguarde... Administração Limpar todos Limpar outros Opções de Legenda/Rótulo Permissões Descrição da função Atualizar Criar Detalhes do usuário Funções de usuário Confirme a senha Versão Ligado Desligado Tem certeza que deseja excluir {0}? Excluído com sucesso Comece a escrever Temas Configurações Procurar Alterar Senha Resetar Senha Filtrar Todos Senha Atual Nova Senha Confirme a Nova Senha As senhas são diferentes As senhas precisam ter no mínimo 8 caracteres, contendo pelo menos uma letra minúscula, uma maiúscula e um número O usuário {0} será excluído. A função {0} será excluída e desassociada de todos os usuários pertencentes a ela. O Tenant {0} será excluído. Pesquisar... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-tr.xml ================================================  E-posta adresiniz doğrulanmadı, giriş yapamazsınız. Kullanıcı hesabı kilitlenmiş. Lütfen bir süre sonra tekrar deneyin. Lütfen kullanıcı adı alanına e-posta adresi girmeyin. Üst kullanıcıya geçiş için boş değer girin. Geçerli müşteri Seçilmemiş Değiştir Müşteri değiştir Çok Seviyeli Menü Geri Başarıyla kayıt olundu E-posta adresiniz etkinleştirilmeli. Roller Görünen ad Düzenle Sil Yeni rol oluştur Rol adı İşlemler Giriş işlemi başarısız! Lütfen daha sonra tekrar deneyiniz. Harici kullanıcı doğrulanamadı! Rolü düzenle Müşteri düzenle Kullanıcı düzenleme Müşteri id aktif değil: {0} Müşteri id aktif değil: {0} Bu alan zorunludur. Lütfen bekleyin... Yönetim Hepsini temizle Diğerlerini temizle Etikent seçenekleri Yetkiler Rol tanımı Yenile Oluştur Kullanıcı detayları Kullanıcı rolleri {0} kullanıcısı silinecektir. {0} rolü silinecek ve atanmış kullanıcılardan kaldırılacaktır. {0} müşterisi silinecektir. Ara... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend-zh-Hans.xml ================================================  AcmStatisticsBackend 请输入账户 请输入密码 © 2018 AcmStatisticsBackend 正在登陆,请稍候! 用户资料 用户 角色 租户 注销 菜单 页签操作 关闭所有 关闭其他 创建 添加 编辑 删除 查找 创建时间 操作 关键字 没有结果 请选择 请选择 提示 确定删除? 标题 内容 修改密码 密码复杂度要求不符. 密码至少需要一位是0到9的数字. 密码至少需要一位是a到z的小写字母. 密码至少需要包含一个特殊字符(非字母或数字的字符). 密码至少需要一位是A到Z的大写字母. 密码长度太短 用户名 名称 是否启用 最近登陆时间 角色名 显示名 描述 是否内置 全部 启用 未启用 取消 确定 创建新角色 角色详情 角色权限 编辑角色 确认删除该角色? 创建新用户 用户详情 用户角色 确认密码 邮箱地址 确认删除该用户? 编辑用户 创建新租户 数据库连接 管理员邮箱地址 默认密码为:{0} 确认删除该租户? 编辑租户 搜索... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Localization/SourceFiles/AcmStatisticsBackend.xml ================================================  Your email address is not confirmed. You can not login. The user account has been locked out. Please try again later. Please don't enter an email address for username. Leave empty to switch to the host Current tenant Not selected Change Change tenant Multi Level Menu Back Successfully registered Your email address should be activated Roles Display Name Edit Delete Create new role Role Name Actions Could not complete login operation. Please try again later. Could not validate external user Edit role Edit tenant Edit user TenantId {0} is not active Unknown tenantId {0} This field is required Please wait... Administration Clear all Clear others Label options Permissions Role description Refresh Create User details User roles Confirm password Version On Off Are you sure want to delete {0}? Successfully deleted Start Typing Skins Settings Filter Current Password New Password Confirm New Password Passwords do not match Passwords must be at least 8 characters, contain a lowercase, uppercase, and number User {0} will be deleted. Role {0} will be deleted and unassigned from all assigned users. Tenant {0} will be deleted. Search... ================================================ FILE: backend/src/AcmStatisticsBackend.Core/MultiTenancy/Tenant.cs ================================================ using Abp.MultiTenancy; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.MultiTenancy { public class Tenant : AbpTenant { public Tenant() { } public Tenant(string tenancyName, string name) : base(tenancyName, name) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/MultiTenancy/TenantManager.cs ================================================ using Abp.Application.Features; using Abp.Domain.Repositories; using Abp.MultiTenancy; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Editions; namespace AcmStatisticsBackend.MultiTenancy { public class TenantManager : AbpTenantManager { public TenantManager( IRepository tenantRepository, IRepository tenantFeatureRepository, EditionManager editionManager, IAbpZeroFeatureValueStore featureValueStore) : base( tenantRepository, tenantFeatureRepository, editionManager, featureValueStore) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AcmStatisticsBackend.Core")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("0fa75a5b-ab83-4fd0-b545-279774c01e87")] ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/CaptchaServiceClient.cs ================================================ using System.Threading.Tasks; using Abp.Dependency; using Flurl.Http; namespace AcmStatisticsBackend.ServiceClients { public class CaptchaServiceClient : ICaptchaServiceClient, ISingletonDependency { /// public async Task ValidateAsync(string id, string text) { var response = await "http://captcha-service/api/captcha-service/validate" .AllowHttpStatus("400") .PostUrlEncodedAsync(new { id = id, text = text, }) .ReceiveJson(); var result = new CaptchaServiceValidateResult { Correct = !response.error, }; if (response.error) { result.ErrorMessage = response.message; } return result; } private class CaptchaServiceValidateRestResponse { // rest 里不是大写 #pragma warning disable SA1300 public bool error { get; set; } public string message { get; set; } #pragma warning restore SA1300 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/CaptchaServiceValidateResult.cs ================================================ namespace AcmStatisticsBackend.ServiceClients { /// /// 的返回值 /// public class CaptchaServiceValidateResult { /// /// 验证结果是否正确 /// public bool Correct { get; set; } /// /// 如果不正确,这里存放错误信息 /// public string ErrorMessage { get; set; } = ""; } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/CrawlerApiBackendClient.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Abp.Dependency; using Flurl.Http; namespace AcmStatisticsBackend.ServiceClients { public class CrawlerApiBackendClient : ICrawlerApiBackendClient, ISingletonDependency { private IReadOnlyCollection _cachedMeta = null; public async Task> GetCrawlerMeta() { if (_cachedMeta == null) { var res = await "http://crawler-api-backend/api/crawlers/" .GetJsonAsync(); _cachedMeta = res.data .Select(pair => new CrawlerMetaItem { CrawlerName = pair.Key, CrawlerTitle = pair.Value.title, CrawlerDescription = pair.Value.description, Url = pair.Value.url, IsVirtualJudge = pair.Value.virtual_judge == true, }) .ToList(); } return _cachedMeta; } // Not capitalized in json #pragma warning disable SA1300 private class GetMetaReturn { public bool error { get; set; } public IDictionary data { get; set; } } private class DataItem { public string title { get; set; } public string description { get; set; } public string url { get; set; } public bool? virtual_judge { get; set; } } #pragma warning restore SA1300 } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/CrawlerMetaItem.cs ================================================ using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; namespace AcmStatisticsBackend.ServiceClients { public class CrawlerMetaItem { [Required] public string CrawlerName { get; set; } [Required] public string CrawlerTitle { get; set; } [AllowNull] public string CrawlerDescription { get; set; } [Required] public string Url { get; set; } public bool IsVirtualJudge { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/ICaptchaServiceClient.cs ================================================ using System.Threading.Tasks; namespace AcmStatisticsBackend.ServiceClients { public interface ICaptchaServiceClient { /// /// 验证码是否正确 /// /// 验证码的ID /// 用户输入的验证码 /// 验证结果。如果不正确,返回(false, 错误信息) Task ValidateAsync(string id, string text); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/ServiceClients/ICrawlerApiBackendClient.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; namespace AcmStatisticsBackend.ServiceClients { public interface ICrawlerApiBackendClient { /// /// Get the meta data of crawlers /// Task> GetCrawlerMeta(); } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Settings/UserSettingAttribute.cs ================================================ using System; using System.ComponentModel.DataAnnotations; using Abp.Domain.Entities; using Abp.Domain.Entities.Auditing; using AcmStatisticsBackend.Authorization.Users; namespace AcmStatisticsBackend.Settings { /// /// Setting attributes for each user. /// public class UserSettingAttribute : Entity, IAudited { [Required] public User User { get; set; } public long UserId { get; set; } /// /// The time (UTC) of last time zone changed. /// public DateTime? LastTimeZoneChangedTime { get; set; } public DateTime CreationTime { get; set; } public long? CreatorUserId { get; set; } public DateTime? LastModificationTime { get; set; } public long? LastModifierUserId { get; set; } public User CreatorUser { get; set; } public User LastModifierUser { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Timing/AppTimes.cs ================================================ using System; using Abp.Dependency; namespace AcmStatisticsBackend.Timing { public class AppTimes : ISingletonDependency { /// /// Gets or sets the startup time of the application. /// public DateTime StartupTime { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Validation/ValidationHelper.cs ================================================ using System.Text.RegularExpressions; using Abp.Extensions; namespace AcmStatisticsBackend.Validation { public static class ValidationHelper { public const string EmailRegex = @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; public static bool IsEmail(string value) { if (value.IsNullOrEmpty()) { return false; } var regex = new Regex(EmailRegex); return regex.IsMatch(value); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Core/Web/WebContentFolderHelper.cs ================================================ using System; using System.IO; using System.Linq; using Abp.Reflection.Extensions; namespace AcmStatisticsBackend.Web { /// /// This class is used to find root path of the web project in; /// unit tests (to find views) and entity framework core command line commands (to find conn string). /// public static class WebContentDirectoryFinder { public static string CalculateContentRootFolder() { var coreAssemblyDirectoryPath = Path.GetDirectoryName(typeof(AcmStatisticsBackendCoreModule).GetAssembly().Location); if (coreAssemblyDirectoryPath == null) { throw new Exception("Could not find location of AcmStatisticsBackend.Core assembly!"); } var directoryInfo = new DirectoryInfo(coreAssemblyDirectoryPath); while (!DirectoryContains(directoryInfo.FullName, "AcmStatisticsBackend.sln")) { if (directoryInfo.Parent == null) { throw new Exception("Could not find content root folder!"); } directoryInfo = directoryInfo.Parent; } var webMvcFolder = Path.Combine(directoryInfo.FullName, "src", "AcmStatisticsBackend.Web.Mvc"); if (Directory.Exists(webMvcFolder)) { return webMvcFolder; } var webHostFolder = Path.Combine(directoryInfo.FullName, "src", "AcmStatisticsBackend.Web.Host"); if (Directory.Exists(webHostFolder)) { return webHostFolder; } throw new Exception("Could not find root folder of the web project!"); } private static bool DirectoryContains(string directory, string fileName) { return Directory.GetFiles(directory).Any(filePath => string.Equals(Path.GetFileName(filePath), fileName)); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/AcmStatisticsBackend.EntityFrameworkCore.csproj ================================================ net8.0 AcmStatisticsBackend true true true all runtime; build; native; contentfiles; analyzers ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/AbpZeroDbMigrator.cs ================================================ using Abp.Domain.Uow; using Abp.EntityFrameworkCore; using Abp.MultiTenancy; using Abp.Zero.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore { public class AbpZeroDbMigrator : AbpZeroDbMigrator { public AbpZeroDbMigrator( IUnitOfWorkManager unitOfWorkManager, IDbPerTenantConnectionStringResolver connectionStringResolver, IDbContextResolver dbContextResolver) : base( unitOfWorkManager, connectionStringResolver, dbContextResolver) { } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/AcmStatisticsBackendDbContext.cs ================================================ using System.Collections.Generic; using Abp.Json; using Abp.Zero.EntityFrameworkCore; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.MultiTenancy; using AcmStatisticsBackend.Settings; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; namespace AcmStatisticsBackend.EntityFrameworkCore { public class AcmStatisticsBackendDbContext : AbpZeroDbContext { /* Define a DbSet for each entity of the application */ public DbSet DefaultQueries { get; set; } public DbSet QueryHistories { get; set; } public DbSet QueryWorkerHistories { get; set; } public DbSet UserSettingAttributes { get; set; } public DbSet QuerySummaries { get; set; } public DbSet QueryCrawlerSummaries { get; set; } public DbSet UsernameInCrawler { get; set; } public AcmStatisticsBackendDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity() .Property(e => e.UsernamesInCrawlers) .HasConversion( v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject>>(v)); modelBuilder.Entity() .Property(e => e.SolvedList) .HasConversion(v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject(v)); modelBuilder.Entity() .Property(e => e.SubmissionsByCrawlerName) .HasConversion(v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject>(v)); modelBuilder.Entity() .HasOne() .WithOne(e => e.QueryHistory) .HasForeignKey(e => e.QueryHistoryId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Property(e => e.SummaryWarnings) .HasConversion(v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject>(v)); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/AcmStatisticsBackendDbContextConfigurer.cs ================================================ using System.Data.Common; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore { public static class AcmStatisticsBackendDbContextConfigurer { public static void Configure(DbContextOptionsBuilder builder, string connectionString) { builder.UseMySql(connectionString, new MySqlServerVersion(new System.Version(8, 0))); } public static void Configure(DbContextOptionsBuilder builder, DbConnection connection) { builder.UseMySql(connection, new MySqlServerVersion(new System.Version(8, 0))); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/AcmStatisticsBackendDbContextFactory.cs ================================================ using AcmStatisticsBackend.Configuration; using AcmStatisticsBackend.Web; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; namespace AcmStatisticsBackend.EntityFrameworkCore { /* This class is needed to run "dotnet ef ..." commands from command line on development. Not used anywhere else */ public class AcmStatisticsBackendDbContextFactory : IDesignTimeDbContextFactory { public AcmStatisticsBackendDbContext CreateDbContext(string[] args) { var builder = new DbContextOptionsBuilder(); var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder()); AcmStatisticsBackendDbContextConfigurer.Configure(builder, configuration.GetConnectionString(AcmStatisticsBackendConsts.ConnectionStringName)); return new AcmStatisticsBackendDbContext(builder.Options); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/AcmStatisticsBackendEntityFrameworkModule.cs ================================================ using Abp.Domain.Uow; using Abp.EntityFrameworkCore; using Abp.EntityFrameworkCore.Configuration; using Abp.Modules; using Abp.MultiTenancy; using Abp.Reflection.Extensions; using Abp.Zero.EntityFrameworkCore; using AcmStatisticsBackend.EntityFrameworkCore.Seed; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore { [DependsOn( typeof(AcmStatisticsBackendCoreModule), typeof(AbpZeroCoreEntityFrameworkCoreModule))] public class AcmStatisticsBackendEntityFrameworkModule : AbpModule { /* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */ public bool SkipDbContextRegistration { get; set; } public bool SkipDbSeed { get; set; } public override void PreInitialize() { if (!SkipDbContextRegistration) { Configuration.Modules.AbpEfCore().AddDbContext(options => { if (options.ExistingConnection != null) { AcmStatisticsBackendDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection); } else { AcmStatisticsBackendDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString); } }); } } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AcmStatisticsBackendEntityFrameworkModule).GetAssembly()); } public override void PostInitialize() { if (!SkipDbContextRegistration) { var dbContextProvider = IocManager.Resolve>(); var unitOfWorkManager = IocManager.Resolve(); using (var unitOfWork = unitOfWorkManager.Begin()) { var context = dbContextProvider.GetDbContext(MultiTenancySides.Host); // Removes actual connection as it has been enlisted in a non needed transaction for migration context.Database.CloseConnection(); context.Database.Migrate(); } } if (!SkipDbSeed) { SeedHelper.SeedHostDb(IocManager); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Repositories/AcmStatisticsBackendRepositoryBase.cs ================================================ using Abp.Domain.Entities; using Abp.Domain.Repositories; using Abp.EntityFrameworkCore; using Abp.EntityFrameworkCore.Repositories; namespace AcmStatisticsBackend.EntityFrameworkCore.Repositories { /// /// Base class for custom repositories of the application. /// /// Entity type. /// Primary key type of the entity. public abstract class AcmStatisticsBackendRepositoryBase : EfCoreRepositoryBase where TEntity : class, IEntity { protected AcmStatisticsBackendRepositoryBase(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } // Add your common methods for all repositories } /// /// Base class for custom repositories of the application. /// This is a shortcut of for primary key. /// /// Entity type. public abstract class AcmStatisticsBackendRepositoryBase : AcmStatisticsBackendRepositoryBase, IRepository where TEntity : class, IEntity { protected AcmStatisticsBackendRepositoryBase(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } // Do not add any method here, add to the class above (since this inherits it)!!! } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Host/DefaultEditionCreator.cs ================================================ using System.Linq; using Abp.Application.Editions; using Abp.Application.Features; using AcmStatisticsBackend.Editions; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Host { public class DefaultEditionCreator { private readonly AcmStatisticsBackendDbContext _context; public DefaultEditionCreator(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { CreateEditions(); } private void CreateEditions() { var defaultEdition = _context.Editions.IgnoreQueryFilters().FirstOrDefault(e => e.Name == EditionManager.DefaultEditionName); if (defaultEdition == null) { defaultEdition = new Edition { Name = EditionManager.DefaultEditionName, DisplayName = EditionManager.DefaultEditionName }; _context.Editions.Add(defaultEdition); _context.SaveChanges(); /* Add desired features to the standard edition, if wanted... */ } } private void CreateFeatureIfNotExists(int editionId, string featureName, bool isEnabled) { if (_context.EditionFeatureSettings.IgnoreQueryFilters().Any(ef => ef.EditionId == editionId && ef.Name == featureName)) { return; } _context.EditionFeatureSettings.Add(new EditionFeatureSetting { Name = featureName, Value = isEnabled.ToString(), EditionId = editionId, }); _context.SaveChanges(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Host/DefaultLanguagesCreator.cs ================================================ using System.Collections.Generic; using System.Linq; using Abp.Localization; using Abp.MultiTenancy; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Host { public class DefaultLanguagesCreator { public static List InitialLanguages => GetInitialLanguages(); private readonly AcmStatisticsBackendDbContext _context; private static List GetInitialLanguages() { var tenantId = AcmStatisticsBackendConsts.MultiTenancyEnabled ? null : (int?)MultiTenancyConsts.DefaultTenantId; return new List { new ApplicationLanguage(tenantId, "en", "English", "famfamfam-flags gb"), new ApplicationLanguage(tenantId, "ar", "العربية", "famfamfam-flags sa"), new ApplicationLanguage(tenantId, "de", "German", "famfamfam-flags de"), new ApplicationLanguage(tenantId, "it", "Italiano", "famfamfam-flags it"), new ApplicationLanguage(tenantId, "fr", "Français", "famfamfam-flags fr"), new ApplicationLanguage(tenantId, "pt-BR", "Português", "famfamfam-flags br"), new ApplicationLanguage(tenantId, "tr", "Türkçe", "famfamfam-flags tr"), new ApplicationLanguage(tenantId, "ru", "Русский", "famfamfam-flags ru"), new ApplicationLanguage(tenantId, "zh-Hans", "简体中文", "famfamfam-flags cn"), new ApplicationLanguage(tenantId, "es-MX", "Español México", "famfamfam-flags mx"), new ApplicationLanguage(tenantId, "nl", "Nederlands", "famfamfam-flags nl"), new ApplicationLanguage(tenantId, "ja", "日本語", "famfamfam-flags jp"), }; } public DefaultLanguagesCreator(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { CreateLanguages(); } private void CreateLanguages() { foreach (var language in InitialLanguages) { AddLanguageIfNotExists(language); } } private void AddLanguageIfNotExists(ApplicationLanguage language) { if (_context.Languages.IgnoreQueryFilters().Any(l => l.TenantId == language.TenantId && l.Name == language.Name)) { return; } _context.Languages.Add(language); _context.SaveChanges(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Host/DefaultSettingsCreator.cs ================================================ using System.Linq; using Abp.Configuration; using Abp.Localization; using Abp.MultiTenancy; using Abp.Net.Mail; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Host { public class DefaultSettingsCreator { private readonly AcmStatisticsBackendDbContext _context; public DefaultSettingsCreator(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { int? tenantId = null; if (AcmStatisticsBackendConsts.MultiTenancyEnabled == false) { tenantId = MultiTenancyConsts.DefaultTenantId; } // Emailing AddSettingIfNotExists(EmailSettingNames.DefaultFromAddress, "admin@mydomain.com", tenantId); AddSettingIfNotExists(EmailSettingNames.DefaultFromDisplayName, "mydomain.com mailer", tenantId); // Languages AddSettingIfNotExists(LocalizationSettingNames.DefaultLanguage, "en", tenantId); } private void AddSettingIfNotExists(string name, string value, int? tenantId = null) { if (_context.Settings.IgnoreQueryFilters().Any(s => s.Name == name && s.TenantId == tenantId && s.UserId == null)) { return; } _context.Settings.Add(new Setting(tenantId, null, name, value)); _context.SaveChanges(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Host/HostRoleAndUserCreator.cs ================================================ using System.Linq; using Abp.Authorization; using Abp.Authorization.Roles; using Abp.Authorization.Users; using Abp.MultiTenancy; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Configuration; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Host { public class HostRoleAndUserCreator { private readonly AcmStatisticsBackendDbContext _context; public HostRoleAndUserCreator(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { CreateHostRoleAndUsers(); } private void CreateHostRoleAndUsers() { // Admin role for host var adminRoleForHost = _context.Roles.IgnoreQueryFilters().FirstOrDefault(r => r.TenantId == null && r.Name == StaticRoleNames.Host.Admin); if (adminRoleForHost == null) { adminRoleForHost = _context.Roles.Add(new Role(null, StaticRoleNames.Host.Admin, StaticRoleNames.Host.Admin) { IsStatic = true, IsDefault = true }).Entity; _context.SaveChanges(); } // Grant all permissions to admin role for host var grantedPermissions = _context.Permissions.IgnoreQueryFilters() .OfType() .Where(p => p.TenantId == null && p.RoleId == adminRoleForHost.Id) .Select(p => p.Name) .ToList(); var permissions = PermissionFinder .GetAllPermissions(new AcmStatisticsBackendAuthorizationProvider()) .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Host) && !grantedPermissions.Contains(p.Name)) .ToList(); if (permissions.Any()) { _context.Permissions.AddRange( permissions.Select(permission => new RolePermissionSetting { TenantId = null, Name = permission.Name, IsGranted = true, RoleId = adminRoleForHost.Id, })); _context.SaveChanges(); } // Admin user for host var adminUserForHost = _context.Users.IgnoreQueryFilters().FirstOrDefault(u => u.TenantId == null && u.UserName == AbpUserBase.AdminUserName); if (adminUserForHost == null) { var user = new User { TenantId = null, UserName = AbpUserBase.AdminUserName, Name = "admin", Surname = "admin", EmailAddress = "admin@aspnetboilerplate.com", IsEmailConfirmed = true, IsActive = true, }; var adminPassword = AppEnvironmentVariables.DefaultAdminPassword; user.Password = new PasswordHasher(new OptionsWrapper(new PasswordHasherOptions())).HashPassword(user, adminPassword); user.SetNormalizedNames(); adminUserForHost = _context.Users.Add(user).Entity; _context.SaveChanges(); // Assign Admin role to admin user _context.UserRoles.Add(new UserRole(null, adminUserForHost.Id, adminRoleForHost.Id)); _context.SaveChanges(); _context.SaveChanges(); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Host/InitialHostDbBuilder.cs ================================================ namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Host { public class InitialHostDbBuilder { private readonly AcmStatisticsBackendDbContext _context; public InitialHostDbBuilder(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { new DefaultEditionCreator(_context).Create(); new DefaultLanguagesCreator(_context).Create(); new HostRoleAndUserCreator(_context).Create(); new DefaultSettingsCreator(_context).Create(); _context.SaveChanges(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/SeedHelper.cs ================================================ using System; using System.Transactions; using Abp.Dependency; using Abp.Domain.Uow; using Abp.EntityFrameworkCore.Uow; using Abp.MultiTenancy; using AcmStatisticsBackend.EntityFrameworkCore.Seed.Host; using AcmStatisticsBackend.EntityFrameworkCore.Seed.Tenants; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed { public static class SeedHelper { public static void SeedHostDb(IIocResolver iocResolver) { WithDbContext(iocResolver, SeedHostDb); } public static void SeedHostDb(AcmStatisticsBackendDbContext context) { context.SuppressAutoSetTenantId = true; // Host seed new InitialHostDbBuilder(context).Create(); // Default tenant seed (in host database). new DefaultTenantBuilder(context).Create(); new TenantRoleAndUserBuilder(context, 1).Create(); } private static void WithDbContext(IIocResolver iocResolver, Action contextAction) where TDbContext : DbContext { using (var uowManager = iocResolver.ResolveAsDisposable()) { using (var uow = uowManager.Object.Begin(TransactionScopeOption.Suppress)) { var context = uowManager.Object.Current.GetDbContext(MultiTenancySides.Host); contextAction(context); uow.Complete(); } } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Tenants/DefaultTenantBuilder.cs ================================================ using System.Linq; using Abp.MultiTenancy; using AcmStatisticsBackend.Editions; using AcmStatisticsBackend.MultiTenancy; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Tenants { public class DefaultTenantBuilder { private readonly AcmStatisticsBackendDbContext _context; public DefaultTenantBuilder(AcmStatisticsBackendDbContext context) { _context = context; } public void Create() { CreateDefaultTenant(); } private void CreateDefaultTenant() { // Default tenant var defaultTenant = _context.Tenants.IgnoreQueryFilters().FirstOrDefault(t => t.TenancyName == AbpTenantBase.DefaultTenantName); if (defaultTenant == null) { defaultTenant = new Tenant(AbpTenantBase.DefaultTenantName, AbpTenantBase.DefaultTenantName); var defaultEdition = _context.Editions.IgnoreQueryFilters().FirstOrDefault(e => e.Name == EditionManager.DefaultEditionName); if (defaultEdition != null) { defaultTenant.EditionId = defaultEdition.Id; } _context.Tenants.Add(defaultTenant); _context.SaveChanges(); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/EntityFrameworkCore/Seed/Tenants/TenantRoleAndUserBuilder.cs ================================================ using System.Linq; using Abp.Authorization; using Abp.Authorization.Roles; using Abp.Authorization.Users; using Abp.MultiTenancy; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Roles; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Configuration; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace AcmStatisticsBackend.EntityFrameworkCore.Seed.Tenants { public class TenantRoleAndUserBuilder { private readonly AcmStatisticsBackendDbContext _context; private readonly int _tenantId; public TenantRoleAndUserBuilder(AcmStatisticsBackendDbContext context, int tenantId) { _context = context; _tenantId = tenantId; } public void Create() { CreateAdminRoleAndUser(); CreateUserRole(); } private void CreateAdminRoleAndUser() { // Admin role var adminRole = _context.Roles.IgnoreQueryFilters() .FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.Admin); if (adminRole == null) { adminRole = _context.Roles .Add(new Role(_tenantId, StaticRoleNames.Tenants.Admin, StaticRoleNames.Tenants.Admin) { IsStatic = true, }).Entity; _context.SaveChanges(); } // Grant all permissions to admin role var grantedPermissions = _context.Permissions.IgnoreQueryFilters() .OfType() .Where(p => p.TenantId == _tenantId && p.RoleId == adminRole.Id) .Select(p => p.Name) .ToList(); var permissions = PermissionFinder .GetAllPermissions(new AcmStatisticsBackendAuthorizationProvider()) .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Tenant) && !grantedPermissions.Contains(p.Name)) .ToList(); if (permissions.Any()) { _context.Permissions.AddRange( permissions.Select(permission => new RolePermissionSetting { TenantId = _tenantId, Name = permission.Name, IsGranted = true, RoleId = adminRole.Id, })); _context.SaveChanges(); } // Admin user var adminUser = _context.Users.IgnoreQueryFilters() .FirstOrDefault(u => u.TenantId == _tenantId && u.UserName == AbpUserBase.AdminUserName); if (adminUser == null) { adminUser = User.CreateTenantAdminUser(_tenantId, "admin@defaulttenant.com"); var adminPassword = AppEnvironmentVariables.DefaultAdminPassword; adminUser.Password = new PasswordHasher(new OptionsWrapper(new PasswordHasherOptions())) .HashPassword(adminUser, adminPassword); adminUser.IsEmailConfirmed = true; adminUser.IsActive = true; _context.Users.Add(adminUser); _context.SaveChanges(); // Assign Admin role to admin user _context.UserRoles.Add(new UserRole(_tenantId, adminUser.Id, adminRole.Id)); _context.SaveChanges(); } } private void CreateUserRole() { // set User role as default role var userRole = _context.Roles.IgnoreQueryFilters() .FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.User); if (userRole == null) { userRole = _context.Roles.Add( new Role(_tenantId, StaticRoleNames.Tenants.User, StaticRoleNames.Tenants.User) { IsStatic = true, IsDefault = true, }).Entity; _context.SaveChanges(); } GrantPermissionForRule(userRole, new[] { PermissionNames.Statistics_DefaultQuery, PermissionNames.AcHistory_Histories, PermissionNames.Settings_Update, }); } private void GrantPermissionForRule(Role role, params string[] permissionNames) { var granted = _context.RolePermissions .Where(item => item.TenantId == _tenantId && item.RoleId == role.Id) .Select(item => item.Name); var shouldGrant = permissionNames.Except(granted); foreach (var name in shouldGrant) { _context.Permissions.Add(new RolePermissionSetting { RoleId = role.Id, TenantId = _tenantId, IsGranted = true, Name = name, }); } _context.SaveChanges(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200325035348_Init.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200325035348_Init")] partial class Init { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.1") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200325035348_Init.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class Init : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "AbpAuditLogs", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: true), ServiceName = table.Column(maxLength: 256, nullable: true), MethodName = table.Column(maxLength: 256, nullable: true), Parameters = table.Column(maxLength: 1024, nullable: true), ReturnValue = table.Column(nullable: true), ExecutionTime = table.Column(nullable: false), ExecutionDuration = table.Column(nullable: false), ClientIpAddress = table.Column(maxLength: 64, nullable: true), ClientName = table.Column(maxLength: 128, nullable: true), BrowserInfo = table.Column(maxLength: 512, nullable: true), Exception = table.Column(maxLength: 2000, nullable: true), ImpersonatorUserId = table.Column(nullable: true), ImpersonatorTenantId = table.Column(nullable: true), CustomData = table.Column(maxLength: 2000, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpBackgroundJobs", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), JobType = table.Column(maxLength: 512, nullable: false), JobArgs = table.Column(maxLength: 1048576, nullable: false), TryCount = table.Column(nullable: false), NextTryTime = table.Column(nullable: false), LastTryTime = table.Column(nullable: true), IsAbandoned = table.Column(nullable: false), Priority = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpEditions", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), Name = table.Column(maxLength: 32, nullable: false), DisplayName = table.Column(maxLength: 64, nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpEditions", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpEntityChangeSets", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), BrowserInfo = table.Column(maxLength: 512, nullable: true), ClientIpAddress = table.Column(maxLength: 64, nullable: true), ClientName = table.Column(maxLength: 128, nullable: true), CreationTime = table.Column(nullable: false), ExtensionData = table.Column(nullable: true), ImpersonatorTenantId = table.Column(nullable: true), ImpersonatorUserId = table.Column(nullable: true), Reason = table.Column(maxLength: 256, nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityChangeSets", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpLanguages", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), TenantId = table.Column(nullable: true), Name = table.Column(maxLength: 128, nullable: false), DisplayName = table.Column(maxLength: 64, nullable: false), Icon = table.Column(maxLength: 128, nullable: true), IsDisabled = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpLanguages", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpLanguageTexts", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), LanguageName = table.Column(maxLength: 128, nullable: false), Source = table.Column(maxLength: 128, nullable: false), Key = table.Column(maxLength: 256, nullable: false), Value = table.Column(maxLength: 67108864, nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpLanguageTexts", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpNotifications", columns: table => new { Id = table.Column(nullable: false), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), NotificationName = table.Column(maxLength: 96, nullable: false), Data = table.Column(maxLength: 1048576, nullable: true), DataTypeName = table.Column(maxLength: 512, nullable: true), EntityTypeName = table.Column(maxLength: 250, nullable: true), EntityTypeAssemblyQualifiedName = table.Column(maxLength: 512, nullable: true), EntityId = table.Column(maxLength: 96, nullable: true), Severity = table.Column(nullable: false), UserIds = table.Column(maxLength: 131072, nullable: true), ExcludedUserIds = table.Column(maxLength: 131072, nullable: true), TenantIds = table.Column(maxLength: 131072, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpNotifications", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpNotificationSubscriptions", columns: table => new { Id = table.Column(nullable: false), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), NotificationName = table.Column(maxLength: 96, nullable: true), EntityTypeName = table.Column(maxLength: 250, nullable: true), EntityTypeAssemblyQualifiedName = table.Column(maxLength: 512, nullable: true), EntityId = table.Column(maxLength: 96, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpNotificationSubscriptions", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpOrganizationUnitRoles", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), RoleId = table.Column(nullable: false), OrganizationUnitId = table.Column(nullable: false), IsDeleted = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpOrganizationUnits", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), TenantId = table.Column(nullable: true), ParentId = table.Column(nullable: true), Code = table.Column(maxLength: 95, nullable: false), DisplayName = table.Column(maxLength: 128, nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); table.ForeignKey( name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", column: x => x.ParentId, principalTable: "AbpOrganizationUnits", principalColumn: "Id", onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateTable( name: "AbpTenantNotifications", columns: table => new { Id = table.Column(nullable: false), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), NotificationName = table.Column(maxLength: 96, nullable: false), Data = table.Column(maxLength: 1048576, nullable: true), DataTypeName = table.Column(maxLength: 512, nullable: true), EntityTypeName = table.Column(maxLength: 250, nullable: true), EntityTypeAssemblyQualifiedName = table.Column(maxLength: 512, nullable: true), EntityId = table.Column(maxLength: 96, nullable: true), Severity = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpTenantNotifications", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpUserAccounts", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), UserLinkId = table.Column(nullable: true), UserName = table.Column(maxLength: 256, nullable: true), EmailAddress = table.Column(maxLength: 256, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpUserAccounts", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpUserLoginAttempts", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), TenantId = table.Column(nullable: true), TenancyName = table.Column(maxLength: 64, nullable: true), UserId = table.Column(nullable: true), UserNameOrEmailAddress = table.Column(maxLength: 256, nullable: true), ClientIpAddress = table.Column(maxLength: 64, nullable: true), ClientName = table.Column(maxLength: 128, nullable: true), BrowserInfo = table.Column(maxLength: 512, nullable: true), Result = table.Column(nullable: false), CreationTime = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpUserLoginAttempts", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpUserNotifications", columns: table => new { Id = table.Column(nullable: false), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), TenantNotificationId = table.Column(nullable: false), State = table.Column(nullable: false), CreationTime = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpUserNotifications", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpUserOrganizationUnits", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), OrganizationUnitId = table.Column(nullable: false), IsDeleted = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpUserOrganizationUnits", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), AuthenticationSource = table.Column(maxLength: 64, nullable: true), UserName = table.Column(maxLength: 256, nullable: false), TenantId = table.Column(nullable: true), EmailAddress = table.Column(maxLength: 256, nullable: false), Name = table.Column(maxLength: 64, nullable: false), Surname = table.Column(maxLength: 64, nullable: false), Password = table.Column(maxLength: 128, nullable: false), EmailConfirmationCode = table.Column(maxLength: 328, nullable: true), PasswordResetCode = table.Column(maxLength: 328, nullable: true), LockoutEndDateUtc = table.Column(nullable: true), AccessFailedCount = table.Column(nullable: false), IsLockoutEnabled = table.Column(nullable: false), PhoneNumber = table.Column(maxLength: 32, nullable: true), IsPhoneNumberConfirmed = table.Column(nullable: false), SecurityStamp = table.Column(maxLength: 128, nullable: true), IsTwoFactorEnabled = table.Column(nullable: false), IsEmailConfirmed = table.Column(nullable: false), IsActive = table.Column(nullable: false), NormalizedUserName = table.Column(maxLength: 256, nullable: false), NormalizedEmailAddress = table.Column(maxLength: 256, nullable: false), ConcurrencyStamp = table.Column(maxLength: 128, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpUsers", x => x.Id); table.ForeignKey( name: "FK_AbpUsers_AbpUsers_CreatorUserId", column: x => x.CreatorUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpUsers_AbpUsers_DeleterUserId", column: x => x.DeleterUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpUsers_AbpUsers_LastModifierUserId", column: x => x.LastModifierUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateTable( name: "AbpWebhookEvents", columns: table => new { Id = table.Column(nullable: false), WebhookName = table.Column(nullable: false), Data = table.Column(nullable: true), CreationTime = table.Column(nullable: false), TenantId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeletionTime = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpWebhookEvents", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpWebhookSubscriptions", columns: table => new { Id = table.Column(nullable: false), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), WebhookUri = table.Column(nullable: false), Secret = table.Column(nullable: false), IsActive = table.Column(nullable: false), Webhooks = table.Column(nullable: true), Headers = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpWebhookSubscriptions", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpFeatures", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), Name = table.Column(maxLength: 128, nullable: false), Value = table.Column(maxLength: 2000, nullable: false), Discriminator = table.Column(nullable: false), EditionId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpFeatures", x => x.Id); table.ForeignKey( name: "FK_AbpFeatures_AbpEditions_EditionId", column: x => x.EditionId, principalTable: "AbpEditions", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityChanges", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), ChangeTime = table.Column(nullable: false), ChangeType = table.Column(nullable: false), EntityChangeSetId = table.Column(nullable: false), EntityId = table.Column(maxLength: 48, nullable: true), EntityTypeFullName = table.Column(maxLength: 192, nullable: true), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); table.ForeignKey( name: "FK_AbpEntityChanges_AbpEntityChangeSets_EntityChangeSetId", column: x => x.EntityChangeSetId, principalTable: "AbpEntityChangeSets", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), TenantId = table.Column(nullable: true), Name = table.Column(maxLength: 32, nullable: false), DisplayName = table.Column(maxLength: 64, nullable: false), IsStatic = table.Column(nullable: false), IsDefault = table.Column(nullable: false), NormalizedName = table.Column(maxLength: 32, nullable: false), ConcurrencyStamp = table.Column(maxLength: 128, nullable: true), Description = table.Column(maxLength: 5000, nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpRoles", x => x.Id); table.ForeignKey( name: "FK_AbpRoles_AbpUsers_CreatorUserId", column: x => x.CreatorUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpRoles_AbpUsers_DeleterUserId", column: x => x.DeleterUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpRoles_AbpUsers_LastModifierUserId", column: x => x.LastModifierUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: true), Name = table.Column(maxLength: 256, nullable: false), Value = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpSettings", x => x.Id); table.ForeignKey( name: "FK_AbpSettings_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateTable( name: "AbpTenants", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), TenancyName = table.Column(maxLength: 64, nullable: false), Name = table.Column(maxLength: 128, nullable: false), ConnectionString = table.Column(maxLength: 1024, nullable: true), IsActive = table.Column(nullable: false), EditionId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpTenants", x => x.Id); table.ForeignKey( name: "FK_AbpTenants_AbpUsers_CreatorUserId", column: x => x.CreatorUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpTenants_AbpUsers_DeleterUserId", column: x => x.DeleterUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpTenants_AbpEditions_EditionId", column: x => x.EditionId, principalTable: "AbpEditions", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_AbpTenants_AbpUsers_LastModifierUserId", column: x => x.LastModifierUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateTable( name: "AbpUserClaims", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), ClaimType = table.Column(maxLength: 256, nullable: true), ClaimValue = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpUserClaims", x => x.Id); table.ForeignKey( name: "FK_AbpUserClaims_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpUserLogins", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), LoginProvider = table.Column(maxLength: 128, nullable: false), ProviderKey = table.Column(maxLength: 256, nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpUserLogins", x => x.Id); table.ForeignKey( name: "FK_AbpUserLogins_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpUserRoles", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), RoleId = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpUserRoles", x => x.Id); table.ForeignKey( name: "FK_AbpUserRoles_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpUserTokens", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), TenantId = table.Column(nullable: true), UserId = table.Column(nullable: false), LoginProvider = table.Column(maxLength: 128, nullable: true), Name = table.Column(maxLength: 128, nullable: true), Value = table.Column(maxLength: 512, nullable: true), ExpireDate = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpUserTokens", x => x.Id); table.ForeignKey( name: "FK_AbpUserTokens_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpWebhookSendAttempts", columns: table => new { Id = table.Column(nullable: false), WebhookEventId = table.Column(nullable: false), WebhookSubscriptionId = table.Column(nullable: false), Response = table.Column(nullable: true), ResponseStatusCode = table.Column(nullable: true), CreationTime = table.Column(nullable: false), LastModificationTime = table.Column(nullable: true), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpWebhookSendAttempts", x => x.Id); table.ForeignKey( name: "FK_AbpWebhookSendAttempts_AbpWebhookEvents_WebhookEventId", column: x => x.WebhookEventId, principalTable: "AbpWebhookEvents", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityPropertyChanges", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), EntityChangeId = table.Column(nullable: false), NewValue = table.Column(maxLength: 512, nullable: true), OriginalValue = table.Column(maxLength: 512, nullable: true), PropertyName = table.Column(maxLength: 96, nullable: true), PropertyTypeFullName = table.Column(maxLength: 192, nullable: true), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); table.ForeignKey( name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", column: x => x.EntityChangeId, principalTable: "AbpEntityChanges", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpPermissions", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), Name = table.Column(maxLength: 128, nullable: false), IsGranted = table.Column(nullable: false), Discriminator = table.Column(nullable: false), RoleId = table.Column(nullable: true), UserId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpPermissions", x => x.Id); table.ForeignKey( name: "FK_AbpPermissions_AbpRoles_RoleId", column: x => x.RoleId, principalTable: "AbpRoles", principalColumn: "Id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_AbpPermissions_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpRoleClaims", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), TenantId = table.Column(nullable: true), RoleId = table.Column(nullable: false), ClaimType = table.Column(maxLength: 256, nullable: true), ClaimValue = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); table.ForeignKey( name: "FK_AbpRoleClaims_AbpRoles_RoleId", column: x => x.RoleId, principalTable: "AbpRoles", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpAuditLogs_TenantId_ExecutionDuration", table: "AbpAuditLogs", columns: new[] { "TenantId", "ExecutionDuration" }); migrationBuilder.CreateIndex( name: "IX_AbpAuditLogs_TenantId_ExecutionTime", table: "AbpAuditLogs", columns: new[] { "TenantId", "ExecutionTime" }); migrationBuilder.CreateIndex( name: "IX_AbpAuditLogs_TenantId_UserId", table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", table: "AbpBackgroundJobs", columns: new[] { "IsAbandoned", "NextTryTime" }); migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_EntityChangeSetId", table: "AbpEntityChanges", column: "EntityChangeSetId"); migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_EntityTypeFullName_EntityId", table: "AbpEntityChanges", columns: new[] { "EntityTypeFullName", "EntityId" }); migrationBuilder.CreateIndex( name: "IX_AbpEntityChangeSets_TenantId_CreationTime", table: "AbpEntityChangeSets", columns: new[] { "TenantId", "CreationTime" }); migrationBuilder.CreateIndex( name: "IX_AbpEntityChangeSets_TenantId_Reason", table: "AbpEntityChangeSets", columns: new[] { "TenantId", "Reason" }); migrationBuilder.CreateIndex( name: "IX_AbpEntityChangeSets_TenantId_UserId", table: "AbpEntityChangeSets", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpEntityPropertyChanges_EntityChangeId", table: "AbpEntityPropertyChanges", column: "EntityChangeId"); migrationBuilder.CreateIndex( name: "IX_AbpFeatures_EditionId_Name", table: "AbpFeatures", columns: new[] { "EditionId", "Name" }); migrationBuilder.CreateIndex( name: "IX_AbpFeatures_TenantId_Name", table: "AbpFeatures", columns: new[] { "TenantId", "Name" }); migrationBuilder.CreateIndex( name: "IX_AbpLanguages_TenantId_Name", table: "AbpLanguages", columns: new[] { "TenantId", "Name" }); migrationBuilder.CreateIndex( name: "IX_AbpLanguageTexts_TenantId_Source_LanguageName_Key", table: "AbpLanguageTexts", columns: new[] { "TenantId", "Source", "LanguageName", "Key" }); migrationBuilder.CreateIndex( name: "IX_AbpNotificationSubscriptions_NotificationName_EntityTypeName~", table: "AbpNotificationSubscriptions", columns: new[] { "NotificationName", "EntityTypeName", "EntityId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpNotificationSubscriptions_TenantId_NotificationName_Entit~", table: "AbpNotificationSubscriptions", columns: new[] { "TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_TenantId_OrganizationUnitId", table: "AbpOrganizationUnitRoles", columns: new[] { "TenantId", "OrganizationUnitId" }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_TenantId_RoleId", table: "AbpOrganizationUnitRoles", columns: new[] { "TenantId", "RoleId" }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_ParentId", table: "AbpOrganizationUnits", column: "ParentId"); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits", columns: new[] { "TenantId", "Code" }); migrationBuilder.CreateIndex( name: "IX_AbpPermissions_TenantId_Name", table: "AbpPermissions", columns: new[] { "TenantId", "Name" }); migrationBuilder.CreateIndex( name: "IX_AbpPermissions_RoleId", table: "AbpPermissions", column: "RoleId"); migrationBuilder.CreateIndex( name: "IX_AbpPermissions_UserId", table: "AbpPermissions", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", column: "RoleId"); migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_TenantId_ClaimType", table: "AbpRoleClaims", columns: new[] { "TenantId", "ClaimType" }); migrationBuilder.CreateIndex( name: "IX_AbpRoles_CreatorUserId", table: "AbpRoles", column: "CreatorUserId"); migrationBuilder.CreateIndex( name: "IX_AbpRoles_DeleterUserId", table: "AbpRoles", column: "DeleterUserId"); migrationBuilder.CreateIndex( name: "IX_AbpRoles_LastModifierUserId", table: "AbpRoles", column: "LastModifierUserId"); migrationBuilder.CreateIndex( name: "IX_AbpRoles_TenantId_NormalizedName", table: "AbpRoles", columns: new[] { "TenantId", "NormalizedName" }); migrationBuilder.CreateIndex( name: "IX_AbpSettings_UserId", table: "AbpSettings", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpSettings_TenantId_Name_UserId", table: "AbpSettings", columns: new[] { "TenantId", "Name", "UserId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpTenantNotifications_TenantId", table: "AbpTenantNotifications", column: "TenantId"); migrationBuilder.CreateIndex( name: "IX_AbpTenants_CreatorUserId", table: "AbpTenants", column: "CreatorUserId"); migrationBuilder.CreateIndex( name: "IX_AbpTenants_DeleterUserId", table: "AbpTenants", column: "DeleterUserId"); migrationBuilder.CreateIndex( name: "IX_AbpTenants_EditionId", table: "AbpTenants", column: "EditionId"); migrationBuilder.CreateIndex( name: "IX_AbpTenants_LastModifierUserId", table: "AbpTenants", column: "LastModifierUserId"); migrationBuilder.CreateIndex( name: "IX_AbpTenants_TenancyName", table: "AbpTenants", column: "TenancyName"); migrationBuilder.CreateIndex( name: "IX_AbpUserAccounts_EmailAddress", table: "AbpUserAccounts", column: "EmailAddress"); migrationBuilder.CreateIndex( name: "IX_AbpUserAccounts_UserName", table: "AbpUserAccounts", column: "UserName"); migrationBuilder.CreateIndex( name: "IX_AbpUserAccounts_TenantId_EmailAddress", table: "AbpUserAccounts", columns: new[] { "TenantId", "EmailAddress" }); migrationBuilder.CreateIndex( name: "IX_AbpUserAccounts_TenantId_UserId", table: "AbpUserAccounts", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserAccounts_TenantId_UserName", table: "AbpUserAccounts", columns: new[] { "TenantId", "UserName" }); migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_TenantId_ClaimType", table: "AbpUserClaims", columns: new[] { "TenantId", "ClaimType" }); migrationBuilder.CreateIndex( name: "IX_AbpUserLoginAttempts_UserId_TenantId", table: "AbpUserLoginAttempts", columns: new[] { "UserId", "TenantId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserLoginAttempts_TenancyName_UserNameOrEmailAddress_Resu~", table: "AbpUserLoginAttempts", columns: new[] { "TenancyName", "UserNameOrEmailAddress", "Result" }); migrationBuilder.CreateIndex( name: "IX_AbpUserLogins_UserId", table: "AbpUserLogins", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpUserLogins_TenantId_UserId", table: "AbpUserLogins", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserLogins_TenantId_LoginProvider_ProviderKey", table: "AbpUserLogins", columns: new[] { "TenantId", "LoginProvider", "ProviderKey" }); migrationBuilder.CreateIndex( name: "IX_AbpUserNotifications_UserId_State_CreationTime", table: "AbpUserNotifications", columns: new[] { "UserId", "State", "CreationTime" }); migrationBuilder.CreateIndex( name: "IX_AbpUserOrganizationUnits_TenantId_OrganizationUnitId", table: "AbpUserOrganizationUnits", columns: new[] { "TenantId", "OrganizationUnitId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserOrganizationUnits_TenantId_UserId", table: "AbpUserOrganizationUnits", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserRoles_UserId", table: "AbpUserRoles", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpUserRoles_TenantId_RoleId", table: "AbpUserRoles", columns: new[] { "TenantId", "RoleId" }); migrationBuilder.CreateIndex( name: "IX_AbpUserRoles_TenantId_UserId", table: "AbpUserRoles", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpUsers_CreatorUserId", table: "AbpUsers", column: "CreatorUserId"); migrationBuilder.CreateIndex( name: "IX_AbpUsers_DeleterUserId", table: "AbpUsers", column: "DeleterUserId"); migrationBuilder.CreateIndex( name: "IX_AbpUsers_LastModifierUserId", table: "AbpUsers", column: "LastModifierUserId"); migrationBuilder.CreateIndex( name: "IX_AbpUsers_TenantId_NormalizedEmailAddress", table: "AbpUsers", columns: new[] { "TenantId", "NormalizedEmailAddress" }); migrationBuilder.CreateIndex( name: "IX_AbpUsers_TenantId_NormalizedUserName", table: "AbpUsers", columns: new[] { "TenantId", "NormalizedUserName" }); migrationBuilder.CreateIndex( name: "IX_AbpUserTokens_UserId", table: "AbpUserTokens", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AbpUserTokens_TenantId_UserId", table: "AbpUserTokens", columns: new[] { "TenantId", "UserId" }); migrationBuilder.CreateIndex( name: "IX_AbpWebhookSendAttempts_WebhookEventId", table: "AbpWebhookSendAttempts", column: "WebhookEventId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AbpAuditLogs"); migrationBuilder.DropTable( name: "AbpBackgroundJobs"); migrationBuilder.DropTable( name: "AbpEntityPropertyChanges"); migrationBuilder.DropTable( name: "AbpFeatures"); migrationBuilder.DropTable( name: "AbpLanguages"); migrationBuilder.DropTable( name: "AbpLanguageTexts"); migrationBuilder.DropTable( name: "AbpNotifications"); migrationBuilder.DropTable( name: "AbpNotificationSubscriptions"); migrationBuilder.DropTable( name: "AbpOrganizationUnitRoles"); migrationBuilder.DropTable( name: "AbpOrganizationUnits"); migrationBuilder.DropTable( name: "AbpPermissions"); migrationBuilder.DropTable( name: "AbpRoleClaims"); migrationBuilder.DropTable( name: "AbpSettings"); migrationBuilder.DropTable( name: "AbpTenantNotifications"); migrationBuilder.DropTable( name: "AbpTenants"); migrationBuilder.DropTable( name: "AbpUserAccounts"); migrationBuilder.DropTable( name: "AbpUserClaims"); migrationBuilder.DropTable( name: "AbpUserLoginAttempts"); migrationBuilder.DropTable( name: "AbpUserLogins"); migrationBuilder.DropTable( name: "AbpUserNotifications"); migrationBuilder.DropTable( name: "AbpUserOrganizationUnits"); migrationBuilder.DropTable( name: "AbpUserRoles"); migrationBuilder.DropTable( name: "AbpUserTokens"); migrationBuilder.DropTable( name: "AbpWebhookSendAttempts"); migrationBuilder.DropTable( name: "AbpWebhookSubscriptions"); migrationBuilder.DropTable( name: "AbpEntityChanges"); migrationBuilder.DropTable( name: "AbpRoles"); migrationBuilder.DropTable( name: "AbpEditions"); migrationBuilder.DropTable( name: "AbpWebhookEvents"); migrationBuilder.DropTable( name: "AbpEntityChangeSets"); migrationBuilder.DropTable( name: "AbpUsers"); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200410093107_AddDefaultQuery.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200410093107_AddDefaultQuery")] partial class AddDefaultQuery { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ParameterName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParameterName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.ToTable("AbpDynamicParameterValues"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("EntityFullName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.HasIndex("EntityFullName", "DynamicParameterId", "TenantId") .IsUnique(); b.ToTable("AbpEntityDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("EntityDynamicParameterId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EntityDynamicParameterId"); b.ToTable("AbpEntityDynamicParameterValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code") .IsUnique(); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany("DynamicParameterValues") .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany() .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.EntityDynamicParameter", "EntityDynamicParameter") .WithMany() .HasForeignKey("EntityDynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200410093107_AddDefaultQuery.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class AddDefaultQuery : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.DropIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits"); migrationBuilder.CreateTable( name: "AbpDynamicParameters", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), ParameterName = table.Column(nullable: true), InputType = table.Column(nullable: true), Permission = table.Column(nullable: true), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicParameters", x => x.Id); }); migrationBuilder.CreateTable( name: "DefaultQueries", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), IsDeleted = table.Column(nullable: false), DeleterUserId = table.Column(nullable: true), DeletionTime = table.Column(nullable: true), UserId = table.Column(nullable: false), MainUsername = table.Column(nullable: false), UsernamesInCrawlers = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_DefaultQueries", x => x.Id); table.ForeignKey( name: "FK_DefaultQueries_AbpUsers_CreatorUserId", column: x => x.CreatorUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_DefaultQueries_AbpUsers_DeleterUserId", column: x => x.DeleterUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_DefaultQueries_AbpUsers_LastModifierUserId", column: x => x.LastModifierUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_DefaultQueries_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpDynamicParameterValues", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), Value = table.Column(nullable: false), TenantId = table.Column(nullable: true), DynamicParameterId = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicParameterValues", x => x.Id); table.ForeignKey( name: "FK_AbpDynamicParameterValues_AbpDynamicParameters_DynamicParame~", column: x => x.DynamicParameterId, principalTable: "AbpDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityDynamicParameters", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), EntityFullName = table.Column(nullable: true), DynamicParameterId = table.Column(nullable: false), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityDynamicParameters", x => x.Id); table.ForeignKey( name: "FK_AbpEntityDynamicParameters_AbpDynamicParameters_DynamicParam~", column: x => x.DynamicParameterId, principalTable: "AbpDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityDynamicParameterValues", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), Value = table.Column(nullable: false), EntityId = table.Column(nullable: true), EntityDynamicParameterId = table.Column(nullable: false), TenantId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityDynamicParameterValues", x => x.Id); table.ForeignKey( name: "FK_AbpEntityDynamicParameterValues_AbpEntityDynamicParameters_E~", column: x => x.EntityDynamicParameterId, principalTable: "AbpEntityDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits", columns: new[] { "TenantId", "Code" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpDynamicParameters_ParameterName_TenantId", table: "AbpDynamicParameters", columns: new[] { "ParameterName", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpDynamicParameterValues_DynamicParameterId", table: "AbpDynamicParameterValues", column: "DynamicParameterId"); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameters_DynamicParameterId", table: "AbpEntityDynamicParameters", column: "DynamicParameterId"); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameters_EntityFullName_DynamicParameterId~", table: "AbpEntityDynamicParameters", columns: new[] { "EntityFullName", "DynamicParameterId", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameterValues_EntityDynamicParameterId", table: "AbpEntityDynamicParameterValues", column: "EntityDynamicParameterId"); migrationBuilder.CreateIndex( name: "IX_DefaultQueries_CreatorUserId", table: "DefaultQueries", column: "CreatorUserId"); migrationBuilder.CreateIndex( name: "IX_DefaultQueries_DeleterUserId", table: "DefaultQueries", column: "DeleterUserId"); migrationBuilder.CreateIndex( name: "IX_DefaultQueries_LastModifierUserId", table: "DefaultQueries", column: "LastModifierUserId"); migrationBuilder.CreateIndex( name: "IX_DefaultQueries_UserId", table: "DefaultQueries", column: "UserId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AbpDynamicParameterValues"); migrationBuilder.DropTable( name: "AbpEntityDynamicParameterValues"); migrationBuilder.DropTable( name: "DefaultQueries"); migrationBuilder.DropTable( name: "AbpEntityDynamicParameters"); migrationBuilder.DropTable( name: "AbpDynamicParameters"); migrationBuilder.DropIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits"); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits", columns: new[] { "TenantId", "Code" }); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200414102908_AddAcHistory.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200414102908_AddAcHistory")] partial class AddAcHistory { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ParameterName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParameterName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.ToTable("AbpDynamicParameterValues"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("EntityFullName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.HasIndex("EntityFullName", "DynamicParameterId", "TenantId") .IsUnique(); b.ToTable("AbpEntityDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("EntityDynamicParameterId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EntityDynamicParameterId"); b.ToTable("AbpEntityDynamicParameterValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code") .IsUnique(); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.AcHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("AcHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.AcWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AcHistoryId") .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("HasSolvedList") .HasColumnType("tinyint(1)"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("AcHistoryId"); b.ToTable("AcWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany("DynamicParameterValues") .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany() .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.EntityDynamicParameter", "EntityDynamicParameter") .WithMany() .HasForeignKey("EntityDynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.AcHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.AcWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.AcHistory", "AcHistory") .WithMany("AcWorkerHistories") .HasForeignKey("AcHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200414102908_AddAcHistory.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class AddAcHistory : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AlterColumn( name: "UsernamesInCrawlers", table: "DefaultQueries", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true); migrationBuilder.CreateTable( name: "AcHistories", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), UserId = table.Column(nullable: false), MainUsername = table.Column(nullable: false), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AcHistories", x => x.Id); table.ForeignKey( name: "FK_AcHistories_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AcWorkerHistories", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), AcHistoryId = table.Column(nullable: false), CrawlerName = table.Column(nullable: false), Username = table.Column(nullable: false), ErrorMessage = table.Column(nullable: true), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), HasSolvedList = table.Column(nullable: false), SolvedList = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_AcWorkerHistories", x => x.Id); table.ForeignKey( name: "FK_AcWorkerHistories_AcHistories_AcHistoryId", column: x => x.AcHistoryId, principalTable: "AcHistories", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AcHistories_UserId", table: "AcHistories", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AcWorkerHistories_AcHistoryId", table: "AcWorkerHistories", column: "AcHistoryId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AcWorkerHistories"); migrationBuilder.DropTable( name: "AcHistories"); migrationBuilder.AlterColumn( name: "UsernamesInCrawlers", table: "DefaultQueries", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string)); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200419031052_UseQueryHistory.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200419031052_UseQueryHistory")] partial class UseQueryHistory { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ParameterName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParameterName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.ToTable("AbpDynamicParameterValues"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("EntityFullName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.HasIndex("EntityFullName", "DynamicParameterId", "TenantId") .IsUnique(); b.ToTable("AbpEntityDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("EntityDynamicParameterId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EntityDynamicParameterId"); b.ToTable("AbpEntityDynamicParameterValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("HasSolvedList") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany("DynamicParameterValues") .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany() .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.EntityDynamicParameter", "EntityDynamicParameter") .WithMany() .HasForeignKey("EntityDynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200419031052_UseQueryHistory.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class UseQueryHistory : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AcWorkerHistories"); migrationBuilder.DropTable( name: "AcHistories"); migrationBuilder.DropIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits"); migrationBuilder.CreateTable( name: "QueryHistories", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(nullable: false), UserId = table.Column(nullable: false), MainUsername = table.Column(nullable: false), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_QueryHistories", x => x.Id); table.ForeignKey( name: "FK_QueryHistories_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "QueryWorkerHistories", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), QueryHistoryId = table.Column(nullable: false), CrawlerName = table.Column(nullable: false), Username = table.Column(nullable: false), ErrorMessage = table.Column(nullable: true), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), HasSolvedList = table.Column(nullable: false), SolvedList = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_QueryWorkerHistories", x => x.Id); table.ForeignKey( name: "FK_QueryWorkerHistories_QueryHistories_QueryHistoryId", column: x => x.QueryHistoryId, principalTable: "QueryHistories", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits", columns: new[] { "TenantId", "Code" }); migrationBuilder.CreateIndex( name: "IX_QueryHistories_UserId", table: "QueryHistories", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_QueryWorkerHistories_QueryHistoryId", table: "QueryWorkerHistories", column: "QueryHistoryId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "QueryWorkerHistories"); migrationBuilder.DropTable( name: "QueryHistories"); migrationBuilder.DropIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits"); migrationBuilder.CreateTable( name: "AcHistories", columns: table => new { Id = table.Column(type: "bigint", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), CreationTime = table.Column(type: "datetime(6)", nullable: false), MainUsername = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), Solved = table.Column(type: "int", nullable: false), Submission = table.Column(type: "int", nullable: false), UserId = table.Column(type: "bigint", nullable: false), }, constraints: table => { table.PrimaryKey("PK_AcHistories", x => x.Id); table.ForeignKey( name: "FK_AcHistories_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AcWorkerHistories", columns: table => new { Id = table.Column(type: "bigint", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), AcHistoryId = table.Column(type: "bigint", nullable: false), CrawlerName = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), ErrorMessage = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), HasSolvedList = table.Column(type: "tinyint(1)", nullable: false), Solved = table.Column(type: "int", nullable: false), SolvedList = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), Submission = table.Column(type: "int", nullable: false), Username = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), }, constraints: table => { table.PrimaryKey("PK_AcWorkerHistories", x => x.Id); table.ForeignKey( name: "FK_AcWorkerHistories_AcHistories_AcHistoryId", column: x => x.AcHistoryId, principalTable: "AcHistories", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnits_TenantId_Code", table: "AbpOrganizationUnits", columns: new[] { "TenantId", "Code" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AcHistories_UserId", table: "AcHistories", column: "UserId"); migrationBuilder.CreateIndex( name: "IX_AcWorkerHistories_AcHistoryId", table: "AcWorkerHistories", column: "AcHistoryId"); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200522145416_AddSettings.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200522145416_AddSettings")] partial class AddSettings { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ParameterName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParameterName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.ToTable("AbpDynamicParameterValues"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("EntityFullName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.HasIndex("EntityFullName", "DynamicParameterId", "TenantId") .IsUnique(); b.ToTable("AbpEntityDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("EntityDynamicParameterId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EntityDynamicParameterId"); b.ToTable("AbpEntityDynamicParameterValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("HasSolvedList") .HasColumnType("tinyint(1)"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany("DynamicParameterValues") .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany() .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.EntityDynamicParameter", "EntityDynamicParameter") .WithMany() .HasForeignKey("EntityDynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200522145416_AddSettings.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class AddSettings : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( name: "IsVirtualJudge", table: "QueryWorkerHistories", nullable: false, defaultValue: false); migrationBuilder.AddColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories", nullable: false); migrationBuilder.CreateTable( name: "UserSettingAttributes", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), UserId = table.Column(nullable: false), LastTimeZoneChangedTime = table.Column(nullable: true), CreationTime = table.Column(nullable: false), CreatorUserId = table.Column(nullable: true), LastModificationTime = table.Column(nullable: true), LastModifierUserId = table.Column(nullable: true), }, constraints: table => { table.PrimaryKey("PK_UserSettingAttributes", x => x.Id); table.ForeignKey( name: "FK_UserSettingAttributes_AbpUsers_CreatorUserId", column: x => x.CreatorUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_UserSettingAttributes_AbpUsers_LastModifierUserId", column: x => x.LastModifierUserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_UserSettingAttributes_AbpUsers_UserId", column: x => x.UserId, principalTable: "AbpUsers", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_UserSettingAttributes_CreatorUserId", table: "UserSettingAttributes", column: "CreatorUserId"); migrationBuilder.CreateIndex( name: "IX_UserSettingAttributes_LastModifierUserId", table: "UserSettingAttributes", column: "LastModifierUserId"); migrationBuilder.CreateIndex( name: "IX_UserSettingAttributes_UserId", table: "UserSettingAttributes", column: "UserId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "UserSettingAttributes"); migrationBuilder.DropColumn( name: "IsVirtualJudge", table: "QueryWorkerHistories"); migrationBuilder.DropColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories"); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200604111842_AddSummary.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20200604111842_AddSummary")] partial class AddSummary { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "3.1.4") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CustomData") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("Exception") .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") .HasMaxLength(2000); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Parameters") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("ProviderKey") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Name") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("JobType") .IsRequired() .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ParameterName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParameterName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.ToTable("AbpDynamicParameterValues"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicParameterId") .HasColumnType("int"); b.Property("EntityFullName") .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicParameterId"); b.HasIndex("EntityFullName", "DynamicParameterId", "TenantId") .IsUnique(); b.ToTable("AbpEntityDynamicParameters"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("EntityDynamicParameterId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EntityDynamicParameterId"); b.ToTable("AbpEntityDynamicParameterValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(48) CHARACTER SET utf8mb4") .HasMaxLength(48); b.Property("EntityTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("ClientIpAddress") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ClientName") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("OriginalValue") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("PropertyName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("PropertyTypeFullName") .HasColumnType("varchar(192) CHARACTER SET utf8mb4") .HasMaxLength(192); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("Icon") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("LanguageName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(67108864); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("ExcludedUserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.Property("UserIds") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(131072); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(1048576); b.Property("DataTypeName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityId") .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("EntityTypeAssemblyQualifiedName") .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); b.Property("EntityTypeName") .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); b.Property("NotificationName") .IsRequired() .HasColumnType("varchar(96) CHARACTER SET utf8mb4") .HasMaxLength(96); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasColumnType("varchar(95) CHARACTER SET utf8mb4") .HasMaxLength(95); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(5000); b.Property("DisplayName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("NormalizedName") .IsRequired() .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("EmailConfirmationCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("NormalizedEmailAddress") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("NormalizedUserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("Password") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("PasswordResetCode") .HasColumnType("varchar(328) CHARACTER SET utf8mb4") .HasMaxLength(328); b.Property("PhoneNumber") .HasColumnType("varchar(32) CHARACTER SET utf8mb4") .HasMaxLength(32); b.Property("SecurityStamp") .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("Surname") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("FromCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") .HasMaxLength(1024); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); b.Property("TenancyName") .IsRequired() .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityParameters.DynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany("DynamicParameterValues") .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameter", b => { b.HasOne("Abp.DynamicEntityParameters.DynamicParameter", "DynamicParameter") .WithMany() .HasForeignKey("DynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityParameters.EntityDynamicParameterValue", b => { b.HasOne("Abp.DynamicEntityParameters.EntityDynamicParameter", "EntityDynamicParameter") .WithMany() .HasForeignKey("EntityDynamicParameterId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20200604111842_AddSummary.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class AddSummary : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.DropColumn( name: "HasSolvedList", table: "QueryWorkerHistories"); migrationBuilder.DropColumn( name: "Solved", table: "QueryHistories"); migrationBuilder.DropColumn( name: "Submission", table: "QueryHistories"); migrationBuilder.AlterColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4"); migrationBuilder.AlterColumn( name: "SolvedList", table: "QueryWorkerHistories", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4"); migrationBuilder.AddColumn( name: "IsReliableSource", table: "QueryHistories", nullable: false, defaultValue: false); migrationBuilder.CreateTable( name: "QuerySummaries", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), QueryHistoryId = table.Column(nullable: false), GenerateTime = table.Column(nullable: false), SummaryWarnings = table.Column(nullable: false), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_QuerySummaries", x => x.Id); table.ForeignKey( name: "FK_QuerySummaries_QueryHistories_QueryHistoryId", column: x => x.QueryHistoryId, principalTable: "QueryHistories", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "QueryCrawlerSummaries", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), QuerySummaryId = table.Column(nullable: false), CrawlerName = table.Column(nullable: false), Submission = table.Column(nullable: false), Solved = table.Column(nullable: false), IsVirtualJudge = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_QueryCrawlerSummaries", x => x.Id); table.ForeignKey( name: "FK_QueryCrawlerSummaries_QuerySummaries_QuerySummaryId", column: x => x.QuerySummaryId, principalTable: "QuerySummaries", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "UsernameInCrawler", columns: table => new { Id = table.Column(nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), QueryCrawlerSummaryId = table.Column(nullable: false), FromCrawlerName = table.Column(nullable: true), Username = table.Column(nullable: false), }, constraints: table => { table.PrimaryKey("PK_UsernameInCrawler", x => x.Id); table.ForeignKey( name: "FK_UsernameInCrawler_QueryCrawlerSummaries_QueryCrawlerSummaryId", column: x => x.QueryCrawlerSummaryId, principalTable: "QueryCrawlerSummaries", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_QueryCrawlerSummaries_QuerySummaryId", table: "QueryCrawlerSummaries", column: "QuerySummaryId"); migrationBuilder.CreateIndex( name: "IX_QuerySummaries_QueryHistoryId", table: "QuerySummaries", column: "QueryHistoryId", unique: true); migrationBuilder.CreateIndex( name: "IX_UsernameInCrawler_QueryCrawlerSummaryId", table: "UsernameInCrawler", column: "QueryCrawlerSummaryId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "UsernameInCrawler"); migrationBuilder.DropTable( name: "QueryCrawlerSummaries"); migrationBuilder.DropTable( name: "QuerySummaries"); migrationBuilder.DropColumn( name: "IsReliableSource", table: "QueryHistories"); migrationBuilder.AlterColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldNullable: true); migrationBuilder.AlterColumn( name: "SolvedList", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldNullable: true); migrationBuilder.AddColumn( name: "HasSolvedList", table: "QueryWorkerHistories", type: "tinyint(1)", nullable: false, defaultValue: false); migrationBuilder.AddColumn( name: "Solved", table: "QueryHistories", type: "int", nullable: false, defaultValue: 0); migrationBuilder.AddColumn( name: "Submission", table: "QueryHistories", type: "int", nullable: false, defaultValue: 0); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210429095008_UpgradeAbp.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20210429095008_UpgradeAbp")] partial class UpgradeAbp { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Relational:MaxIdentifierLength", 64) .HasAnnotation("ProductVersion", "5.0.5"); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CustomData") .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.Property("Exception") .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.Property("ExceptionMessage") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("Parameters") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("ProviderKey") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("Name") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("JobType") .IsRequired() .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("EntityFullName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.HasIndex("EntityFullName", "DynamicPropertyId", "TenantId") .IsUnique(); b.ToTable("AbpDynamicEntityProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicEntityPropertyId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicEntityPropertyId"); b.ToTable("AbpDynamicEntityPropertyValues"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DisplayName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("PropertyName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("PropertyName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.ToTable("AbpDynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(48) .HasColumnType("varchar(48) CHARACTER SET utf8mb4"); b.Property("EntityTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("NewValueHash") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("OriginalValue") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("OriginalValueHash") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("PropertyName") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("PropertyTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("Icon") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("LanguageName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(67108864) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("ExcludedUserIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("NotificationName") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasMaxLength(95) .HasColumnType("varchar(95) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("Description") .HasMaxLength(5000) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("NormalizedName") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("EmailConfirmationCode") .HasMaxLength(328) .HasColumnType("varchar(328) CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("NormalizedEmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("NormalizedUserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("Password") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("PasswordResetCode") .HasMaxLength(328) .HasColumnType("varchar(328) CHARACTER SET utf8mb4"); b.Property("PhoneNumber") .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("SecurityStamp") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("Surname") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("FromCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenancyName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany() .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicEntityProperty", "DynamicEntityProperty") .WithMany() .HasForeignKey("DynamicEntityPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicEntityProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany("DynamicPropertyValues") .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); b.Navigation("Parent"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("WebhookEvent"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QuerySummary"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryCrawlerSummary"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("Edition"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Edition"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Navigation("DynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Navigation("PropertyChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Navigation("EntityChanges"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Navigation("Children"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Navigation("Claims"); b.Navigation("Permissions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Navigation("Claims"); b.Navigation("Logins"); b.Navigation("Permissions"); b.Navigation("Roles"); b.Navigation("Settings"); b.Navigation("Tokens"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Navigation("Usernames"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Navigation("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Navigation("QueryCrawlerSummaries"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210429095008_UpgradeAbp.cs ================================================ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class UpgradeAbp : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AbpDynamicParameterValues"); migrationBuilder.DropTable( name: "AbpEntityDynamicParameterValues"); migrationBuilder.DropTable( name: "AbpEntityDynamicParameters"); migrationBuilder.DropTable( name: "AbpDynamicParameters"); migrationBuilder.AddColumn( name: "NewValueHash", table: "AbpEntityPropertyChanges", type: "longtext CHARACTER SET utf8mb4", nullable: true); migrationBuilder.AddColumn( name: "OriginalValueHash", table: "AbpEntityPropertyChanges", type: "longtext CHARACTER SET utf8mb4", nullable: true); migrationBuilder.AddColumn( name: "ExceptionMessage", table: "AbpAuditLogs", type: "varchar(1024) CHARACTER SET utf8mb4", maxLength: 1024, nullable: true); migrationBuilder.CreateTable( name: "AbpDynamicProperties", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), PropertyName = table.Column(type: "varchar(256) CHARACTER SET utf8mb4", maxLength: 256, nullable: true), DisplayName = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), InputType = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), Permission = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), TenantId = table.Column(type: "int", nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicProperties", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpDynamicEntityProperties", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), EntityFullName = table.Column(type: "varchar(256) CHARACTER SET utf8mb4", maxLength: 256, nullable: true), DynamicPropertyId = table.Column(type: "int", nullable: false), TenantId = table.Column(type: "int", nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicEntityProperties", x => x.Id); table.ForeignKey( name: "FK_AbpDynamicEntityProperties_AbpDynamicProperties_DynamicPrope~", column: x => x.DynamicPropertyId, principalTable: "AbpDynamicProperties", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpDynamicPropertyValues", columns: table => new { Id = table.Column(type: "bigint", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), Value = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), TenantId = table.Column(type: "int", nullable: true), DynamicPropertyId = table.Column(type: "int", nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicPropertyValues", x => x.Id); table.ForeignKey( name: "FK_AbpDynamicPropertyValues_AbpDynamicProperties_DynamicPropert~", column: x => x.DynamicPropertyId, principalTable: "AbpDynamicProperties", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpDynamicEntityPropertyValues", columns: table => new { Id = table.Column(type: "bigint", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), Value = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), EntityId = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), DynamicEntityPropertyId = table.Column(type: "int", nullable: false), TenantId = table.Column(type: "int", nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicEntityPropertyValues", x => x.Id); table.ForeignKey( name: "FK_AbpDynamicEntityPropertyValues_AbpDynamicEntityProperties_Dy~", column: x => x.DynamicEntityPropertyId, principalTable: "AbpDynamicEntityProperties", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpDynamicEntityProperties_DynamicPropertyId", table: "AbpDynamicEntityProperties", column: "DynamicPropertyId"); migrationBuilder.CreateIndex( name: "IX_AbpDynamicEntityProperties_EntityFullName_DynamicPropertyId_~", table: "AbpDynamicEntityProperties", columns: new[] { "EntityFullName", "DynamicPropertyId", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpDynamicEntityPropertyValues_DynamicEntityPropertyId", table: "AbpDynamicEntityPropertyValues", column: "DynamicEntityPropertyId"); migrationBuilder.CreateIndex( name: "IX_AbpDynamicProperties_PropertyName_TenantId", table: "AbpDynamicProperties", columns: new[] { "PropertyName", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpDynamicPropertyValues_DynamicPropertyId", table: "AbpDynamicPropertyValues", column: "DynamicPropertyId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "AbpDynamicEntityPropertyValues"); migrationBuilder.DropTable( name: "AbpDynamicPropertyValues"); migrationBuilder.DropTable( name: "AbpDynamicEntityProperties"); migrationBuilder.DropTable( name: "AbpDynamicProperties"); migrationBuilder.DropColumn( name: "NewValueHash", table: "AbpEntityPropertyChanges"); migrationBuilder.DropColumn( name: "OriginalValueHash", table: "AbpEntityPropertyChanges"); migrationBuilder.DropColumn( name: "ExceptionMessage", table: "AbpAuditLogs"); migrationBuilder.CreateTable( name: "AbpDynamicParameters", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), InputType = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), ParameterName = table.Column(type: "varchar(255) CHARACTER SET utf8mb4", nullable: true), Permission = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), TenantId = table.Column(type: "int", nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicParameters", x => x.Id); }); migrationBuilder.CreateTable( name: "AbpDynamicParameterValues", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), DynamicParameterId = table.Column(type: "int", nullable: false), TenantId = table.Column(type: "int", nullable: true), Value = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpDynamicParameterValues", x => x.Id); table.ForeignKey( name: "FK_AbpDynamicParameterValues_AbpDynamicParameters_DynamicParame~", column: x => x.DynamicParameterId, principalTable: "AbpDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityDynamicParameters", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), DynamicParameterId = table.Column(type: "int", nullable: false), EntityFullName = table.Column(type: "varchar(255) CHARACTER SET utf8mb4", nullable: true), TenantId = table.Column(type: "int", nullable: true), }, constraints: table => { table.PrimaryKey("PK_AbpEntityDynamicParameters", x => x.Id); table.ForeignKey( name: "FK_AbpEntityDynamicParameters_AbpDynamicParameters_DynamicParam~", column: x => x.DynamicParameterId, principalTable: "AbpDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "AbpEntityDynamicParameterValues", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), EntityDynamicParameterId = table.Column(type: "int", nullable: false), EntityId = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: true), TenantId = table.Column(type: "int", nullable: true), Value = table.Column(type: "longtext CHARACTER SET utf8mb4", nullable: false), }, constraints: table => { table.PrimaryKey("PK_AbpEntityDynamicParameterValues", x => x.Id); table.ForeignKey( name: "FK_AbpEntityDynamicParameterValues_AbpEntityDynamicParameters_E~", column: x => x.EntityDynamicParameterId, principalTable: "AbpEntityDynamicParameters", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_AbpDynamicParameters_ParameterName_TenantId", table: "AbpDynamicParameters", columns: new[] { "ParameterName", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpDynamicParameterValues_DynamicParameterId", table: "AbpDynamicParameterValues", column: "DynamicParameterId"); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameters_DynamicParameterId", table: "AbpEntityDynamicParameters", column: "DynamicParameterId"); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameters_EntityFullName_DynamicParameterId~", table: "AbpEntityDynamicParameters", columns: new[] { "EntityFullName", "DynamicParameterId", "TenantId" }, unique: true); migrationBuilder.CreateIndex( name: "IX_AbpEntityDynamicParameterValues_EntityDynamicParameterId", table: "AbpEntityDynamicParameterValues", column: "EntityDynamicParameterId"); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210627092246_RemoveRoleDescription.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20210627092246_RemoveRoleDescription")] partial class RemoveRoleDescription { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Relational:MaxIdentifierLength", 64) .HasAnnotation("ProductVersion", "5.0.7"); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CustomData") .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.Property("Exception") .HasMaxLength(2000) .HasColumnType("varchar(2000) CHARACTER SET utf8mb4"); b.Property("ExceptionMessage") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("Parameters") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("ReturnValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ServiceName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("ClaimValue") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("ProviderKey") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("Name") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("JobType") .IsRequired() .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("EntityFullName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.HasIndex("EntityFullName", "DynamicPropertyId", "TenantId") .IsUnique(); b.ToTable("AbpDynamicEntityProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicEntityPropertyId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicEntityPropertyId"); b.ToTable("AbpDynamicEntityPropertyValues"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DisplayName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("InputType") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Permission") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("PropertyName") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("PropertyName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.ToTable("AbpDynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(48) .HasColumnType("varchar(48) CHARACTER SET utf8mb4"); b.Property("EntityTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("NewValueHash") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("OriginalValue") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("OriginalValueHash") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("PropertyName") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("PropertyTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("Icon") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("LanguageName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(67108864) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("ExcludedUserIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserIds") .HasMaxLength(131072) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("NotificationName") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512) CHARACTER SET utf8mb4"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250) CHARACTER SET utf8mb4"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96) CHARACTER SET utf8mb4"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasMaxLength(95) .HasColumnType("varchar(95) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Webhooks") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("NormalizedName") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("EmailConfirmationCode") .HasMaxLength(328) .HasColumnType("varchar(328) CHARACTER SET utf8mb4"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("NormalizedEmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("NormalizedUserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.Property("Password") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("PasswordResetCode") .HasMaxLength(328) .HasColumnType("varchar(328) CHARACTER SET utf8mb4"); b.Property("PhoneNumber") .HasMaxLength(32) .HasColumnType("varchar(32) CHARACTER SET utf8mb4"); b.Property("SecurityStamp") .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("Surname") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("ErrorMessage") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("FromCrawlerName") .HasColumnType("longtext CHARACTER SET utf8mb4"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasMaxLength(1024) .HasColumnType("varchar(1024) CHARACTER SET utf8mb4"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128) CHARACTER SET utf8mb4"); b.Property("TenancyName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64) CHARACTER SET utf8mb4"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany() .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicEntityProperty", "DynamicEntityProperty") .WithMany() .HasForeignKey("DynamicEntityPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicEntityProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany("DynamicPropertyValues") .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); b.Navigation("Parent"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("WebhookEvent"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QuerySummary"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryCrawlerSummary"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("Edition"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Edition"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Navigation("DynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Navigation("PropertyChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Navigation("EntityChanges"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Navigation("Children"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Navigation("Claims"); b.Navigation("Permissions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Navigation("Claims"); b.Navigation("Logins"); b.Navigation("Permissions"); b.Navigation("Roles"); b.Navigation("Settings"); b.Navigation("Tokens"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Navigation("Usernames"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Navigation("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Navigation("QueryCrawlerSummaries"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210627092246_RemoveRoleDescription.cs ================================================ using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class RemoveRoleDescription : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.DropColumn( name: "Description", table: "AbpRoles"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( name: "Description", table: "AbpRoles", type: "longtext CHARACTER SET utf8mb4", maxLength: 5000, nullable: true); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210627092411_UpgradeDriver.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20210627092411_UpgradeDriver")] partial class UpgradeDriver { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Relational:MaxIdentifierLength", 64) .HasAnnotation("ProductVersion", "5.0.7"); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator("Discriminator").HasValue("FeatureSetting"); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CustomData") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("Exception") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("ExceptionMessage") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Parameters") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ReturnValue") .HasColumnType("longtext"); b.Property("ServiceName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasColumnType("longtext"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator("Discriminator").HasValue("PermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("LoginProvider") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("ProviderKey") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Name") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("JobType") .IsRequired() .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("EntityFullName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.HasIndex("EntityFullName", "DynamicPropertyId", "TenantId") .IsUnique(); b.ToTable("AbpDynamicEntityProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicEntityPropertyId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicEntityPropertyId"); b.ToTable("AbpDynamicEntityPropertyValues"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("DisplayName") .HasColumnType("longtext"); b.Property("InputType") .HasColumnType("longtext"); b.Property("Permission") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("PropertyName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.ToTable("AbpDynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(48) .HasColumnType("varchar(48)"); b.Property("EntityTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("NewValueHash") .HasColumnType("longtext"); b.Property("OriginalValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("OriginalValueHash") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("PropertyTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("Icon") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("LanguageName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(67108864) .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("ExcludedUserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("UserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("Code") .IsRequired() .HasMaxLength(95) .HasColumnType("varchar(95)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext"); b.Property("Webhooks") .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("NormalizedName") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("EmailConfirmationCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("NormalizedEmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("NormalizedUserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Password") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("PasswordResetCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("PhoneNumber") .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("SecurityStamp") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Surname") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("ErrorMessage") .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("FromCrawlerName") .HasColumnType("longtext"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); b.Property("ConnectionString") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenancyName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany() .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicEntityProperty", "DynamicEntityProperty") .WithMany() .HasForeignKey("DynamicEntityPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicEntityProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany("DynamicPropertyValues") .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); b.Navigation("Parent"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("WebhookEvent"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QuerySummary"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryCrawlerSummary"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("Edition"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Edition"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Navigation("DynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Navigation("PropertyChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Navigation("EntityChanges"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Navigation("Children"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Navigation("Claims"); b.Navigation("Permissions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Navigation("Claims"); b.Navigation("Logins"); b.Navigation("Permissions"); b.Navigation("Roles"); b.Navigation("Settings"); b.Navigation("Tokens"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Navigation("Usernames"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Navigation("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Navigation("QueryCrawlerSummaries"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20210627092411_UpgradeDriver.cs ================================================ using Microsoft.EntityFrameworkCore.Migrations; namespace AcmStatisticsBackend.Migrations { public partial class UpgradeDriver : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AlterColumn( name: "Username", table: "UsernameInCrawler", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "FromCrawlerName", table: "UsernameInCrawler", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Username", table: "QueryWorkerHistories", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SolvedList", table: "QueryWorkerHistories", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ErrorMessage", table: "QueryWorkerHistories", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "CrawlerName", table: "QueryWorkerHistories", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SummaryWarnings", table: "QuerySummaries", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "MainUsername", table: "QueryHistories", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "CrawlerName", table: "QueryCrawlerSummaries", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "UsernamesInCrawlers", table: "DefaultQueries", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "MainUsername", table: "DefaultQueries", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Webhooks", table: "AbpWebhookSubscriptions", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "WebhookUri", table: "AbpWebhookSubscriptions", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Secret", table: "AbpWebhookSubscriptions", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Headers", table: "AbpWebhookSubscriptions", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Response", table: "AbpWebhookSendAttempts", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "WebhookName", table: "AbpWebhookEvents", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpWebhookEvents", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ClaimValue", table: "AbpUserClaims", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpTenantNotifications", type: "longtext", maxLength: 1048576, nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 1048576, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpSettings", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ClaimValue", table: "AbpRoleClaims", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpPermissions", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "UserIds", table: "AbpNotifications", type: "longtext", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "TenantIds", table: "AbpNotifications", type: "longtext", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ExcludedUserIds", table: "AbpNotifications", type: "longtext", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpNotifications", type: "longtext", maxLength: 1048576, nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 1048576, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpLanguageTexts", type: "longtext", maxLength: 67108864, nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 67108864) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpFeatures", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "OriginalValueHash", table: "AbpEntityPropertyChanges", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "NewValueHash", table: "AbpEntityPropertyChanges", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ExtensionData", table: "AbpEntityChangeSets", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpDynamicPropertyValues", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Permission", table: "AbpDynamicProperties", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "InputType", table: "AbpDynamicProperties", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "DisplayName", table: "AbpDynamicProperties", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpDynamicEntityPropertyValues", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "EntityId", table: "AbpDynamicEntityPropertyValues", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "JobArgs", table: "AbpBackgroundJobs", type: "longtext", maxLength: 1048576, nullable: false, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldMaxLength: 1048576) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ReturnValue", table: "AbpAuditLogs", type: "longtext", nullable: true, oldClrType: typeof(string), oldType: "longtext CHARACTER SET utf8mb4", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.AlterColumn( name: "Username", table: "UsernameInCrawler", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "FromCrawlerName", table: "UsernameInCrawler", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Username", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SubmissionsByCrawlerName", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SolvedList", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ErrorMessage", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "CrawlerName", table: "QueryWorkerHistories", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "SummaryWarnings", table: "QuerySummaries", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "MainUsername", table: "QueryHistories", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "CrawlerName", table: "QueryCrawlerSummaries", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "UsernamesInCrawlers", table: "DefaultQueries", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "MainUsername", table: "DefaultQueries", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Webhooks", table: "AbpWebhookSubscriptions", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "WebhookUri", table: "AbpWebhookSubscriptions", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Secret", table: "AbpWebhookSubscriptions", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Headers", table: "AbpWebhookSubscriptions", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Response", table: "AbpWebhookSendAttempts", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "WebhookName", table: "AbpWebhookEvents", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpWebhookEvents", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ClaimValue", table: "AbpUserClaims", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpTenantNotifications", type: "longtext CHARACTER SET utf8mb4", maxLength: 1048576, nullable: true, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 1048576, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpSettings", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ClaimValue", table: "AbpRoleClaims", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpPermissions", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "UserIds", table: "AbpNotifications", type: "longtext CHARACTER SET utf8mb4", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "TenantIds", table: "AbpNotifications", type: "longtext CHARACTER SET utf8mb4", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ExcludedUserIds", table: "AbpNotifications", type: "longtext CHARACTER SET utf8mb4", maxLength: 131072, nullable: true, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 131072, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Data", table: "AbpNotifications", type: "longtext CHARACTER SET utf8mb4", maxLength: 1048576, nullable: true, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 1048576, oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpLanguageTexts", type: "longtext CHARACTER SET utf8mb4", maxLength: 67108864, nullable: false, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 67108864) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpFeatures", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "OriginalValueHash", table: "AbpEntityPropertyChanges", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "NewValueHash", table: "AbpEntityPropertyChanges", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ExtensionData", table: "AbpEntityChangeSets", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpDynamicPropertyValues", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Permission", table: "AbpDynamicProperties", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "InputType", table: "AbpDynamicProperties", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "DisplayName", table: "AbpDynamicProperties", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Value", table: "AbpDynamicEntityPropertyValues", type: "longtext CHARACTER SET utf8mb4", nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "EntityId", table: "AbpDynamicEntityPropertyValues", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "JobArgs", table: "AbpBackgroundJobs", type: "longtext CHARACTER SET utf8mb4", maxLength: 1048576, nullable: false, oldClrType: typeof(string), oldType: "longtext", oldMaxLength: 1048576) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "ReturnValue", table: "AbpAuditLogs", type: "longtext CHARACTER SET utf8mb4", nullable: true, oldClrType: typeof(string), oldType: "longtext", oldNullable: true) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20250813025256_UpgradeAbp840.Designer.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] [Migration("20250813025256_UpgradeAbp840")] partial class UpgradeAbp840 { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.19") .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasMaxLength(21) .HasColumnType("varchar(21)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("FeatureSetting"); b.UseTphMappingStrategy(); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CustomData") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("Exception") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("ExceptionMessage") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Parameters") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ReturnValue") .HasColumnType("longtext"); b.Property("ServiceName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasMaxLength(21) .HasColumnType("varchar(21)"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("PermissionSetting"); b.UseTphMappingStrategy(); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("LoginProvider") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("ProviderKey") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("ProviderKey", "TenantId") .IsUnique(); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Name") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("JobType") .IsRequired() .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("EntityFullName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.HasIndex("EntityFullName", "DynamicPropertyId", "TenantId") .IsUnique(); b.ToTable("AbpDynamicEntityProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicEntityPropertyId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicEntityPropertyId"); b.ToTable("AbpDynamicEntityPropertyValues"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DisplayName") .HasColumnType("longtext"); b.Property("InputType") .HasColumnType("longtext"); b.Property("Permission") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("PropertyName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.ToTable("AbpDynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(48) .HasColumnType("varchar(48)"); b.Property("EntityTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("NewValueHash") .HasColumnType("longtext"); b.Property("OriginalValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("OriginalValueHash") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("PropertyTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("Icon") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("LanguageName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(67108864) .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("ExcludedUserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("UserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("Code") .IsRequired() .HasMaxLength(95) .HasColumnType("varchar(95)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext"); b.Property("Webhooks") .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("NormalizedName") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("EmailConfirmationCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("NormalizedEmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("NormalizedUserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Password") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("PasswordResetCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("PhoneNumber") .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("SecurityStamp") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Surname") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("ErrorMessage") .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("FromCrawlerName") .HasColumnType("longtext"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ConnectionString") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenancyName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany() .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicEntityProperty", "DynamicEntityProperty") .WithMany() .HasForeignKey("DynamicEntityPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicEntityProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany("DynamicPropertyValues") .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); b.Navigation("Parent"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("WebhookEvent"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QuerySummary"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryCrawlerSummary"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("Edition"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Edition"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Navigation("DynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Navigation("PropertyChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Navigation("EntityChanges"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Navigation("Children"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Navigation("Claims"); b.Navigation("Permissions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Navigation("Claims"); b.Navigation("Logins"); b.Navigation("Permissions"); b.Navigation("Roles"); b.Navigation("Settings"); b.Navigation("Tokens"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Navigation("Usernames"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Navigation("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Navigation("QueryCrawlerSummaries"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/20250813025256_UpgradeAbp840.cs ================================================ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable namespace AcmStatisticsBackend.Migrations { /// public partial class UpgradeAbp840 : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AlterColumn( name: "Id", table: "UserSettingAttributes", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "UsernameInCrawler", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryWorkerHistories", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QuerySummaries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryHistories", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryCrawlerSummaries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "DefaultQueries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserTokens", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUsers", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserRoles", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserOrganizationUnits", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AddColumn( name: "TargetNotifiers", table: "AbpUserNotifications", type: "varchar(1024)", maxLength: 1024, nullable: true) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserLogins", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserLoginAttempts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserClaims", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserAccounts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpTenants", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpSettings", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpRoles", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpRoleClaims", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpPermissions", type: "varchar(21)", maxLength: 21, nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpPermissions", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpOrganizationUnits", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpOrganizationUnitRoles", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AddColumn( name: "TargetNotifiers", table: "AbpNotificationSubscriptions", type: "varchar(1024)", maxLength: 1024, nullable: true) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AddColumn( name: "TargetNotifiers", table: "AbpNotifications", type: "varchar(1024)", maxLength: 1024, nullable: true) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpLanguageTexts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpLanguages", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpFeatures", type: "varchar(21)", maxLength: 21, nullable: false, oldClrType: typeof(string), oldType: "longtext") .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpFeatures", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityPropertyChanges", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityChangeSets", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityChanges", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEditions", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicPropertyValues", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicProperties", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicEntityPropertyValues", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicEntityProperties", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpBackgroundJobs", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpAuditLogs", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.CreateIndex( name: "IX_AbpUserLogins_ProviderKey_TenantId", table: "AbpUserLogins", columns: new[] { "ProviderKey", "TenantId" }, unique: true); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropIndex( name: "IX_AbpUserLogins_ProviderKey_TenantId", table: "AbpUserLogins"); migrationBuilder.DropColumn( name: "TargetNotifiers", table: "AbpUserNotifications"); migrationBuilder.DropColumn( name: "TargetNotifiers", table: "AbpNotificationSubscriptions"); migrationBuilder.DropColumn( name: "TargetNotifiers", table: "AbpNotifications"); migrationBuilder.AlterColumn( name: "Id", table: "UserSettingAttributes", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "UsernameInCrawler", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryWorkerHistories", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QuerySummaries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryHistories", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "QueryCrawlerSummaries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "DefaultQueries", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserTokens", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUsers", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserRoles", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserOrganizationUnits", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserLogins", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserLoginAttempts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserClaims", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpUserAccounts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpTenants", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpSettings", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpRoles", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpRoleClaims", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpPermissions", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "varchar(21)", oldMaxLength: 21) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpPermissions", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpOrganizationUnits", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpOrganizationUnitRoles", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpLanguageTexts", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpLanguages", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Discriminator", table: "AbpFeatures", type: "longtext", nullable: false, oldClrType: typeof(string), oldType: "varchar(21)", oldMaxLength: 21) .Annotation("MySql:CharSet", "utf8mb4") .OldAnnotation("MySql:CharSet", "utf8mb4"); migrationBuilder.AlterColumn( name: "Id", table: "AbpFeatures", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityPropertyChanges", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityChangeSets", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEntityChanges", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpEditions", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicPropertyValues", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicProperties", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicEntityPropertyValues", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpDynamicEntityProperties", type: "int", nullable: false, oldClrType: typeof(int), oldType: "int") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpBackgroundJobs", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); migrationBuilder.AlterColumn( name: "Id", table: "AbpAuditLogs", type: "bigint", nullable: false, oldClrType: typeof(long), oldType: "bigint") .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.EntityFrameworkCore/Migrations/AcmStatisticsBackendDbContextModelSnapshot.cs ================================================ // using System; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable namespace AcmStatisticsBackend.Migrations { [DbContext(typeof(AcmStatisticsBackendDbContext))] partial class AcmStatisticsBackendDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.19") .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); modelBuilder.Entity("Abp.Application.Editions.Edition", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.HasKey("Id"); b.ToTable("AbpEditions"); }); modelBuilder.Entity("Abp.Application.Features.FeatureSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasMaxLength(21) .HasColumnType("varchar(21)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.HasKey("Id"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("FeatureSetting"); b.UseTphMappingStrategy(); }); modelBuilder.Entity("Abp.Auditing.AuditLog", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CustomData") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("Exception") .HasMaxLength(2000) .HasColumnType("varchar(2000)"); b.Property("ExceptionMessage") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ExecutionDuration") .HasColumnType("int"); b.Property("ExecutionTime") .HasColumnType("datetime(6)"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("MethodName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Parameters") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("ReturnValue") .HasColumnType("longtext"); b.Property("ServiceName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "ExecutionDuration"); b.HasIndex("TenantId", "ExecutionTime"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpAuditLogs"); }); modelBuilder.Entity("Abp.Authorization.PermissionSetting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Discriminator") .IsRequired() .HasMaxLength(21) .HasColumnType("varchar(21)"); b.Property("IsGranted") .HasColumnType("tinyint(1)"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("PermissionSetting"); b.UseTphMappingStrategy(); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("RoleId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpRoleClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserAccount", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserLinkId") .HasColumnType("bigint"); b.Property("UserName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("EmailAddress"); b.HasIndex("UserName"); b.HasIndex("TenantId", "EmailAddress"); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "UserName"); b.ToTable("AbpUserAccounts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ClaimType") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("ClaimValue") .HasColumnType("longtext"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "ClaimType"); b.ToTable("AbpUserClaims"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("LoginProvider") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("ProviderKey") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("ProviderKey", "TenantId") .IsUnique(); b.HasIndex("TenantId", "UserId"); b.HasIndex("TenantId", "LoginProvider", "ProviderKey"); b.ToTable("AbpUserLogins"); }); modelBuilder.Entity("Abp.Authorization.Users.UserLoginAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Result") .HasColumnType("tinyint unsigned"); b.Property("TenancyName") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UserNameOrEmailAddress") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("UserId", "TenantId"); b.HasIndex("TenancyName", "UserNameOrEmailAddress", "Result"); b.ToTable("AbpUserLoginAttempts"); }); modelBuilder.Entity("Abp.Authorization.Users.UserOrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserOrganizationUnits"); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "RoleId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserRoles"); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ExpireDate") .HasColumnType("datetime(6)"); b.Property("LoginProvider") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Name") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpUserTokens"); }); modelBuilder.Entity("Abp.BackgroundJobs.BackgroundJobInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsAbandoned") .HasColumnType("tinyint(1)"); b.Property("JobArgs") .IsRequired() .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("JobType") .IsRequired() .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("LastTryTime") .HasColumnType("datetime(6)"); b.Property("NextTryTime") .HasColumnType("datetime(6)"); b.Property("Priority") .HasColumnType("tinyint unsigned"); b.Property("TryCount") .HasColumnType("smallint"); b.HasKey("Id"); b.HasIndex("IsAbandoned", "NextTryTime"); b.ToTable("AbpBackgroundJobs"); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.Property("Value") .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("UserId"); b.HasIndex("TenantId", "Name", "UserId") .IsUnique(); b.ToTable("AbpSettings"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("EntityFullName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.HasIndex("EntityFullName", "DynamicPropertyId", "TenantId") .IsUnique(); b.ToTable("AbpDynamicEntityProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicEntityPropertyId") .HasColumnType("int"); b.Property("EntityId") .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicEntityPropertyId"); b.ToTable("AbpDynamicEntityPropertyValues"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DisplayName") .HasColumnType("longtext"); b.Property("InputType") .HasColumnType("longtext"); b.Property("Permission") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("PropertyName", "TenantId") .IsUnique(); b.ToTable("AbpDynamicProperties"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("DynamicPropertyId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("DynamicPropertyId"); b.ToTable("AbpDynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ChangeTime") .HasColumnType("datetime(6)"); b.Property("ChangeType") .HasColumnType("tinyint unsigned"); b.Property("EntityChangeSetId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(48) .HasColumnType("varchar(48)"); b.Property("EntityTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeSetId"); b.HasIndex("EntityTypeFullName", "EntityId"); b.ToTable("AbpEntityChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("BrowserInfo") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("ClientIpAddress") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ClientName") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("ExtensionData") .HasColumnType("longtext"); b.Property("ImpersonatorTenantId") .HasColumnType("int"); b.Property("ImpersonatorUserId") .HasColumnType("bigint"); b.Property("Reason") .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("TenantId", "CreationTime"); b.HasIndex("TenantId", "Reason"); b.HasIndex("TenantId", "UserId"); b.ToTable("AbpEntityChangeSets"); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("EntityChangeId") .HasColumnType("bigint"); b.Property("NewValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("NewValueHash") .HasColumnType("longtext"); b.Property("OriginalValue") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("OriginalValueHash") .HasColumnType("longtext"); b.Property("PropertyName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("PropertyTypeFullName") .HasMaxLength(192) .HasColumnType("varchar(192)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("EntityChangeId"); b.ToTable("AbpEntityPropertyChanges"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguage", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("Icon") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsDisabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpLanguages"); }); modelBuilder.Entity("Abp.Localization.ApplicationLanguageText", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Key") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("LanguageName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Source") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenantId") .HasColumnType("int"); b.Property("Value") .IsRequired() .HasMaxLength(67108864) .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("TenantId", "Source", "LanguageName", "Key"); b.ToTable("AbpLanguageTexts"); }); modelBuilder.Entity("Abp.Notifications.NotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("ExcludedUserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.Property("UserIds") .HasMaxLength(131072) .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpNotifications"); }); modelBuilder.Entity("Abp.Notifications.NotificationSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("NotificationName", "EntityTypeName", "EntityId", "UserId"); b.HasIndex("TenantId", "NotificationName", "EntityTypeName", "EntityId", "UserId"); b.ToTable("AbpNotificationSubscriptions"); }); modelBuilder.Entity("Abp.Notifications.TenantNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Data") .HasMaxLength(1048576) .HasColumnType("longtext"); b.Property("DataTypeName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityId") .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("EntityTypeAssemblyQualifiedName") .HasMaxLength(512) .HasColumnType("varchar(512)"); b.Property("EntityTypeName") .HasMaxLength(250) .HasColumnType("varchar(250)"); b.Property("NotificationName") .IsRequired() .HasMaxLength(96) .HasColumnType("varchar(96)"); b.Property("Severity") .HasColumnType("tinyint unsigned"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId"); b.ToTable("AbpTenantNotifications"); }); modelBuilder.Entity("Abp.Notifications.UserNotificationInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("State") .HasColumnType("int"); b.Property("TargetNotifiers") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("TenantId") .HasColumnType("int"); b.Property("TenantNotificationId") .HasColumnType("char(36)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId", "State", "CreationTime"); b.ToTable("AbpUserNotifications"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("Code") .IsRequired() .HasMaxLength(95) .HasColumnType("varchar(95)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("ParentId") .HasColumnType("bigint"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("ParentId"); b.HasIndex("TenantId", "Code"); b.ToTable("AbpOrganizationUnits"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnitRole", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("OrganizationUnitId") .HasColumnType("bigint"); b.Property("RoleId") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("TenantId", "OrganizationUnitId"); b.HasIndex("TenantId", "RoleId"); b.ToTable("AbpOrganizationUnitRoles"); }); modelBuilder.Entity("Abp.Webhooks.WebhookEvent", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("Data") .HasColumnType("longtext"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookName") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookEvents"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("Response") .HasColumnType("longtext"); b.Property("ResponseStatusCode") .HasColumnType("int"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookEventId") .HasColumnType("char(36)"); b.Property("WebhookSubscriptionId") .HasColumnType("char(36)"); b.HasKey("Id"); b.HasIndex("WebhookEventId"); b.ToTable("AbpWebhookSendAttempts"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSubscriptionInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("Headers") .HasColumnType("longtext"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("Secret") .IsRequired() .HasColumnType("longtext"); b.Property("TenantId") .HasColumnType("int"); b.Property("WebhookUri") .IsRequired() .HasColumnType("longtext"); b.Property("Webhooks") .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("AbpWebhookSubscriptions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("IsDefault") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsStatic") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("NormalizedName") .IsRequired() .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("TenantId") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedName"); b.ToTable("AbpRoles"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("AccessFailedCount") .HasColumnType("int"); b.Property("AuthenticationSource") .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("EmailConfirmationCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("IsEmailConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsLockoutEnabled") .HasColumnType("tinyint(1)"); b.Property("IsPhoneNumberConfirmed") .HasColumnType("tinyint(1)"); b.Property("IsTwoFactorEnabled") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LockoutEndDateUtc") .HasColumnType("datetime(6)"); b.Property("Name") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("NormalizedEmailAddress") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("NormalizedUserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.Property("Password") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("PasswordResetCode") .HasMaxLength(328) .HasColumnType("varchar(328)"); b.Property("PhoneNumber") .HasMaxLength(32) .HasColumnType("varchar(32)"); b.Property("SecurityStamp") .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("Surname") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.Property("TenantId") .HasColumnType("int"); b.Property("UserName") .IsRequired() .HasMaxLength(256) .HasColumnType("varchar(256)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenantId", "NormalizedEmailAddress"); b.HasIndex("TenantId", "NormalizedUserName"); b.ToTable("AbpUsers"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.Property("UsernamesInCrawlers") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("DefaultQueries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QuerySummaryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.HasKey("Id"); b.HasIndex("QuerySummaryId"); b.ToTable("QueryCrawlerSummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("IsReliableSource") .HasColumnType("tinyint(1)"); b.Property("MainUsername") .IsRequired() .HasColumnType("longtext"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("QueryHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("GenerateTime") .HasColumnType("datetime(6)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("Submission") .HasColumnType("int"); b.Property("SummaryWarnings") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId") .IsUnique(); b.ToTable("QuerySummaries"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CrawlerName") .IsRequired() .HasColumnType("longtext"); b.Property("ErrorMessage") .HasColumnType("longtext"); b.Property("IsVirtualJudge") .HasColumnType("tinyint(1)"); b.Property("QueryHistoryId") .HasColumnType("bigint"); b.Property("Solved") .HasColumnType("int"); b.Property("SolvedList") .HasColumnType("longtext"); b.Property("Submission") .HasColumnType("int"); b.Property("SubmissionsByCrawlerName") .HasColumnType("longtext"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryHistoryId"); b.ToTable("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("FromCrawlerName") .HasColumnType("longtext"); b.Property("QueryCrawlerSummaryId") .HasColumnType("bigint"); b.Property("Username") .IsRequired() .HasColumnType("longtext"); b.HasKey("Id"); b.HasIndex("QueryCrawlerSummaryId"); b.ToTable("UsernameInCrawler"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("ConnectionString") .HasMaxLength(1024) .HasColumnType("varchar(1024)"); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("DeleterUserId") .HasColumnType("bigint"); b.Property("DeletionTime") .HasColumnType("datetime(6)"); b.Property("EditionId") .HasColumnType("int"); b.Property("IsActive") .HasColumnType("tinyint(1)"); b.Property("IsDeleted") .HasColumnType("tinyint(1)"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("Name") .IsRequired() .HasMaxLength(128) .HasColumnType("varchar(128)"); b.Property("TenancyName") .IsRequired() .HasMaxLength(64) .HasColumnType("varchar(64)"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("DeleterUserId"); b.HasIndex("EditionId"); b.HasIndex("LastModifierUserId"); b.HasIndex("TenancyName"); b.ToTable("AbpTenants"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); b.Property("CreationTime") .HasColumnType("datetime(6)"); b.Property("CreatorUserId") .HasColumnType("bigint"); b.Property("LastModificationTime") .HasColumnType("datetime(6)"); b.Property("LastModifierUserId") .HasColumnType("bigint"); b.Property("LastTimeZoneChangedTime") .HasColumnType("datetime(6)"); b.Property("UserId") .HasColumnType("bigint"); b.HasKey("Id"); b.HasIndex("CreatorUserId"); b.HasIndex("LastModifierUserId"); b.HasIndex("UserId"); b.ToTable("UserSettingAttributes"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.Property("EditionId") .HasColumnType("int"); b.HasIndex("EditionId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("EditionFeatureSetting"); }); modelBuilder.Entity("Abp.MultiTenancy.TenantFeatureSetting", b => { b.HasBaseType("Abp.Application.Features.FeatureSetting"); b.HasIndex("TenantId", "Name"); b.ToTable("AbpFeatures"); b.HasDiscriminator().HasValue("TenantFeatureSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("RoleId") .HasColumnType("int"); b.HasIndex("RoleId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("RolePermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasBaseType("Abp.Authorization.PermissionSetting"); b.Property("UserId") .HasColumnType("bigint"); b.HasIndex("UserId"); b.ToTable("AbpPermissions"); b.HasDiscriminator().HasValue("UserPermissionSetting"); }); modelBuilder.Entity("Abp.Authorization.Roles.RoleClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Claims") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserClaim", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Claims") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserLogin", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Logins") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserRole", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Roles") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserToken", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Tokens") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Configuration.Setting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Settings") .HasForeignKey("UserId"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityProperty", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany() .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicEntityPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicEntityProperty", "DynamicEntityProperty") .WithMany() .HasForeignKey("DynamicEntityPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicEntityProperty"); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicPropertyValue", b => { b.HasOne("Abp.DynamicEntityProperties.DynamicProperty", "DynamicProperty") .WithMany("DynamicPropertyValues") .HasForeignKey("DynamicPropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DynamicProperty"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.HasOne("Abp.EntityHistory.EntityChangeSet", null) .WithMany("EntityChanges") .HasForeignKey("EntityChangeSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.EntityHistory.EntityPropertyChange", b => { b.HasOne("Abp.EntityHistory.EntityChange", null) .WithMany("PropertyChanges") .HasForeignKey("EntityChangeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.HasOne("Abp.Organizations.OrganizationUnit", "Parent") .WithMany("Children") .HasForeignKey("ParentId"); b.Navigation("Parent"); }); modelBuilder.Entity("Abp.Webhooks.WebhookSendAttempt", b => { b.HasOne("Abp.Webhooks.WebhookEvent", "WebhookEvent") .WithMany() .HasForeignKey("WebhookEventId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("WebhookEvent"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.DefaultQuery", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QuerySummary", "QuerySummary") .WithMany("QueryCrawlerSummaries") .HasForeignKey("QuerySummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QuerySummary"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithOne() .HasForeignKey("AcmStatisticsBackend.Crawlers.QuerySummary", "QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryWorkerHistory", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryHistory", "QueryHistory") .WithMany("QueryWorkerHistories") .HasForeignKey("QueryHistoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryHistory"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.UsernameInCrawler", b => { b.HasOne("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", "QueryCrawlerSummary") .WithMany("Usernames") .HasForeignKey("QueryCrawlerSummaryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("QueryCrawlerSummary"); }); modelBuilder.Entity("AcmStatisticsBackend.MultiTenancy.Tenant", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "DeleterUser") .WithMany() .HasForeignKey("DeleterUserId"); b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.Navigation("CreatorUser"); b.Navigation("DeleterUser"); b.Navigation("Edition"); b.Navigation("LastModifierUser"); }); modelBuilder.Entity("AcmStatisticsBackend.Settings.UserSettingAttribute", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "CreatorUser") .WithMany() .HasForeignKey("CreatorUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "LastModifierUser") .WithMany() .HasForeignKey("LastModifierUserId"); b.HasOne("AcmStatisticsBackend.Authorization.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("CreatorUser"); b.Navigation("LastModifierUser"); b.Navigation("User"); }); modelBuilder.Entity("Abp.Application.Features.EditionFeatureSetting", b => { b.HasOne("Abp.Application.Editions.Edition", "Edition") .WithMany() .HasForeignKey("EditionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Edition"); }); modelBuilder.Entity("Abp.Authorization.Roles.RolePermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Roles.Role", null) .WithMany("Permissions") .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.Authorization.Users.UserPermissionSetting", b => { b.HasOne("AcmStatisticsBackend.Authorization.Users.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("Abp.DynamicEntityProperties.DynamicProperty", b => { b.Navigation("DynamicPropertyValues"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChange", b => { b.Navigation("PropertyChanges"); }); modelBuilder.Entity("Abp.EntityHistory.EntityChangeSet", b => { b.Navigation("EntityChanges"); }); modelBuilder.Entity("Abp.Organizations.OrganizationUnit", b => { b.Navigation("Children"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Roles.Role", b => { b.Navigation("Claims"); b.Navigation("Permissions"); }); modelBuilder.Entity("AcmStatisticsBackend.Authorization.Users.User", b => { b.Navigation("Claims"); b.Navigation("Logins"); b.Navigation("Permissions"); b.Navigation("Roles"); b.Navigation("Settings"); b.Navigation("Tokens"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryCrawlerSummary", b => { b.Navigation("Usernames"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QueryHistory", b => { b.Navigation("QueryWorkerHistories"); }); modelBuilder.Entity("AcmStatisticsBackend.Crawlers.QuerySummary", b => { b.Navigation("QueryCrawlerSummaries"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/AcmStatisticsBackend.Web.Core.csproj ================================================ 1.0.0.0 net8.0 AcmStatisticsBackend.Web.Core AcmStatisticsBackend.Web.Core false false false false false false false false false AcmStatisticsBackend 7.2 ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/AcmStatisticsBackendWebCoreModule.cs ================================================ using System; using System.Text; using Abp.AspNetCore; using Abp.AspNetCore.Configuration; using Abp.Configuration.Startup; using Abp.Modules; using Abp.Reflection.Extensions; using Abp.Zero.Configuration; using AcmStatisticsBackend.Authentication.JwtBearer; using AcmStatisticsBackend.Configuration; using AcmStatisticsBackend.EntityFrameworkCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; namespace AcmStatisticsBackend { [DependsOn( typeof(AcmStatisticsBackendApplicationModule), typeof(AcmStatisticsBackendEntityFrameworkModule), typeof(AbpAspNetCoreModule))] public class AcmStatisticsBackendWebCoreModule : AbpModule { private readonly IWebHostEnvironment _env; private readonly IConfigurationRoot _appConfiguration; public AcmStatisticsBackendWebCoreModule(IWebHostEnvironment env) { _env = env; _appConfiguration = env.GetAppConfiguration(); } public override void PreInitialize() { Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString( AcmStatisticsBackendConsts.ConnectionStringName); // Use database for language management Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization(); Configuration.Modules.AbpAspNetCore() .CreateControllersForAppServices( typeof(AcmStatisticsBackendApplicationModule).GetAssembly()); ConfigureTokenAuth(); } private void ConfigureTokenAuth() { IocManager.Register(); var tokenAuthConfig = IocManager.Resolve(); tokenAuthConfig.SecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_appConfiguration["Authentication:JwtBearer:SecurityKey"])); tokenAuthConfig.Issuer = _appConfiguration["Authentication:JwtBearer:Issuer"]; tokenAuthConfig.Audience = _appConfiguration["Authentication:JwtBearer:Audience"]; tokenAuthConfig.SigningCredentials = new SigningCredentials(tokenAuthConfig.SecurityKey, SecurityAlgorithms.HmacSha256); tokenAuthConfig.Expiration = TimeSpan.FromDays(1); } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AcmStatisticsBackendWebCoreModule).GetAssembly()); } public override void PostInitialize() { IocManager.Resolve() .AddApplicationPartsIfNotAddedBefore(typeof(AcmStatisticsBackendWebCoreModule).Assembly); Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Authentication/JwtBearer/JwtTokenMiddleware.cs ================================================ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; namespace AcmStatisticsBackend.Authentication.JwtBearer { public static class JwtTokenMiddleware { public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string schema = JwtBearerDefaults.AuthenticationScheme) { return app.Use(async (ctx, next) => { if (ctx.User.Identity?.IsAuthenticated != true) { var result = await ctx.AuthenticateAsync(schema); if (result.Succeeded && result.Principal != null) { ctx.User = result.Principal; } } await next(); }); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Authentication/JwtBearer/TokenAuthConfiguration.cs ================================================ using System; using Microsoft.IdentityModel.Tokens; namespace AcmStatisticsBackend.Authentication.JwtBearer { public class TokenAuthConfiguration { public SymmetricSecurityKey SecurityKey { get; set; } public string Issuer { get; set; } public string Audience { get; set; } public SigningCredentials SigningCredentials { get; set; } public TimeSpan Expiration { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Configuration/HostingEnvironmentExtensions.cs ================================================ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; namespace AcmStatisticsBackend.Configuration { public static class HostingEnvironmentExtensions { public static IConfigurationRoot GetAppConfiguration(this IWebHostEnvironment env) { return AppConfigurations.Get(env.ContentRootPath, env.EnvironmentName, env.IsDevelopment()); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Controllers/AcmStatisticsBackendControllerBase.cs ================================================ using Abp.AspNetCore.Mvc.Controllers; using Abp.IdentityFramework; using Microsoft.AspNetCore.Identity; namespace AcmStatisticsBackend.Controllers { public abstract class AcmStatisticsBackendControllerBase : AbpController { protected AcmStatisticsBackendControllerBase() { LocalizationSourceName = AcmStatisticsBackendConsts.LocalizationSourceName; } protected void CheckErrors(IdentityResult identityResult) { identityResult.CheckErrors(LocalizationManager); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Controllers/TokenAuthController.cs ================================================ using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Abp.Authorization; using Abp.Authorization.Users; using Abp.MultiTenancy; using Abp.Runtime.Security; using AcmStatisticsBackend.Authentication.JwtBearer; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Models.TokenAuth; using AcmStatisticsBackend.MultiTenancy; using Microsoft.AspNetCore.Mvc; namespace AcmStatisticsBackend.Controllers { [Route("api/[controller]/[action]")] public class TokenAuthController : AcmStatisticsBackendControllerBase { private readonly LogInManager _logInManager; private readonly ITenantCache _tenantCache; private readonly AbpLoginResultTypeHelper _abpLoginResultTypeHelper; private readonly TokenAuthConfiguration _configuration; public TokenAuthController( LogInManager logInManager, ITenantCache tenantCache, AbpLoginResultTypeHelper abpLoginResultTypeHelper, TokenAuthConfiguration configuration) { _logInManager = logInManager; _tenantCache = tenantCache; _abpLoginResultTypeHelper = abpLoginResultTypeHelper; _configuration = configuration; } [HttpPost] public async Task Authenticate([FromBody] AuthenticateModel model) { var loginResult = await GetLoginResultAsync( model.UserNameOrEmailAddress, model.Password, GetTenancyNameOrNull()); var expiration = model.RememberClient ? TimeSpan.FromDays(30) : _configuration.Expiration; var accessToken = CreateAccessToken( CreateJwtClaims(loginResult.Identity), expiration); return new AuthenticateResultModel { AccessToken = accessToken, ExpireInSeconds = (int)expiration.TotalSeconds, UserId = loginResult.User.Id, }; } private string GetTenancyNameOrNull() { if (!AbpSession.TenantId.HasValue) { return null; } return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName; } private async Task> GetLoginResultAsync( string usernameOrEmailAddress, string password, string tenancyName) { var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName); switch (loginResult.Result) { case AbpLoginResultType.Success: return loginResult; default: throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName); } } private string CreateAccessToken(IEnumerable claims, TimeSpan? expiration = null) { var now = DateTime.UtcNow; var jwtSecurityToken = new JwtSecurityToken( issuer: _configuration.Issuer, audience: _configuration.Audience, claims: claims, notBefore: now, expires: now.Add(expiration ?? _configuration.Expiration), signingCredentials: _configuration.SigningCredentials); return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); } private static List CreateJwtClaims(ClaimsIdentity identity) { var claims = identity.Claims.ToList(); var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier); // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims. claims.AddRange(new[] { new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64), }); return claims; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Middleware/CookieAuthMiddleware.cs ================================================ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace AcmStatisticsBackend.Middleware { /// /// 如果 header 中没有 authorization,就从cookie中取到并放进header中 /// public class CookieAuthMiddleware { private const string CookieAuthKey = "OAuthToken"; private const string AuthorizationStart = "Bearer "; private readonly RequestDelegate _next; public CookieAuthMiddleware(RequestDelegate next) { this._next = next ?? throw new ArgumentNullException(nameof(next)); } public async Task Invoke(HttpContext context) { if (context.Request.Cookies.TryGetValue(CookieAuthKey, out var token) && !context.Request.Headers.ContainsKey("Authorization")) { context.Request.Headers.Add("Authorization", AuthorizationStart + token); } await this._next(context); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Models/TokenAuth/AuthenticateModel.cs ================================================ using System.ComponentModel.DataAnnotations; using Abp.Auditing; using Abp.Authorization.Users; namespace AcmStatisticsBackend.Models.TokenAuth { public class AuthenticateModel { [Required] [StringLength(AbpUserBase.MaxEmailAddressLength)] public string UserNameOrEmailAddress { get; set; } [Required] [StringLength(AbpUserBase.MaxPlainPasswordLength)] [DisableAuditing] public string Password { get; set; } public bool RememberClient { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Models/TokenAuth/AuthenticateResultModel.cs ================================================ namespace AcmStatisticsBackend.Models.TokenAuth { public class AuthenticateResultModel { public string AccessToken { get; set; } public int ExpireInSeconds { get; set; } public long UserId { get; set; } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Core/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("AcmStatisticsBackend.Web.Core")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AcmStatisticsBackend.Web.Core")] [assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("22cfe0d2-8dca-42d7-ad7d-784c3862493f")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/AcmStatisticsBackend.Web.Host.csproj ================================================ net8.0 true AcmStatisticsBackend.Web.Host Exe AcmStatisticsBackend.Web.Host AbpCompanyName-AcmStatisticsBackend-56C2EF2F-ABD6-4EFC-AAF2-2E81C34E8FB1 true true 7.2 ..\..\..\build\docker-compose.dcproj Linux ..\.. Always PreserveNewest PreserveNewest PreserveNewest all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Controllers/AntiForgeryController.cs ================================================ using Abp.Web.Security.AntiForgery; using AcmStatisticsBackend.Controllers; using Microsoft.AspNetCore.Antiforgery; namespace AcmStatisticsBackend.Web.Host.Controllers { public class AntiForgeryController : AcmStatisticsBackendControllerBase { private readonly IAntiforgery _antiforgery; private readonly IAbpAntiForgeryManager _antiForgeryManager; public AntiForgeryController(IAntiforgery antiforgery, IAbpAntiForgeryManager antiForgeryManager) { _antiforgery = antiforgery; _antiForgeryManager = antiForgeryManager; } public void GetToken() { _antiforgery.SetCookieTokenAndHeader(HttpContext); } public void SetCookie() { _antiForgeryManager.SetCookie(HttpContext); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Dockerfile ================================================ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["src/AcmStatisticsBackend.Web.Host/AcmStatisticsBackend.Web.Host.csproj", "src/AcmStatisticsBackend.Web.Host/"] COPY ["src/AcmStatisticsBackend.Web.Core/AcmStatisticsBackend.Web.Core.csproj", "src/AcmStatisticsBackend.Web.Core/"] COPY ["src/AcmStatisticsBackend.EntityFrameworkCore/AcmStatisticsBackend.EntityFrameworkCore.csproj", "src/AcmStatisticsBackend.EntityFrameworkCore/"] COPY ["src/AcmStatisticsBackend.Core/AcmStatisticsBackend.Core.csproj", "src/AcmStatisticsBackend.Core/"] COPY ["src/AcmStatisticsBackend.Application/AcmStatisticsBackend.Application.csproj", "src/AcmStatisticsBackend.Application/"] RUN dotnet restore "src/AcmStatisticsBackend.Web.Host/AcmStatisticsBackend.Web.Host.csproj" COPY . . WORKDIR "/src/src/AcmStatisticsBackend.Web.Host" RUN dotnet build "AcmStatisticsBackend.Web.Host.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "AcmStatisticsBackend.Web.Host.csproj" -c Release -o /app/publish FROM base AS final RUN apt-get update && apt-get install -y wait-for-it ENV WAIT_COMMAND true WORKDIR /app COPY --from=publish /app/publish . ENV ASPNETCORE_URLS=http://0.0.0.0:80 CMD $WAIT_COMMAND && dotnet AcmStatisticsBackend.Web.Host.dll ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Properties/launchSettings.json ================================================ { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:21021/", "sslPort": 0 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "AcmStatisticsBackend.Web.Host": { "commandName": "Project", "launchBrowser": true, "launchUrl": "http://localhost:21021", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "http://localhost:21021/" }, "Docker": { "commandName": "Docker", "launchBrowser": true, "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", "publishAllPorts": true } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Startup/AcmStatisticsBackendWebHostModule.cs ================================================ using Abp.Modules; using Abp.Reflection.Extensions; using AcmStatisticsBackend.Configuration; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; namespace AcmStatisticsBackend.Web.Host.Startup { [DependsOn( typeof(AcmStatisticsBackendWebCoreModule))] public class AcmStatisticsBackendWebHostModule : AbpModule { private readonly IWebHostEnvironment _env; private readonly IConfigurationRoot _appConfiguration; public AcmStatisticsBackendWebHostModule(IWebHostEnvironment env) { _env = env; _appConfiguration = env.GetAppConfiguration(); } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AcmStatisticsBackendWebHostModule).GetAssembly()); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Startup/AuthConfigurer.cs ================================================ using System; using System.Linq; using System.Text; using System.Threading.Tasks; using Abp.Runtime.Security; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; namespace AcmStatisticsBackend.Web.Host.Startup { public static class AuthConfigurer { public static void Configure(IServiceCollection services, IConfiguration configuration) { if (bool.Parse(configuration["Authentication:JwtBearer:IsEnabled"])) { services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "JwtBearer"; options.DefaultChallengeScheme = "JwtBearer"; }).AddJwtBearer("JwtBearer", options => { options.Audience = configuration["Authentication:JwtBearer:Audience"]; options.TokenValidationParameters = new TokenValidationParameters { // The signing key must match! ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey"])), // Validate the JWT Issuer (iss) claim ValidateIssuer = true, ValidIssuer = configuration["Authentication:JwtBearer:Issuer"], // Validate the JWT Audience (aud) claim ValidateAudience = true, ValidAudience = configuration["Authentication:JwtBearer:Audience"], // Validate the token expiry ValidateLifetime = true, // If you want to allow a certain amount of clock drift, set that here ClockSkew = TimeSpan.Zero, }; }); } } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Startup/Program.cs ================================================ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace AcmStatisticsBackend.Web.Host.Startup { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) { return WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/Startup/Startup.cs ================================================ using System; using System.IO; using System.Linq; using Abp.AspNetCore; using Abp.AspNetCore.Mvc.Antiforgery; using Abp.Castle.Logging.Log4Net; using Abp.Dependency; using Abp.Extensions; using Abp.Json; using AcmStatisticsBackend.Configuration; using AcmStatisticsBackend.Identity; using AcmStatisticsBackend.Middleware; using Castle.Facilities.Logging; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using Newtonsoft.Json.Serialization; namespace AcmStatisticsBackend.Web.Host.Startup { public class Startup { private const string _defaultCorsPolicyName = "localhost"; private readonly IConfigurationRoot _appConfiguration; public Startup(IWebHostEnvironment env) { _appConfiguration = env.GetAppConfiguration(); } public IServiceProvider ConfigureServices(IServiceCollection services) { // MVC services.AddControllersWithViews( options => { options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute()); }) .AddNewtonsoftJson(options => { options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance) { NamingStrategy = new CamelCaseNamingStrategy(), }; }); IdentityRegistrar.Register(services); AuthConfigurer.Configure(services, _appConfiguration); services.AddSignalR(); // Configure CORS for angular2 UI services.AddCors( options => options.AddPolicy( _defaultCorsPolicyName, builder => builder // App:CorsOrigins in appsettings.json can contain more than one address separated by comma. .WithOrigins( _appConfiguration["App:CorsOrigins"] .Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(o => o.RemovePostFix("/")) .ToArray()) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials())); // Swagger - Enable this line and the related lines in Configure method to enable swagger UI services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo() { Title = "AcmStatisticsBackend API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); // Define the BearerAuth scheme that's in use options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme() { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, }); // Set the comments path for the swagger json and ui. var basePath = AppDomain.CurrentDomain.BaseDirectory; var docPath = Path.Combine(basePath, "AcmStatisticsBackend.Application.xml"); options.IncludeXmlComments(docPath); }); // Configure X-Forwarded-For services.Configure(options => { options.ForwardLimit = null; }); // Configure Abp and Dependency Injection return services.AddAbp( options => { // Configure Log4Net logging options.IocManager.IocContainer.AddFacility( f => f.UseAbpLog4Net().WithConfig("log4net.config")); }); } public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { app.UseMiddleware(); app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework. app.UseCors(_defaultCorsPolicyName); // Enable CORS! app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAbpRequestLocalization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}"); }); // Enable middleware to serve generated Swagger as a JSON endpoint app.UseSwagger(opts => { opts.RouteTemplate = "api/backend/{documentName}/swagger.json"; }); } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/app.config ================================================  ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/appsettings.Staging.json ================================================ { "ConnectionStrings": { "Default": "Server=10.0.75.1; Database=AcmStatisticsBackendDb; User=sa; Password=123qwe;" }, "App": { "ServerRootAddress": "http://localhost:9902/", "CorsOrigins": "http://localhost:9902" } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/appsettings.json ================================================ { "ConnectionStrings": { "Default": "Server=localhost; port=3306; Database=acm_statistics_abp; uid=root; pwd=123456; Convert Zero Datetime=True" }, "App": { "ServerRootAddress": "http://localhost:3000/", "ClientRootAddress": "http://localhost:4200/", "CorsOrigins": "http://localhost:4200,http://localhost:8080,http://localhost:8081,http://localhost:3000,http://reverse-proxy" }, "Authentication": { "JwtBearer": { "IsEnabled": "true", "SecurityKey": "AcmStatisticsBackend_C421AAEE0D114E9C", "Issuer": "AcmStatisticsBackend", "Audience": "AcmStatisticsBackend" } }, "Logging": { "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Warning" } } } ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/log4net.config ================================================  ================================================ FILE: backend/src/AcmStatisticsBackend.Web.Host/web.config ================================================  ================================================ FILE: backend/stylecop.json ================================================ { "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "settings": { "orderingRules": { "usingDirectivesPlacement": "outsideNamespace" }, "layoutRules": { "newlineAtEndOfFile": "require" } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Accounts/AccountAppService_Tests.cs ================================================ using System.Collections.Generic; using System.Threading.Tasks; using Abp.Authorization; using Abp.MultiTenancy; using Abp.UI; using AcmStatisticsBackend.Accounts; using AcmStatisticsBackend.Accounts.Dto; using AcmStatisticsBackend.Authorization; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.Crawlers.Dto; using AcmStatisticsBackend.ServiceClients; using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; namespace AcmStatisticsBackend.Tests.Accounts { public class AccountAppService_Tests : AcmStatisticsBackendTestBase { private readonly IAccountAppService _accountAppService; private readonly FakeCaptchaServiceClient _captchaServiceClient; private readonly LogInManager _logInManager; public AccountAppService_Tests() { _captchaServiceClient = new FakeCaptchaServiceClient(); _accountAppService = Resolve(new { captchaServiceClient = _captchaServiceClient, }); _logInManager = Resolve(); } [Fact] public async Task Register_应该能够正确注册() { // arrange _captchaServiceClient.Return = new CaptchaServiceValidateResult { Correct = true, ErrorMessage = null, }; // act var result = await _accountAppService.Register(new RegisterInput { UserName = "testuser", Password = "StrongPassword", CaptchaId = "aaaaa", CaptchaText = "fdafdsf", }); // assert result.CanLogin.Should().BeTrue(); await UsingDbContextAsync(async ctx => { var user = await ctx.Users.FirstOrDefaultAsync(user => user.UserName == "testuser"); user.EmailAddress.Should().Be("testuser@noemail.fake"); user.IsEmailConfirmed.Should().BeFalse(); }); } [Fact] public async Task Register_能够在验证码错误时能报错() { // arrange _captchaServiceClient.Return = new CaptchaServiceValidateResult { Correct = false, ErrorMessage = "an error message", }; // act await _accountAppService.Register(new RegisterInput { UserName = "testuser", Password = "StrongPassword", CaptchaId = "aaaaa", CaptchaText = "fdafdsf", }).ShouldThrow() // assert .WithMessage("an error message"); } [Fact] public async Task SelfDelete_能够正确删除用户() { // arrange _captchaServiceClient.Return = new CaptchaServiceValidateResult { Correct = true, ErrorMessage = null, }; await _accountAppService.Register(new RegisterInput { UserName = "user1", Password = "StrongPassword", CaptchaId = "a", CaptchaText = "a", }); await UsingDbContextAsync(1, async ctx => { var user = await ctx.Users.FirstAsync(a => a.UserName == "user1"); user.Should().NotBeNull(); }); // act LoginAsTenant(AbpTenantBase.DefaultTenantName, "user1"); await _accountAppService.SelfDelete(); // test User origUser = null; await UsingDbContextAsync(1, async ctx => { origUser = await ctx.Users.FirstOrDefaultAsync(a => a.UserName == "user1"); origUser.IsDeleted.Should().BeTrue(); }); // 能够注册相同的用户名(和邮箱) await _accountAppService.Register(new RegisterInput { UserName = "user1", Password = "StrongPassword", CaptchaId = "a", CaptchaText = "a", }); await UsingDbContextAsync(1, async ctx => { var user = await ctx.Users.FirstAsync(a => a.UserName == "user1" && !a.IsDeleted); user.Should().NotBeNull(); user.Id.Should().NotBe(origUser.Id); }); } [Fact] public async Task ChangePassword_CanWorkCorrectly() { // arrange _captchaServiceClient.Return = new CaptchaServiceValidateResult { Correct = true, ErrorMessage = null, }; await _accountAppService.Register(new RegisterInput { UserName = "user1", Password = "password1", CaptchaId = "a", CaptchaText = "a", }); var result = await _logInManager.LoginAsync("user1", "password1", AbpTenantBase.DefaultTenantName); result.Result.Should().Be(AbpLoginResultType.Success); // act LoginAsTenant(AbpTenantBase.DefaultTenantName, "user1"); await _accountAppService.ChangePassword(new ChangePasswordInput { CurrentPassword = "password1", NewPassword = "password2", }); // assert (await _logInManager.LoginAsync("user1", "password2", AbpTenantBase.DefaultTenantName)) .Result.Should().Be(AbpLoginResultType.Success); (await _logInManager.LoginAsync("user1", "password1", AbpTenantBase.DefaultTenantName)) .Result.Should().Be(AbpLoginResultType.InvalidPassword); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Accounts/FakeCaptchaServiceClient.cs ================================================ using System.Threading.Tasks; using AcmStatisticsBackend.ServiceClients; namespace AcmStatisticsBackend.Tests.Accounts { public class FakeCaptchaServiceClient : ICaptchaServiceClient { public CaptchaServiceValidateResult Return { get; set; } public Task ValidateAsync(string id, string text) { return Task.FromResult(Return); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/AcmStatisticsBackend.Tests.csproj ================================================  1.0.0.0 net8.0 AcmStatisticsBackend.Tests AcmStatisticsBackend.Tests true false false false runtime; build; native; contentfiles; analyzers; buildtransitive all all runtime; build; native; contentfiles; analyzers Always ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/AcmStatisticsBackendTestBase.cs ================================================ using System; using System.Linq; using System.Threading.Tasks; using Abp; using Abp.Authorization.Users; using Abp.Events.Bus; using Abp.Events.Bus.Entities; using Abp.MultiTenancy; using Abp.Runtime.Session; using Abp.TestBase; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.EntityFrameworkCore; using AcmStatisticsBackend.EntityFrameworkCore.Seed.Host; using AcmStatisticsBackend.EntityFrameworkCore.Seed.Tenants; using AcmStatisticsBackend.MultiTenancy; using Microsoft.EntityFrameworkCore; namespace AcmStatisticsBackend.Tests { public abstract class AcmStatisticsBackendTestBase : AbpIntegratedTestBase { protected AcmStatisticsBackendTestBase() { void NormalizeDbContext(AcmStatisticsBackendDbContext context) { context.EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; context.EventBus = NullEventBus.Instance; context.SuppressAutoSetTenantId = true; } // Seed initial data for host AbpSession.TenantId = null; UsingDbContext(context => { NormalizeDbContext(context); context.Database.EnsureCreated(); new InitialHostDbBuilder(context).Create(); new DefaultTenantBuilder(context).Create(); }); // Seed initial data for default tenant AbpSession.TenantId = 1; UsingDbContext(context => { NormalizeDbContext(context); new TenantRoleAndUserBuilder(context, 1).Create(); }); LoginAsDefaultTenantAdmin(); } #region UsingDbContext protected IDisposable UsingTenantId(int? tenantId) { var previousTenantId = AbpSession.TenantId; AbpSession.TenantId = tenantId; return new DisposeAction(() => AbpSession.TenantId = previousTenantId); } protected void UsingDbContext(Action action) { UsingDbContext(AbpSession.TenantId, action); } protected Task UsingDbContextAsync(Func action) { return UsingDbContextAsync(AbpSession.TenantId, action); } protected T UsingDbContext(Func func) { return UsingDbContext(AbpSession.TenantId, func); } protected Task UsingDbContextAsync(Func> func) { return UsingDbContextAsync(AbpSession.TenantId, func); } protected void UsingDbContext(int? tenantId, Action action) { using (UsingTenantId(tenantId)) { using (var context = LocalIocManager.Resolve()) { action(context); context.SaveChanges(); } } } protected async Task UsingDbContextAsync(int? tenantId, Func action) { using (UsingTenantId(tenantId)) { using (var context = LocalIocManager.Resolve()) { await action(context); await context.SaveChangesAsync(); } } } protected T UsingDbContext(int? tenantId, Func func) { T result; using (UsingTenantId(tenantId)) { using (var context = LocalIocManager.Resolve()) { result = func(context); context.SaveChanges(); } } return result; } protected async Task UsingDbContextAsync(int? tenantId, Func> func) { T result; using (UsingTenantId(tenantId)) { using (var context = LocalIocManager.Resolve()) { result = await func(context); await context.SaveChangesAsync(); } } return result; } #endregion #region Login protected void LoginAsHostAdmin() { LoginAsHost(AbpUserBase.AdminUserName); } protected void LoginAsDefaultTenantAdmin() { LoginAsTenant(AbpTenantBase.DefaultTenantName, AbpUserBase.AdminUserName); } protected void LoginAsDefaultTenant(string userName) { LoginAsTenant(AbpTenantBase.DefaultTenantName, userName); } protected void LoginAsHost(string userName) { var user = GetHostUser(userName); AbpSession.UserId = user.Id; } protected void LoginAsTenant(string tenancyName, string userName) { var tenant = UsingDbContext(context => context.Tenants.FirstOrDefault(t => t.TenancyName == tenancyName)); if (tenant == null) { throw new Exception("There is no tenant: " + tenancyName); } AbpSession.TenantId = tenant.Id; var user = UsingDbContext( context => context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName)); if (user == null) { throw new Exception("There is no user: " + userName + " for tenant: " + tenancyName); } AbpSession.UserId = user.Id; } #endregion #region GetUser /// /// Gets current user if is not null. /// Throws exception if it's null. /// protected async Task GetCurrentUserAsync() { var userId = AbpSession.GetUserId(); return await UsingDbContext(context => context.Users.SingleAsync(u => u.Id == userId)); } /// /// Gets current tenant if is not null. /// Throws exception if there is no current tenant. /// protected async Task GetCurrentTenantAsync() { var tenantId = AbpSession.GetTenantId(); return await UsingDbContext(context => context.Tenants.SingleAsync(t => t.Id == tenantId)); } protected User GetHostUser(string userName) { AbpSession.TenantId = null; var user = UsingDbContext( context => context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName)); if (user == null) { throw new Exception("There is no user: " + userName + " for host."); } return user; } protected User GetHostAdmin() { return GetHostUser(AbpUserBase.AdminUserName); } #endregion } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/AcmStatisticsBackendTestModule.cs ================================================ using System; using Abp.AutoMapper; using Abp.Configuration.Startup; using Abp.Dependency; using Abp.Modules; using Abp.Net.Mail; using Abp.TestBase; using Abp.Zero.Configuration; using Abp.Zero.EntityFrameworkCore; using AcmStatisticsBackend.EntityFrameworkCore; using AcmStatisticsBackend.Tests.DependencyInjection; using Castle.MicroKernel.Registration; using NSubstitute; using Xunit; namespace AcmStatisticsBackend.Tests { [DependsOn( typeof(AcmStatisticsBackendApplicationModule), typeof(AcmStatisticsBackendEntityFrameworkModule), typeof(AbpTestBaseModule))] public class AcmStatisticsBackendTestModule : AbpModule { private readonly ServiceCollectionRegistrar _registrar; public AcmStatisticsBackendTestModule( AcmStatisticsBackendEntityFrameworkModule abpProjectNameEntityFrameworkModule) { abpProjectNameEntityFrameworkModule.SkipDbContextRegistration = true; abpProjectNameEntityFrameworkModule.SkipDbSeed = true; _registrar = new ServiceCollectionRegistrar(); } public override void PreInitialize() { Configuration.UnitOfWork.Timeout = TimeSpan.FromMinutes(30); Configuration.UnitOfWork.IsTransactional = false; // Disable static mapper usage since it breaks unit tests (see https://github.com/aspnetboilerplate/aspnetboilerplate/issues/2052) Configuration.Modules.AbpAutoMapper().UseStaticMapper = false; Configuration.BackgroundJobs.IsJobExecutionEnabled = false; // Use database for language management Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization(); RegisterFakeService>(); Configuration.ReplaceService(DependencyLifeStyle.Transient); } public override void Initialize() { _registrar.Register(IocManager); } public override void Shutdown() { _registrar.Dispose(); base.Shutdown(); } private void RegisterFakeService() where TService : class { IocManager.IocContainer.Register( Component.For() .UsingFactoryMethod(() => Substitute.For()) .LifestyleSingleton()); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Crawlers/DefaultQueryAppService_Tests.cs ================================================ using System.Collections.Generic; using System.Threading.Tasks; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.Crawlers.Dto; using FluentAssertions; using Xunit; namespace AcmStatisticsBackend.Tests.Crawlers { public class DefaultQueryAppService_Tests : AcmStatisticsBackendTestBase { private readonly IDefaultQueryAppService _appService; public DefaultQueryAppService_Tests() { _appService = Resolve(); } [Fact] public async Task GetDefaultQueries_ShouldWorkCorrectly() { // act await _appService.SetDefaultQueries(new DefaultQueryDto { MainUsername = "mainUsername", UsernamesInCrawlers = new Dictionary> { { "crawler1", new List { "username1", "username2" } }, { "crawler2", new List { "username3", "username4" } }, }, }); var result = await _appService.GetDefaultQueries(); // assert result.Should().BeEquivalentTo(new DefaultQueryDto { MainUsername = "mainUsername", UsernamesInCrawlers = new Dictionary> { { "crawler1", new List { "username1", "username2" } }, { "crawler2", new List { "username3", "username4" } }, }, }); } [Fact] public async Task SetDefaultQueries_ShouldWorkCorrectly() { // act await _appService.SetDefaultQueries(new DefaultQueryDto { MainUsername = "", }); var result = await _appService.GetDefaultQueries(); // assert result.Should().BeEquivalentTo(new DefaultQueryDto { MainUsername = "", UsernamesInCrawlers = new Dictionary>(), }); } [Fact] public async Task GetDefaultQueries_WhenNoRecord_ReturnResultWithEmptyParameters() { // act var result = await _appService.GetDefaultQueries(); // assert result.Should().BeEquivalentTo(new DefaultQueryDto { MainUsername = "", UsernamesInCrawlers = new Dictionary>(), }); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Crawlers/QueryHistoryAppService_Tests.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Abp.Application.Services.Dto; using Abp.Timing; using Abp.UI; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.Crawlers.Dto; using AcmStatisticsBackend.ServiceClients; using AcmStatisticsBackend.Tests.DependencyInjection; using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; namespace AcmStatisticsBackend.Tests.Crawlers { public class QueryHistoryAppService_Tests : AcmStatisticsBackendTestBase { private IQueryHistoryAppService _queryHistoryAppService; private TestClockProvider _testClockProvider; protected override void PreInitialize() { LocalIocManager.Register(); } protected override void PostInitialize() { _testClockProvider = Resolve() as TestClockProvider; var testCrawlerApiBackendClient = new TestCrawlerApiBackendClient(); _queryHistoryAppService = Resolve(new { crawlerApiBackendClient = testCrawlerApiBackendClient, }); testCrawlerApiBackendClient.CrawlerMeta = new List { new CrawlerMetaItem { CrawlerName = "c1", CrawlerTitle = "C1", Url = "", CrawlerDescription = "", IsVirtualJudge = false, }, new CrawlerMetaItem { CrawlerName = "c2", CrawlerTitle = "C2", Url = "", CrawlerDescription = "", IsVirtualJudge = false, }, new CrawlerMetaItem { CrawlerName = "c3", CrawlerTitle = "C3", Url = "", CrawlerDescription = "", IsVirtualJudge = true, }, new CrawlerMetaItem { CrawlerName = "c4", CrawlerTitle = "C4", Url = "", CrawlerDescription = "", IsVirtualJudge = true, }, }; } [Fact] public async Task SaveOrReplaceQueryHistory_CanSaveRecord() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); // act var result = await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "mainUser", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { Username = "u1", CrawlerName = "c1", Solved = 3, Submission = 20, ErrorMessage = null, SolvedList = new[] { "p1", "p2", "p3", }, }, new QueryWorkerHistoryDto { Username = "u2", CrawlerName = "c2", ErrorMessage = "Cannot find username", }, }, }); // assert UsingDbContext(ctx => { ctx.QueryHistories.Should().HaveCount(1); var acHistory = ctx.QueryHistories.Single(); Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); acHistory.UserId.Should().Be(AbpSession.UserId.Value); acHistory.CreationTime.Should().Be(new DateTime(2020, 4, 1, 10, 0, 0)); acHistory.MainUsername.Should().Be("mainUser"); acHistory.IsReliableSource.Should().BeFalse(); ctx.QueryWorkerHistories.Should().HaveCount(2); var list = ctx.QueryWorkerHistories.ToList(); list[0].WithIn(it => { it.Solved.Should().Be(3); it.Submission.Should().Be(20); it.Username.Should().Be("u1"); it.CrawlerName.Should().Be("c1"); it.QueryHistoryId.Should().Be(acHistory.Id); it.ErrorMessage.Should().Be(null); it.SolvedList.Should().Equal("p1", "p2", "p3"); }); list[1].WithIn(it => { it.Solved.Should().Be(0); it.SolvedList.Should().BeNull(); it.ErrorMessage.Should().Be("Cannot find username"); }); }); result.QueryHistoryId.Should().Be(1); } [Fact] public async Task SaveOrReplaceQueryHistory_CanReplaceRecordOfTheSameDay() { // arrange LoginAsDefaultTenantAdmin(); // act _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "u1", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { CrawlerName = "c1", Username = "u1", Solved = 1, Submission = 10, }, }, }); // 第二次存储 _testClockProvider.Now = new DateTime(2020, 4, 1, 20, 0, 0); var result = await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "u1", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { CrawlerName = "c1", Username = "u1", Solved = 5, Submission = 10, }, }, }); // assert UsingDbContext(ctx => { ctx.QueryHistories.Should().HaveCount(1); var history = ctx.QueryHistories.Single(); ctx.QueryWorkerHistories.Should().HaveCount(1); var workerHistory = ctx.QueryWorkerHistories.Single(); workerHistory.QueryHistoryId.Should().Be(history.Id); workerHistory.Solved.Should().Be(5); }); result.QueryHistoryId.Should().Be(2); } [Fact] public async Task SaveOrReplaceAcHistory_ShouldKeepRecordsOfDifferentDays() { // arrange LoginAsDefaultTenantAdmin(); // act _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "u1", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { CrawlerName = "c1", Username = "u1", Solved = 1, Submission = 10, }, }, }); // 第二次存储 _testClockProvider.Now = new DateTime(2020, 4, 2, 10, 0, 0); var result = await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "u1", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { CrawlerName = "c1", Username = "u1", Solved = 5, Submission = 10, }, }, }); // assert UsingDbContext(ctx => { ctx.QueryHistories.Should().HaveCount(2); ctx.QueryWorkerHistories.Should().HaveCount(2); }); result.QueryHistoryId.Should().Be(2); } [Fact] public async Task SaveOrReplaceQueryHistory_ShouldGenerateSummary() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); // act var result = await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "mainUser", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { Username = "u1", CrawlerName = "c1", Solved = 3, Submission = 20, ErrorMessage = null, SolvedList = new[] { "p1", "p2", "p3", }, }, new QueryWorkerHistoryDto { Username = "u2", CrawlerName = "c2", ErrorMessage = "Cannot find username", }, }, }); // assert UsingDbContext(ctx => { ctx.QuerySummaries.Should().HaveCount(1); var querySummary = ctx.QuerySummaries.Single(); querySummary.WithIn(it => { it.Solved.Should().Be(3); it.Submission.Should().Be(20); it.QueryHistoryId.Should().Be(result.QueryHistoryId); }); ctx.QueryCrawlerSummaries.Should().HaveCount(1); ctx.QueryCrawlerSummaries.Single().WithIn(it => { it.QuerySummaryId.Should().Be(querySummary.Id); }); }); } [Fact] public async Task DeleteAcHistory_ShouldRemoveAcHistoryAndAcWorkerHistoryAtTheSameTime() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "u1", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { CrawlerName = "c1", Username = "u1", Solved = 1, Submission = 10, }, }, }); // act await _queryHistoryAppService.DeleteQueryHistory(new DeleteQueryHistoryInput { Id = 1, }); // assert UsingDbContext(ctx => { ctx.QueryHistories.Should().HaveCount(0); ctx.QueryWorkerHistories.Should().HaveCount(0); ctx.QuerySummaries.Should().HaveCount(0); ctx.QueryCrawlerSummaries.Should().HaveCount(0); }); } [Fact] public async Task GetAcHistory_ShouldWorkCorrectly() { // arrange LoginAsDefaultTenantAdmin(); await UsingDbContextAsync(async ctx => { Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); await ctx.QueryHistories.AddAsync(new QueryHistory { MainUsername = "u1", CreationTime = new DateTime(2020, 4, 1, 10, 0, 0), UserId = AbpSession.UserId.Value, }); }); // act var result = await _queryHistoryAppService.GetQueryHistories(new PagedResultRequestDto { SkipCount = 0, MaxResultCount = 5, }); // assert result.TotalCount.Should().Be(1); result.Items[0].WithIn(it => { it.MainUsername.Should().Be("u1"); it.CreationTime.Should().Be(new DateTime(2020, 4, 1, 10, 0, 0)); }); } [Fact] public async Task GetAcHistory_ShouldReturnHistoriesInCorrectOrder() { // arrange LoginAsDefaultTenantAdmin(); await UsingDbContextAsync(async ctx => { Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); await ctx.QueryHistories.AddRangeAsync(new[] { new QueryHistory { MainUsername = "u1", CreationTime = new DateTime(2020, 4, 1, 10, 0, 0), UserId = AbpSession.UserId.Value, }, new QueryHistory { MainUsername = "u1", CreationTime = new DateTime(2020, 4, 2, 10, 0, 0), UserId = AbpSession.UserId.Value, }, }); }); // act var result = await _queryHistoryAppService.GetQueryHistories(new PagedResultRequestDto { SkipCount = 0, MaxResultCount = 5, }); // assert result.TotalCount.Should().Be(2); result.Items[0].WithIn(it => { it.MainUsername.Should().Be("u1"); it.CreationTime.Should().Be(new DateTime(2020, 4, 2, 10, 0, 0)); }); result.Items[1].WithIn(it => { it.MainUsername.Should().Be("u1"); it.CreationTime.Should().Be(new DateTime(2020, 4, 1, 10, 0, 0)); }); } [Fact] public async Task GetAcWorkerHistory_ShouldWorkCorrectly() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "mainUser", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { Username = "u1", CrawlerName = "c1", Solved = 3, Submission = 20, ErrorMessage = null, SolvedList = new[] { "p1", "p2", "p3", }, IsVirtualJudge = false, }, new QueryWorkerHistoryDto { Username = "u2", CrawlerName = "c2", ErrorMessage = "Cannot find username", }, }, }); var historyResponse = await _queryHistoryAppService.GetQueryHistories(new PagedResultRequestDto()); var historyId = historyResponse.Items[0].Id; // act var list = await _queryHistoryAppService.GetQueryWorkerHistories(new GetAcWorkerHistoryInput { QueryHistoryId = historyId, }); // assert list.Items.Count.Should().Be(2); list.Items[0].WithIn(it => { it.Solved.Should().Be(3); it.Submission.Should().Be(20); it.Username.Should().Be("u1"); it.CrawlerName.Should().Be("c1"); it.ErrorMessage.Should().BeNull(); it.SolvedList.Should().Equal("p1", "p2", "p3"); }); list.Items[1].WithIn(it => { it.Solved.Should().Be(0); it.Username.Should().Be("u2"); it.CrawlerName.Should().Be("c2"); it.ErrorMessage.Should().Be("Cannot find username"); it.SolvedList.Should().BeNull(); }); } [Fact] public async Task It_CanSaveAndGetRecordWithSubmissions() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); // act await _queryHistoryAppService.SaveOrReplaceQueryHistory(new SaveOrReplaceQueryHistoryInput { MainUsername = "mainUser", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { Username = "u1", CrawlerName = "c1", Solved = 3, Submission = 10, ErrorMessage = null, SolvedList = new[] { "p1", "p2", "p3", }, }, new QueryWorkerHistoryDto { Username = "u2", CrawlerName = "c3", Solved = 3, Submission = 10, SolvedList = new[] { "c1-p1", "c1-p5", "NO_NAME-1001", }, IsVirtualJudge = true, SubmissionsByCrawlerName = new Dictionary { { "c1", 5 }, { "NO_NAME", 5 }, }, }, }, }); // assert await UsingDbContextAsync(async ctx => { (await ctx.QueryHistories.CountAsync()).Should().Be(1); var acHistory = await ctx.QueryHistories.FirstAsync(); Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); acHistory.UserId.Should().Be(AbpSession.UserId.Value); acHistory.CreationTime.Should().Be(new DateTime(2020, 4, 1, 10, 0, 0)); acHistory.MainUsername.Should().Be("mainUser"); (await ctx.QueryWorkerHistories.CountAsync()).Should().Be(2); var list = await ctx.QueryWorkerHistories.ToListAsync(); list[0].WithIn(it => { it.Solved.Should().Be(3); it.Submission.Should().Be(10); it.Username.Should().Be("u1"); it.CrawlerName.Should().Be("c1"); it.QueryHistoryId.Should().Be(acHistory.Id); it.ErrorMessage.Should().Be(null); it.SolvedList.Should().Equal("p1", "p2", "p3"); }); list[1].WithIn(it => { it.Solved.Should().Be(3); it.SolvedList.Should().Equal("c1-p1", "c1-p5", "NO_NAME-1001"); it.IsVirtualJudge.Should().Be(true); it.SubmissionsByCrawlerName.Should().BeEquivalentTo(new Dictionary { { "c1", 5 }, { "NO_NAME", 5 }, }); }); }); } [Fact] public async Task GetQuerySummary_ShouldWorkCorrectly() { // arrange LoginAsDefaultTenantAdmin(); _testClockProvider.Now = new DateTime(2020, 4, 1, 10, 0, 0); var saveOrReplaceQueryHistoryOutput = await _queryHistoryAppService.SaveOrReplaceQueryHistory( new SaveOrReplaceQueryHistoryInput { MainUsername = "mainUser", QueryWorkerHistories = new List { new QueryWorkerHistoryDto { Username = "u1", CrawlerName = "c1", Solved = 3, Submission = 20, ErrorMessage = null, SolvedList = new[] { "p1", "p2", "p3", }, }, new QueryWorkerHistoryDto { Username = "u2", CrawlerName = "c2", ErrorMessage = "Cannot find username", }, }, }); // act var result = await _queryHistoryAppService.GetQuerySummary(new GetQuerySummaryInput { QueryHistoryId = saveOrReplaceQueryHistoryOutput.QueryHistoryId, }); // assert result.Should().BeEquivalentTo(new QuerySummaryDto { QueryHistoryId = saveOrReplaceQueryHistoryOutput.QueryHistoryId, GenerateTime = _testClockProvider.Now, MainUsername = "mainUser", Solved = 3, Submission = 20, SummaryWarnings = new List(), QueryCrawlerSummaries = new List { new QueryCrawlerSummaryDto { CrawlerName = "c1", Usernames = new List { new UsernameInCrawlerDto { Username = "u1", }, }, Solved = 3, Submission = 20, IsVirtualJudge = false, }, }, }); } [Fact] public async Task GetQuerySummary_WhenSummaryNotExist_ShouldThrow() { // arrange LoginAsDefaultTenantAdmin(); var user = await GetCurrentUserAsync(); var id = UsingDbContext(c => { var entity = new QueryHistory { UserId = user.Id, CreationTime = DateTime.Now, MainUsername = "aaa", IsReliableSource = false, }; c.QueryHistories.Add(entity); c.SaveChanges(); return entity.Id; }); // act var task = _queryHistoryAppService.GetQuerySummary(new GetQuerySummaryInput { QueryHistoryId = id, }); // assert await task.ShouldThrow() .WithMessage("This query history does not have summary"); } [Fact] public async Task GetQueryHistoriesAndSummaries_ShouldWorkCorrectly() { // arrange LoginAsDefaultTenantAdmin(); await UsingDbContextAsync(async ctx => { Debug.Assert(AbpSession.UserId != null, "AbpSession.UserId != null"); var histories = new[] { new QueryHistory { MainUsername = "u1", CreationTime = new DateTime(2020, 4, 1, 10, 0, 0), UserId = AbpSession.UserId.Value, }, // correct order new QueryHistory { MainUsername = "u1", CreationTime = new DateTime(2020, 4, 2, 10, 0, 0), UserId = AbpSession.UserId.Value, }, }; await ctx.QueryHistories.AddRangeAsync(histories); await ctx.SaveChangesAsync(); await ctx.QuerySummaries.AddRangeAsync(new[] { // test join summary new QuerySummary { QueryHistoryId = histories[0].Id, Solved = 10, Submission = 20, GenerateTime = new DateTime(2020, 4, 3, 10, 0, 0), SummaryWarnings = new List(), }, // test left join (the second history should be outputted) }); }); // act var result = await _queryHistoryAppService.GetQueryHistoriesAndSummaries(new PagedResultRequestDto { SkipCount = 0, MaxResultCount = 5, }); // assert result.TotalCount.Should().Be(2); result.Items[0].WithIn(it => { it.CreationTime.Should().Be(new DateTime(2020, 4, 2, 10, 0, 0)); it.Solved.Should().BeNull(); it.Submission.Should().BeNull(); }); result.Items[1].WithIn(it => { it.CreationTime.Should().Be(new DateTime(2020, 4, 1, 10, 0, 0)); it.Solved.Should().Be(10); it.Submission.Should().Be(20); }); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Crawlers/QuerySummary_ModelTests.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Abp.Domain.Repositories; using Abp.TestBase; using AcmStatisticsBackend.Authorization.Users; using AcmStatisticsBackend.Crawlers; using FluentAssertions; using Xunit; namespace AcmStatisticsBackend.Tests.Crawlers { public class QuerySummary_ModelTests : AcmStatisticsBackendTestBase { private readonly IRepository _queryHistoryRepository; private readonly IRepository _querySummaryRepository; private readonly UserManager _userManager; private UserRegistrationManager _userRegistrationManager; public QuerySummary_ModelTests() { _queryHistoryRepository = Resolve>(); _querySummaryRepository = Resolve>(); _userManager = Resolve(); _userRegistrationManager = Resolve(); } private async Task InsertDataByQueryHistory() { await UsingDbContextAsync(async c => { var history = await _queryHistoryRepository.InsertAsync(new QueryHistory { UserId = GetHostAdmin().Id, MainUsername = "a_user", QueryWorkerHistories = new List { new QueryWorkerHistory { Solved = 3, Submission = 10, Username = "u1", CrawlerName = "crawler", }, }, }); await _querySummaryRepository.InsertAsync(new QuerySummary { QueryHistoryId = history.Id, Solved = 0, Submission = 0, QueryCrawlerSummaries = new List { new QueryCrawlerSummary { Solved = 0, Submission = 0, Usernames = new List { new UsernameInCrawler { Username = "a_user", FromCrawlerName = "", }, }, CrawlerName = "crawler", }, }, SummaryWarnings = new List { new SummaryWarning("c1", "a warning"), }, }); }); } private async Task InsertDataByQuerySummary(long? userId = null) { await UsingDbContextAsync(async c => { await _querySummaryRepository.InsertAsync(new QuerySummary { QueryHistory = new QueryHistory { UserId = userId ?? GetHostAdmin().Id, MainUsername = "a_user", QueryWorkerHistories = new List() { new QueryWorkerHistory { Solved = 3, Submission = 10, Username = "u1", CrawlerName = "crawler", }, }, }, Solved = 0, Submission = 0, QueryCrawlerSummaries = new List { new QueryCrawlerSummary { Solved = 0, Submission = 0, Usernames = new List { new UsernameInCrawler { Username = "a_user", FromCrawlerName = "", }, }, CrawlerName = "crawler", }, }, SummaryWarnings = new List { new SummaryWarning("c1", "a warning"), }, }); }); } [Theory] [InlineData("insert QueryHistory first")] [InlineData("insert QuerySummary directly")] public async Task AfterInsertion_ShouldSetForeignKey(string strategy) { // act if (strategy.Contains("QueryHistory")) { await InsertDataByQueryHistory(); } else { await InsertDataByQuerySummary(); } // test UsingDbContext(c => { c.QueryHistories.Should().HaveCount(1); c.QueryWorkerHistories.Should().HaveCount(1); c.QuerySummaries.Should().HaveCount(1); c.UsernameInCrawler.Should().HaveCount(1); var queryHistory = c.QueryHistories.Single(); var querySummary = c.QuerySummaries.Single(); var queryCrawlerSummary = c.QueryCrawlerSummaries.Single(); var queryWorkerHistory = c.QueryWorkerHistories.Single(); querySummary.QueryHistoryId.Should().Be(queryHistory.Id); queryCrawlerSummary.QuerySummaryId.Should().Be(querySummary.Id); queryWorkerHistory.QueryHistoryId.Should().Be(queryHistory.Id); queryWorkerHistory.SolvedList.Should().BeNull(); queryWorkerHistory.SubmissionsByCrawlerName.Should().BeNull(); }); } [Fact] public async Task WhenDeleteQuerySummary_ShouldNotDeleteQueryHistory() { // arrange await InsertDataByQuerySummary(); // act UsingDbContext(c => { var summary = c.QuerySummaries.Single(); c.QuerySummaries.Remove(summary); }); // assert UsingDbContext(c => { c.QueryWorkerHistories.Should().HaveCount(1); c.QueryHistories.Should().HaveCount(1); c.QuerySummaries.Should().HaveCount(0); c.UsernameInCrawler.Should().HaveCount(0); }); } [Fact] public async Task WhenDeleteQueryHistory_ShouldDeleteQuerySummary() { // arrange await InsertDataByQuerySummary(); // act UsingDbContext(c => { var history = c.QueryHistories.Single(); c.QueryHistories.Remove(history); }); // assert UsingDbContext(c => { c.QueryWorkerHistories.Should().HaveCount(0); c.QueryHistories.Should().HaveCount(0); c.QuerySummaries.Should().HaveCount(0); c.UsernameInCrawler.Should().HaveCount(0); }); } [Fact] public async Task WhenDeletingUser_ShouldDeleteHistoriesAndSummaries() { // arrange var user = await UsingDbContextAsync(async c => await _userRegistrationManager.RegisterAsync( "user1", "123qwe")); await InsertDataByQuerySummary(user.Id); LoginAsDefaultTenant("user1"); // act await UsingDbContextAsync(async c => { await _userManager.DeleteAsync(user); }); // assert UsingDbContext(c => { c.QueryWorkerHistories.Should().HaveCount(0); c.QueryHistories.Should().HaveCount(0); c.QuerySummaries.Should().HaveCount(0); c.UsernameInCrawler.Should().HaveCount(0); }); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Crawlers/SummaryGenerator_Tests.cs ================================================ using System; using System.Collections.Generic; using Abp.UI; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.ServiceClients; using FluentAssertions; using Xunit; namespace AcmStatisticsBackend.Tests.Crawlers { public class SummaryGenerator_Tests { private readonly CrawlerMetaItem[] _crawlerMeta; private readonly SummaryGenerator _summaryGenerator; public SummaryGenerator_Tests() { var testClockProvider = new TestClockProvider(); testClockProvider.Now = new DateTime(2020, 4, 1); _summaryGenerator = new SummaryGenerator(testClockProvider); _crawlerMeta = new[] { new CrawlerMetaItem { CrawlerName = "cr1", CrawlerTitle = "Cr1", Url = "", CrawlerDescription = "", IsVirtualJudge = false, }, new CrawlerMetaItem { CrawlerName = "cr2", CrawlerTitle = "Cr2", Url = "", CrawlerDescription = "", IsVirtualJudge = false, }, new CrawlerMetaItem { CrawlerName = "cr3", CrawlerTitle = "Cr3", Url = "", CrawlerDescription = "", IsVirtualJudge = true, }, new CrawlerMetaItem { CrawlerName = "cr4", CrawlerTitle = "Cr4", Url = "", CrawlerDescription = "", IsVirtualJudge = true, }, }; } [Fact] public void It_ShouldHaveGenerateTime() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.GenerateTime.Should().Be(new DateTime(2020, 4, 1)); } [Fact] public void WithoutSolvedList_ShouldGenerateWarning() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", }, new QueryWorkerHistory { CrawlerName = "cr2", Solved = 2, Submission = 5, Username = "u2", }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(3); result.Submission.Should().Be(8); result.SummaryWarnings.Should().BeEquivalentTo(new List { new SummaryWarning("cr1", "This crawler does not have a solved list and " + "its result will be directly added to summary."), new SummaryWarning("cr2", "This crawler does not have a solved list and " + "its result will be directly added to summary."), }); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 3, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 2, Submission = 5, Usernames = new List { new UsernameInCrawler { Username = "u2", }, }, }, }); } [Fact] public void VirtualJudgeWithoutSolvedList_ShouldThrow() { var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", Solved = 3, Submission = 10, IsVirtualJudge = true, }, }; FluentActions.Invoking(() => _summaryGenerator.Generate(_crawlerMeta, histories)) .Should().Throw() .WithMessage("Virtual judge Cr3 should have a solved list."); } [Theory] [InlineData("cr3", false, "According to crawler meta, the type of crawler Cr3 should be a virtual judge.")] [InlineData("cr1", true, "According to crawler meta, the type of crawler Cr1 should not be a virtual judge.")] public void WhenWorkerNotMatchCrawlerMeta_ShouldThrow( string crawlerName, bool isVirtualJudge, string exceptionMessage) { var histories = new[] { new QueryWorkerHistory { CrawlerName = crawlerName, Solved = 1, Submission = 10, IsVirtualJudge = isVirtualJudge, SolvedList = new[] { "moj-1001", }, }, }; FluentActions.Invoking(() => _summaryGenerator.Generate(_crawlerMeta, histories)) .Should().Throw() .WithMessage(exceptionMessage); } [Fact] public void WhenWorkerDoesNotExistInMeta_ShouldThrow() { var histories = new[] { new QueryWorkerHistory { Submission = 1, Solved = 1, Username = "u5", CrawlerName = "cr5", IsVirtualJudge = false, }, }; FluentActions.Invoking(() => _summaryGenerator.Generate(_crawlerMeta, histories)) .Should().Throw() .WithMessage("The meta data of crawler cr5 does not exist."); } [Fact] public void LocalJudgeWithSolvedList_ShouldWork() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", SolvedList = new[] { "1001", }, }, new QueryWorkerHistory { CrawlerName = "cr2", Solved = 2, Submission = 5, Username = "u2", SolvedList = new[] { "1001", "1002", }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(3); result.Submission.Should().Be(8); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 3, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 2, Submission = 5, Usernames = new List { new UsernameInCrawler { Username = "u2", }, }, }, }); } [Theory] [InlineData( new[] { "1001", }, new[] { "1001", "1002", }, 2)] [InlineData( new[] { "1001", "1005", }, new[] { "1001", "1002", }, 3)] [InlineData( new[] { "1003", "1005", }, new[] { "1001", "1002", }, 4)] [InlineData( new[] { "1001", "1002", }, new[] { "1001", "1002", }, 2)] public void DifferentWorkerOfTheSameCrawler_ShouldMergeTheirSolvedList(string[] set1, string[] set2, int solved) { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = set1.Length, Submission = 20, Username = "u1", SolvedList = set1, }, new QueryWorkerHistory { CrawlerName = "cr1", Solved = set2.Length, Submission = 30, Username = "u2", SolvedList = set2, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(solved); result.Submission.Should().Be(50); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = solved, Submission = 50, Usernames = new List { new UsernameInCrawler { Username = "u1", }, new UsernameInCrawler { Username = "u2", }, }, }, }); } [Fact] public void DifferentWorkerOfTheSameCrawler_WhenOnlySomeWorkerDoNotHaveSolvedList_ShouldThrow() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", SolvedList = new[] { "1001", }, }, new QueryWorkerHistory { CrawlerName = "cr1", Solved = 2, Submission = 5, Username = "u2", SolvedList = new[] { "1001", "1002", }, }, new QueryWorkerHistory { CrawlerName = "cr1", Solved = 10, Submission = 10, Username = "u3", }, }; // act var call = FluentActions.Invoking(() => _summaryGenerator.Generate( _crawlerMeta, histories)); // assert call.Should().Throw() .WithMessage("All workers of crawler Cr1 must have solved list!"); } [Fact] public void WorkerCrawlerExistsInVirtualJudge_WhenBothHaveSolvedList_ShouldMergeResult() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", SolvedList = new[] { "1001", }, }, new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 3, Submission = 15, Username = "u2", SolvedList = new[] { "cr1-1001", "cr1-1002", "cr2-2001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "cr2", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(3); result.Submission.Should().Be(18); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 2, Submission = 8, Usernames = new List { new UsernameInCrawler { Username = "u1", }, new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u2", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u2", }, }, }, }); } [Fact] public void WorkerCrawlerExistsInVirtualJudge_WhenCrawlerNotHaveSolvedList_ShouldGenerateWarning_AndAddResult() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", }, new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 3, Submission = 15, Username = "u2", SolvedList = new[] { "cr1-1001", "cr1-1002", "cr2-2001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "cr2", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(4); result.Submission.Should().Be(18); result.SummaryWarnings.Should().BeEquivalentTo(new List { new SummaryWarning("cr1", "This crawler does not have a solved list and " + "its result will be directly added to summary."), }); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 3, Submission = 8, Usernames = new List { new UsernameInCrawler { Username = "u1", }, new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u2", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u2", }, }, }, }); } [Fact] public void WhenSolvedNotMatchSolvedList_ShouldUseResultOfSolvedList() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 2, Submission = 3, Username = "u1", SolvedList = new[] { "1001", }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(3); // result.SummaryWarnings.Should().BeEquivalentTo(new List // { // new SummaryWarning("cr1", // "The solved number of this crawler is 2, however, there are 1" + // " problems in the solved list, which can be an error of the crawler."), // }); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 3, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenSolvedNotMatchSolvedList_ShouldUseResultOfSolvedList() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 2, Submission = 5, Username = "u1", SolvedList = new[] { "cr1-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 1 }, { "cr2", 4 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(5); // result.SummaryWarnings.Should().BeEquivalentTo(new List // { // new SummaryWarning("cr3", // "The solved number of this crawler is 2, however, there are 1" + // " problems in the solved list. Only "), // }); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 1, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 0, Submission = 4, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenAllSolvedListsMerged_ShouldNotExistInSummary() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 15, Username = "u1", SolvedList = new[] { "cr1-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "cr2", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(15); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 5, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr2", IsVirtualJudge = false, Solved = 0, Submission = 10, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenSomeSolvedListsNotMerged_ShouldExistInSummary() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 15, Username = "u1", SolvedList = new[] { "NN-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "NN", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(15); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 0, Submission = 5, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenSubmissionByCrawlerIsNotInCrawlerMeta_ShouldAddToVirtualJudge() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 10, Username = "u1", SolvedList = new[] { "NN-1001", }, SubmissionsByCrawlerName = new Dictionary { { "NN", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(10); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenSubmissionNotMatchSubmissionByCrawler_ShouldGenerateWarning_AndUseSubmissionByCrawler() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 0, Submission = 1, Username = "u1", SolvedList = new string[] { }, SubmissionsByCrawlerName = new Dictionary { { "NN", 10 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(0); result.Submission.Should().Be(10); result.SummaryWarnings.Should().BeEquivalentTo(new List { new SummaryWarning("cr3", "submissionByCrawler field of this crawler does not match its submission field, " + "and only results in submissionByCrawler are used."), }); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 0, Submission = 10, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenItHasLocalJudge_ShouldWorkAsLocalJudge() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 20, Username = "u1", SolvedList = new[] { "cr3-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr3", 20 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(1); result.Submission.Should().Be(20); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = false, Solved = 1, Submission = 20, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenItHasLocalJudge_AndProvidedByAnotherVj_ShouldWorkAsLocalJudge() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 20, Username = "u1", SolvedList = new[] { "cr3-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr3", 20 }, }, }, new QueryWorkerHistory { CrawlerName = "cr4", IsVirtualJudge = true, Solved = 2, Submission = 20, Username = "u2", SolvedList = new[] { "cr3-1001", "cr3-1002", }, SubmissionsByCrawlerName = new Dictionary { { "cr3", 20 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(2); result.Submission.Should().Be(40); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = false, Solved = 2, Submission = 40, Usernames = new List { new UsernameInCrawler { Username = "u1", }, new UsernameInCrawler { Username = "u2", FromCrawlerName = "cr4", }, }, }, }); } [Fact] public void VirtualJudge_WhenItHasLocalJudge_AndListNotMerged_ShouldOutputTwoSummary() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 35, Username = "u1", SolvedList = new[] { "NN-1001", "cr1-1001", "cr3-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "NN", 10 }, { "cr3", 20 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(3); result.Submission.Should().Be(35); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 5, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, // cr3 should has 2 crawler summary // as local judge and virtual judge, separately new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = false, Solved = 1, Submission = 20, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } [Fact] public void VirtualJudge_WhenItHasLocalJudge_CanOutputTwoDifferentUsernames() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 35, Username = "u1", SolvedList = new[] { "NN-1001", "cr1-1001", "cr3-1001", }, SubmissionsByCrawlerName = new Dictionary { { "cr1", 5 }, { "NN", 10 }, { "cr3", 20 }, }, }, new QueryWorkerHistory { CrawlerName = "cr4", IsVirtualJudge = true, Solved = 2, Submission = 20, Username = "u2", SolvedList = new[] { "cr3-1001", "cr3-1002", }, SubmissionsByCrawlerName = new Dictionary { { "cr3", 20 }, }, }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert result.Solved.Should().Be(4); result.Submission.Should().Be(55); result.SummaryWarnings.Should().HaveCount(0); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 5, Usernames = new List { new UsernameInCrawler { FromCrawlerName = "cr3", Username = "u1", }, }, }, // cr3 should has 2 crawler summary // as local judge and virtual judge, separately new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = true, Solved = 1, Submission = 10, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, new QueryCrawlerSummary { CrawlerName = "cr3", IsVirtualJudge = false, Solved = 2, Submission = 40, Usernames = new List { new UsernameInCrawler { Username = "u1", }, new UsernameInCrawler { Username = "u2", FromCrawlerName = "cr4", }, }, }, }); } [Fact] public void WhenInputErrorWorker_ShouldIgnore() { // arrange var histories = new[] { new QueryWorkerHistory { CrawlerName = "cr1", Solved = 1, Submission = 3, Username = "u1", SolvedList = new[] { "1001", }, }, new QueryWorkerHistory { CrawlerName = "cr3", IsVirtualJudge = true, Username = "u2", ErrorMessage = "An error occured", }, }; // act var result = _summaryGenerator.Generate( _crawlerMeta, histories); // assert // assert result.Solved.Should().Be(1); result.Submission.Should().Be(3); result.SummaryWarnings.Should().BeEmpty(); result.QueryCrawlerSummaries.Should().BeEquivalentTo(new List { new QueryCrawlerSummary { CrawlerName = "cr1", IsVirtualJudge = false, Solved = 1, Submission = 3, Usernames = new List { new UsernameInCrawler { Username = "u1", }, }, }, }); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/DependencyInjection/ServiceCollectionRegistrar.cs ================================================ using System; using Abp.Dependency; using AcmStatisticsBackend.EntityFrameworkCore; using AcmStatisticsBackend.Identity; using Castle.MicroKernel.Registration; using Castle.Windsor.MsDependencyInjection; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace AcmStatisticsBackend.Tests.DependencyInjection { public class ServiceCollectionRegistrar : IDisposable { private SqliteConnection _connection; public void Register(IIocManager iocManager) { var services = new ServiceCollection(); IdentityRegistrar.Register(services); services.AddEntityFrameworkSqlite(); var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(iocManager.IocContainer, services); // In-memory database only exists while the connection is open _connection = new SqliteConnection("DataSource=:memory:"); _connection.Open(); var builder = new DbContextOptionsBuilder(); builder.UseSqlite(_connection).UseInternalServiceProvider(serviceProvider); iocManager.IocContainer.Register( Component .For>() .Instance(builder.Options) .LifestyleSingleton()); } public void Dispose() { _connection?.Dispose(); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/DependencyInjection/TestClockProvider.cs ================================================ using System; using Abp.Timing; namespace AcmStatisticsBackend.Tests { /// /// Used to mock time. When setting Now, its Kind will be set to UTC. /// public class TestClockProvider : IClockProvider { private DateTime _now; public DateTime Normalize(DateTime dateTime) { return ClockProviders.Utc.Normalize(dateTime); } public DateTime Now { get => _now; set => _now = DateTime.SpecifyKind(value, DateTimeKind.Utc); } public DateTimeKind Kind => DateTimeKind.Utc; public bool SupportsMultipleTimezone => true; } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/DependencyInjection/TestCrawlerApiBackendClient.cs ================================================ using System.Collections.Generic; using System.Threading.Tasks; using AcmStatisticsBackend.ServiceClients; namespace AcmStatisticsBackend.Tests.DependencyInjection { public class TestCrawlerApiBackendClient : ICrawlerApiBackendClient { public List CrawlerMeta { get; set; } #pragma warning disable 1998 public async Task> GetCrawlerMeta() { return CrawlerMeta.AsReadOnly(); } #pragma warning restore 1998 } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/MultiTenantFactAttribute.cs ================================================ using Xunit; namespace AcmStatisticsBackend.Tests { public sealed class MultiTenantFactAttribute : FactAttribute { public MultiTenantFactAttribute() { if (!AcmStatisticsBackendConsts.MultiTenancyEnabled) { Skip = "MultiTenancy is disabled."; } } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AcmStatisticsBackend.Tests")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("0d4c5d00-c144-4213-a007-4b8944113ab1")] ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/ServiceClients/CaptchaServiceClient_Tests.cs ================================================ using System.Net.Http; using System.Threading.Tasks; using AcmStatisticsBackend.ServiceClients; using FluentAssertions; using Flurl.Http.Testing; using Xunit; namespace AcmStatisticsBackend.Tests.ServiceClients { public class CaptchaServiceClient_Tests { private readonly ICaptchaServiceClient _captchaServiceClient; public CaptchaServiceClient_Tests() { _captchaServiceClient = new CaptchaServiceClient(); } [Fact] public async Task WhenHttpResponseWithoutError_ShouldWorkCorrectly() { // arrange using var httpTest = new HttpTest(); httpTest.RespondWithJson(new { error = false, }); // act var result = await _captchaServiceClient.ValidateAsync("id", "text"); // assert httpTest.ShouldHaveCalled("http://captcha-service/api/captcha-service/validate") .WithVerb(HttpMethod.Post) .WithRequestUrlEncoded(new { id = "id", text = "text", }) .Times(1); result.Correct.Should().BeTrue(); result.ErrorMessage.Should().BeEmpty(); } [Fact] public async Task WhenHttpResponseError_ShouldReportError() { // arrange using var httpTest = new HttpTest(); httpTest.RespondWithJson(new { error = true, message = "err message", }, 400); // act var result = await _captchaServiceClient.ValidateAsync("id", "text"); // assert httpTest.ShouldHaveCalled("http://captcha-service/api/captcha-service/validate") .WithVerb(HttpMethod.Post) .WithRequestUrlEncoded(new { id = "id", text = "text", }) .Times(1); result.Correct.Should().BeFalse(); result.ErrorMessage.Should().Be("err message"); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/ServiceClients/CrawlerApiBackendClient_Tests.cs ================================================ using System.Net.Http; using System.Threading.Tasks; using AcmStatisticsBackend.Crawlers; using AcmStatisticsBackend.ServiceClients; using FluentAssertions; using Flurl.Http.Testing; using Xunit; namespace AcmStatisticsBackend.Tests.ServiceClients { public class CrawlerApiBackendClient_Tests { private readonly ICrawlerApiBackendClient _crawlerApiBackendClient; public CrawlerApiBackendClient_Tests() { _crawlerApiBackendClient = new CrawlerApiBackendClient(); } [Fact] public async Task GetCrawlerMeta_ShouldWorkCorrectly() { // arrange using var httpTest = new HttpTest(); httpTest.RespondWithJson(new { error = false, data = new { uva = new { title = "UVA", description = "u description", url = "http", }, vjudge = new { title = "VJudge", description = "v description", url = "https", virtual_judge = true, }, }, }); // act var result = await _crawlerApiBackendClient.GetCrawlerMeta(); // assert httpTest.ShouldHaveCalled("http://crawler-api-backend/api/crawlers/") .WithVerb(HttpMethod.Get) .Times(1); result.Should().BeEquivalentTo(new[] { new CrawlerMetaItem { CrawlerName = "uva", CrawlerTitle = "UVA", CrawlerDescription = "u description", Url = "http", IsVirtualJudge = false, }, new CrawlerMetaItem { CrawlerName = "vjudge", CrawlerTitle = "VJudge", CrawlerDescription = "v description", Url = "https", IsVirtualJudge = true, }, }); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Sessions/SessionAppService_Tests.cs ================================================ using System.Threading.Tasks; using AcmStatisticsBackend.Sessions; using FluentAssertions; using Xunit; namespace AcmStatisticsBackend.Tests.Sessions { public class SessionAppService_Tests : AcmStatisticsBackendTestBase { private readonly ISessionAppService _sessionAppService; public SessionAppService_Tests() { _sessionAppService = Resolve(); } [Fact] public async Task Should_Get_Current_User_And_Tenant_When_Logged_In_As_Tenant() { // Act var output = await _sessionAppService.GetCurrentLoginInformations(); // Assert var currentUser = await GetCurrentUserAsync(); var currentTenant = await GetCurrentTenantAsync(); output.User.Should().NotBe(null); output.User.Name.Should().Be(currentUser.Name); output.Tenant.Should().NotBe(null); output.Tenant.Name.Should().Be(currentTenant.Name); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/Settings/UserConfigAppService_TimeZone_Tests.cs ================================================ using System; using System.Threading.Tasks; using Abp.Runtime.Validation; using Abp.UI; using AcmStatisticsBackend.Settings; using AcmStatisticsBackend.Settings.Dto; using FluentAssertions; using Xunit; namespace AcmStatisticsBackend.Tests.Settings { public class UserConfigAppService_TimeZone_Tests : AcmStatisticsBackendTestBase { private readonly IUserConfigAppService _userConfigAppService; private readonly TestClockProvider _clockProvider; public UserConfigAppService_TimeZone_Tests() { _clockProvider = new TestClockProvider(); _userConfigAppService = Resolve(new { clockProvider = _clockProvider, }); } [Fact] public async Task GetUserTimeZone_ShouldWork() { // arrange LoginAsHostAdmin(); await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { TimeZone = "US Eastern Standard Time", }); // act var result = await _userConfigAppService.GetUserSettings(); // assert result.Values["Abp.Timing.TimeZone"].Should().Be("US Eastern Standard Time"); } [Fact] public async Task GetUserTimeZone_WhenNoTimeZoneSet_ShouldReturnDefaultTimeZone() { // arrange LoginAsHostAdmin(); // act var result = await _userConfigAppService.GetUserSettings(); // assert result.Values["Abp.Timing.TimeZone"].Should().Be("UTC"); } [Fact] public async Task SetUserTimeZone_WhenTimeZoneIsInvalid_ShouldThrow() { LoginAsHostAdmin(); await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { TimeZone = "BlaBla", }).ShouldThrow(); } [Fact] public async Task SetUserTimeZone_ShouldWork() { // arrange LoginAsHostAdmin(); // act await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { TimeZone = "US Eastern Standard Time", }); // assert var result = await _userConfigAppService.GetUserSettings(); result.Values["Abp.Timing.TimeZone"].Should().Be("US Eastern Standard Time"); } [Fact] public async Task SetUserTimeZone_CannotBeSetTwiceWithIn24Hours() { _clockProvider.Now = new DateTime(2020, 4, 1, 0, 0, 0); await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { // GMT +01:00 TimeZone = "Central Europe Standard Time", }); // UTC: 23:00 April 1; Local: 00:00 April 2 _clockProvider.Now = _clockProvider.Now.AddHours(23); // should not set time zone await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { TimeZone = "Dateline Standard Time", }).ShouldThrow(); // UTC: 00:00 April 2; Local: 01:00 April 2 _clockProvider.Now = _clockProvider.Now.AddHours(1); // Can set time zone await _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { TimeZone = "Dateline Standard Time", }); var result = await _userConfigAppService.GetUserSettings(); result.Values["Abp.Timing.TimeZone"].Should().Be("Dateline Standard Time"); } [Fact] public async Task SetUserTimeZone_WhenInputWithNonWindowsIds_ShouldThrow() { // arrange LoginAsHostAdmin(); // act var task = _userConfigAppService.SetUserTimeZone(new UserTimeZoneDto { // Iana time zone id TimeZone = "America/Santiago", }); // assert await task.ShouldThrow(); } } } ================================================ FILE: backend/test/AcmStatisticsBackend.Tests/TestExtensions.cs ================================================ using System; using System.Threading.Tasks; using FluentAssertions; using FluentAssertions.Specialized; namespace AcmStatisticsBackend.Tests { public static class TestExtensions { public static Task> ShouldThrow( this Task task, string because = "") where T : Exception { Func call = async () => await task; return call.Should().ThrowAsync(because); } public static Task> ShouldThrow( this Task task, string because = "") where TException : Exception { Func> call = async () => await task; return call.Should().ThrowAsync(because); } } } ================================================ FILE: build/.dockerignore ================================================ * ================================================ FILE: build/.gitignore ================================================ /.env /obj /bin /backend-db *.user /App_Data /db-backup ================================================ FILE: build/commitlint.Dockerfile ================================================ ARG NODE_BASE_IMAGE FROM ${NODE_BASE_IMAGE} RUN apk add --no-cache git RUN git config --global user.email "test@test.com" RUN git config --global user.name "Test Name" RUN pnpm install -g \ @commitlint/cli \ @commitlint/config-conventional WORKDIR /var/project ================================================ FILE: build/commitlint.mk ================================================ ## makefile for commitlint include share.mk # === consts === CommitlintImageTag = $(CommonTagPrefix)-commitlint-image # 用来执行 commitlint 的地址,可以被覆盖 CommitlintValidPath = $(CURDIR)/.. # === targets === .PHONY: test-commit commitlint-travis .node-base: $(MAKE) -f node-base.mk build build: .node-base docker build . \ -t $(CommitlintImageTag) \ -f commitlint.Dockerfile \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) clean: docker image rm $(CommitlintImageTag); true test-commit: build docker run --rm \ -v "$(CommitlintValidPath):/var/project" \ $(CommitlintImageTag) \ commitlint --from master --color ================================================ FILE: build/docker-compose.dcproj ================================================ 2.1 Linux 5ae26e44-7afe-4443-aa6e-f3fdf9519bfd None {Scheme}://localhost:{ServicePort} backend docker-compose.dev-backend.yml docker-compose.yml ================================================ FILE: build/docker-compose.dev-backend.yml ================================================ # For backend debugging version: '3.4' services: backend: image: ${DOCKER_REGISTRY-}acm-statistics-backend build: context: ../backend dockerfile: src/AcmStatisticsBackend.Web.Host/Dockerfile environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "80" volumes: - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro db: ports: - "3306:3306" adminer: ports: - "8080:8080" watchtower: # skip watchtower in development image: tianon/true:latest command: '' ohunt: environment: DisableCrawlerWorker: all ================================================ FILE: build/docker-compose.dev-frontend.yml ================================================ version: '3.4' services: # for frontend hot reload frontend: image: acm-statistics-frontend-base volumes: - ../frontend/assets:/var/project/assets - ../frontend/components:/var/project/components - ../frontend/layouts:/var/project/layouts - ../frontend/middleware:/var/project/middleware - ../frontend/modules:/var/project/modules - ../frontend/pages:/var/project/pages - ../frontend/plugins:/var/project/plugins - ../frontend/static:/var/project/static - ../frontend/store:/var/project/store environment: - NODE_ENV=development command: sh -c "npm run dev" crawler-api-backend: environment: # show detail logs including response - NODE_ENV=development watchtower: # skip watchtower in development image: tianon/true:latest command: '' ohunt: environment: DisableCrawlerWorker: all ================================================ FILE: build/docker-compose.e2e.yml ================================================ # fixture of build/docker-compose.yml version: "3.4" services: frontend: environment: - http_proxy=http://mock-proxy:1080 crawler-api-backend: environment: - http_proxy=http://mock-proxy:1080 captcha-service: environment: - E2E=1 watchtower: # skip watchtower in development image: tianon/true:latest command: "" mock-proxy: image: jamesdbloom/mockserver:mockserver-5.5.1 ports: # use this port to connect to mockserver on host - "1081:1080" mock-configurer: image: acm-statistics-e2e-mock-configurer volumes: # organize them into a separate folder to prevent mounting node_modules - ../e2e/http-mocks/src:/mocks/src labels: - traefik.http.routers.mock-configurer.rule=PathPrefix(`/mock-configurer`) - traefik.http.services.mock-configurer.loadbalancer.server.port=80 ohunt: environment: DisableCrawlerWorker: all ================================================ FILE: build/docker-compose.mk ================================================ ## makefile for docker-compose include share.mk # === variables === # the docker repo name (username) to publish image RepoName = liu233w/ # use git commit hash as image tag CommitHash := $(shell git log -1 --pretty=%H) # the image to publish Images = FrontendTag CrawlerApiBackendTag BackendTag CaptchaServiceTag OHuntTag # === inner === ImageToTag := $(foreach n,$(Images),$(n)-tag) ImageToPush := $(foreach n,$(Images),$(n)-push) # variables for each images $(ImageToTag): Image = $($(subst -tag,,$@)) $(ImageToPush): Image = $($(subst -push,,$@)) $(ImageToTag) $(ImageToPush): ImageNameWithHash = $(RepoName)$(Image):$(CommitHash) $(ImageToTag) $(ImageToPush): ImageNameWithLatest = $(RepoName)$(Image):latest # === targets === .PHONY: .build tag push up dev-frontend .build-dev e2e-up .build: $(MAKE) -C ../crawler-api-backend build $(MAKE) -C ../frontend build $(MAKE) -C ../backend build $(MAKE) -C ../captcha-service build $(MAKE) -C ../ohunt build $(RM) backend-db/mysql.sock tag: .build $(ImageToTag) push: tag $(ImageToPush) $(ImageToTag): @echo try to tag $(ImageNameWithHash) and $(ImageNameWithLatest) docker tag $(Image) $(ImageNameWithHash) docker tag $(Image) $(ImageNameWithLatest) $(ImageToPush): @echo try to push $(ImageNameWithHash) and $(ImageNameWithLatest) docker push $(ImageNameWithHash) docker push $(ImageNameWithLatest) up: .build .env docker compose up $(compose-args) # additionally run mock-server when start the server for e2e test # Remove the old database e2e-up: .build .env $(MAKE) -C ../e2e build-http-mocks $(RMR) backend-db || echo remove failed $(MKDIR) backend-db docker compose -f docker-compose.yml -f docker-compose.e2e.yml up $(compose-args) .env: $(CP) template.env .env dev-frontend: .build docker compose -f docker-compose.yml -f docker-compose.dev-frontend.yml up $(compose-args) ================================================ FILE: build/docker-compose.yml ================================================ version: '3.4' services: reverse-proxy: image: traefik:v2.10.1 command: - "--api.insecure=true" - "--providers.docker=true" - "--entrypoints.web.address=:80" - "--accesslog=true" # An outside reverse proxy is used, so we can just trust all forward headers - "--entryPoints.web.forwardedHeaders.insecure" ports: - "${EXPOSE_PORT}:80" - "${TRAEFIK_PORT}:8080" # The Web UI (enabled by --api) volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - frontend - backend - captcha-service - crawler-api-backend frontend: image: ${DOCKER_REPO}acm-statistics-frontend${DOCKER_TAG} environment: - HOST=0.0.0.0 labels: - traefik.http.routers.frontend.rule=PathPrefix(`/`) - traefik.http.services.frontend.loadbalancer.server.port=3000 crawler-api-backend: image: ${DOCKER_REPO}acm-statistics-crawler-api-backend${DOCKER_TAG} environment: - ACM_STATISTICS_CRAWLER_ENV__crawlers__vjudge__crawler_login_user="${VJUDGE_USERNAME}" - ACM_STATISTICS_CRAWLER_ENV__crawlers__vjudge__crawler_login_password="${VJUDGE_PASSWORD}" labels: - traefik.http.routers.crawler-api-backend.rule=PathPrefix(`/api/crawlers`) - traefik.http.services.crawler-api-backend.loadbalancer.server.port=80 watchtower: image: containrrr/watchtower volumes: - /var/run/docker.sock:/var/run/docker.sock command: -s "0 */30 * * * *" --cleanup labels: - traefik.enable=false backend: image: ${DOCKER_REPO}acm-statistics-backend${DOCKER_TAG} environment: ConnectionStrings__Default: Server=db; port=3306; Database=acm_statistics; uid=root; pwd=${MYSQL_ROOT_PASSWORD}; Convert Zero Datetime=True BACKEND_ADMIN_DEFAULT_PASSWORD: ${BACKEND_ADMIN_DEFAULT_PASSWORD} Authentication__JwtBearer__SecurityKey: ${BACKEND_JWT_PRIVATE_KEY} WAIT_COMMAND: wait-for-it db:3306 -t 0 ASPNETCORE_FORWARDEDHEADERS_ENABLED: 'true' labels: - traefik.http.routers.backend.rule=PathPrefix(`/api`)||PathPrefix(`/AntiForgery`) - traefik.http.routers.backend.priority=18 - traefik.http.services.backend.loadbalancer.server.port=80 volumes: - ./App_Data:/app/App_Data depends_on: - db - captcha-service db: image: mysql:8-oracle restart: always environment: MYSQL_DATABASE: acm_statistics # Password for root access MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # Where our data will be persisted volumes: - ./backend-db:/var/lib/mysql # fix `mbind: Operation not permitted`, see https://stackoverflow.com/a/55706057 cap_add: - SYS_NICE # CAP_SYS_NICE labels: - traefik.enable=false captcha-service: image: ${DOCKER_REPO}acm-statistics-captcha-service${DOCKER_TAG} labels: # Only getting captcha part needs public access. - traefik.http.routers.captcha-service.rule=Path(`/api/captcha-service/generate`) - traefik.http.services.captcha-service.loadbalancer.server.port=80 db-backup: image: databack/mysql-backup command: dump restart: always user: "${DB_BACKUP_UID}" volumes: - ./db-backup:/db environment: DB_DUMP_TARGET: /db DB_USER: root DB_PASS: ${MYSQL_ROOT_PASSWORD} # DB_DUMP_BEGIN: +2 # backup at 3:00 am DB_DUMP_BEGIN: "0300" DB_SERVER: db DB_DUMP_INCLUDE: acm_statistics depends_on: - db labels: - traefik.enable=false ohunt: image: ${DOCKER_REPO}acm-statistics-ohunt${DOCKER_TAG} environment: ConnectionStrings__Default: Server=db; port=3306; Database=ohunt; uid=root; pwd=${MYSQL_ROOT_PASSWORD}; Convert Zero Datetime=True WAIT_COMMAND: wait-for-it db:3306 -t 0 restart: always labels: - traefik.http.routers.ohunt.rule=PathPrefix(`/api/ohunt`)||PathPrefix(`/ohunt`) - traefik.http.services.ohunt.loadbalancer.server.port=80 depends_on: - db ================================================ FILE: build/node-base.Dockerfile ================================================ FROM node:22.22.0-alpine # dependency to run codecov on CI ARG CODECOV=false RUN if [ "$CODECOV" != "false" ]; then \ apk add --no-cache \ bash \ curl \ ; fi RUN npm install --global pnpm@9 ================================================ FILE: build/node-base.mk ================================================ ## makefile for node base image include share.mk NodeBaseOption = ifdef CODECOV NodeBaseOption := --build-arg CODECOV=$(CODECOV) $(NodeBaseOption) endif build: docker build . -f node-base.Dockerfile -t $(NodeBaseTag) $(NodeBaseOption) clean: docker image rm $(NodeBaseTag); true ================================================ FILE: build/share.mk ================================================ # == consts == CommonTagPrefix = acm-statistics NodeBaseTag = $(CommonTagPrefix)-node-base CrawlerTag = $(CommonTagPrefix)-crawler CrawlerBaseTag = $(CommonTagPrefix)-crawler-base FrontendBaseTag = $(CommonTagPrefix)-frontend-base FrontendTag = $(CommonTagPrefix)-frontend CrawlerApiBackendTag = $(CommonTagPrefix)-crawler-api-backend CrawlerApiBackendBaseTag = $(CommonTagPrefix)-crawler-api-backend-base E2eMockConfigurerTag = $(CommonTagPrefix)-e2e-mock-configurer E2eBaseTag = $(CommonTagPrefix)-e2e-base BackendTag = $(CommonTagPrefix)-backend BackendBaseTag = $(CommonTagPrefix)-backend-base CaptchaServiceTag = $(CommonTagPrefix)-captcha-service CaptchaServiceBaseTag = $(CommonTagPrefix)-captcha-service-base OHuntTag = $(CommonTagPrefix)-ohunt OHuntBaseTag = $(CommonTagPrefix)-ohunt-base # == phony .PHONY: test build run clean test-ci help # == set variables == # enable correct path on msys2 in windows export MSYS2_ARG_CONV_EXCL = * # == resolve run-args == ifeq ($(filter r no-rm,$(make-args)),) override run-args := $(run-args) --rm endif ifeq ($(filter i no-interactive,$(make-args)),) override run-args := $(run-args) --interactive endif ifeq ($(filter t no-tty,$(make-args)),) override run-args := $(run-args) --tty endif RM = docker run --rm -v $(shell pwd):/app -w /app alpine rm -f RMR = docker run --rm -v $(shell pwd):/app -w /app alpine rm -rf # == detect system and set command == ifeq ($(findstring cmd.exe,$(SHELL)),cmd.exe) # cmd shell CP = copy MKDIR = md else # Linux or cygwin/msys CP = cp MKDIR = mkdir endif # === consts == # the version number is shown in about page ifndef VERSION_NUM VERSION_NUM := $(shell git log -1 --pretty=%H) endif # a timestamp shown in about page and page footer ifndef BUILD_TIME ifdef OS # windows BUILD_TIME := $(shell powershell -command "[int32](New-TimeSpan -Start (Get-Date "01/01/1970") -End ((Get-Date).ToUniversalTime())).TotalSeconds") else BUILD_TIME := $(shell date +%s) endif endif ================================================ FILE: build/shell.Dockerfile ================================================ ARG NODE_BASE_IMAGE FROM ${NODE_BASE_IMAGE} RUN apk add --no-cache \ git \ curl \ bash \ ; WORKDIR /var/project CMD ["bash"] ================================================ FILE: build/shell.mk ================================================ ## 用于开发用的 shell 的 makefile include share.mk # === consts === ShellTag = $(CommonTagPrefix)-shell # 对应的本机上的地址,可以被覆盖 ProjectPath = $(CURDIR)/.. # === targets === .PHONY: .node-base build shell shell: build docker run --rm -it -v "$(ProjectPath):/var/project" $(ShellTag) build: .node-base docker build . \ -t $(ShellTag) \ -f shell.Dockerfile \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) .node-base: $(MAKE) -f node-base.mk build clean: docker image rm $(ShellTag); true ================================================ FILE: build/template.env ================================================ # == configuration for docker compose == # port for the main application. It is better to use another load balancer for the endpoint. If you want to expose the port to public, remove the `127.0.0.1:` part and only keep the port number EXPOSE_PORT=127.0.0.1:3000 # port for traefik dashboard. not recommended to expose to public TRAEFIK_PORT=127.0.0.1:3001 # docker repo name and tag. no need to modify this DOCKER_REPO= DOCKER_TAG= # == config for services == # config for vjudge crawler, you can enter yours VJUDGE_USERNAME=vjudge username VJUDGE_PASSWORD=vjudge password # MySQL root password MYSQL_ROOT_PASSWORD=password # default password for backend admin BACKEND_ADMIN_DEFAULT_PASSWORD=123qwe # JWT private key for backend, please change it BACKEND_JWT_PRIVATE_KEY=AcmStatisticsBackend_C421AAEE0D114E9C # Database backup UID. if you connect to the server using root user, set it to 0. Or set it to your uid. DB_BACKUP_UID=0 ================================================ FILE: captcha-service/.dockerignore ================================================ # dependencies node_modules # logs npm-debug.log # codecov coverage # docker .dockerignore base.Dockerfile release.Dockerfile # make Makefile # 日志文件 /logs/ ================================================ FILE: captcha-service/.eslintrc.js ================================================ module.exports = { root: true, env: { browser: false, node: true, es6: true, 'jest/globals': true, }, parserOptions: { parser: 'babel-eslint', ecmaVersion: 8, }, extends: [ 'eslint:recommended', 'plugin:jest/recommended', ], // required to lint *.vue files plugins: [ 'jest', ], // add your custom rules here rules: { 'semi': [2, 'never'], 'no-console': 'off', 'vue/max-attributes-per-line': 'off', // 行末逗号:在多行中强制最后一项有逗号,单行中强制没有 'comma-dangle': ['error', 'always-multiline'], 'quotes': ['error', 'single'], // 服务端不用管这个 'lodash/import-scope': 'off', // 这个方法的可读性太低了 'lodash/matches-prop-shorthand': 'off', }, } ================================================ FILE: captcha-service/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # next.js build output .next # 日志文件 /logs/ ================================================ FILE: captcha-service/Makefile ================================================ ## makefile for captcha service include ../build/share.mk help: @echo run \"make help\" in root directory to get help .node-base: cd ../build && $(MAKE) -f node-base.mk build .base: .node-base docker build . \ -f base.Dockerfile \ -t $(CaptchaServiceBaseTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) build: .base docker build . \ -f release.Dockerfile \ -t $(CaptchaServiceTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) \ --build-arg SERVICE_BASE_IMAGE=$(CaptchaServiceBaseTag) test: .base docker run --rm -t $(CaptchaServiceBaseTag) pnpm test run: .base docker run $(run-args) $(CaptchaServiceBaseTag) $(run-cmd) clean: docker image rm $(CaptchaServiceBaseTag) $(CaptchaServiceTag); true test-ci: .base docker run --rm \ -v "$(CURDIR)/coverage:/var/project/coverage" \ $(CaptchaServiceBaseTag) \ pnpm test -- --colors ================================================ FILE: captcha-service/README.md ================================================ captcha-service === 验证码微服务。目前只有 `/api/captcha-service/generate` 对前端开放。验证部分只能从内部访问。 [测试文件](./__test__/app.spec.js)中有API的用例。 ## 本地运行 - 使用 `pnpm start` 运行 - 在运行之后会监视 `localhost:80` ## 部署 - 使用 docker ================================================ FILE: captcha-service/__mocks__/svg-captcha.js ================================================ module.exports = { create() { return { text: 'validate-text', data: '', } }, } ================================================ FILE: captcha-service/__test__/app.spec.js ================================================ /* eslint-disable jest/expect-expect */ jest.mock('svg-captcha') const request = require('supertest') const app = require('../src/app').callback() describe('/api/captcha-service/generate', () => { it('可以生成验证码', async () => { const res = await request(app).post('/api/captcha-service/generate') .expect(200) expect(res.body).toMatchObject({ error: false, data: { id: expect.any(String), captcha: '', }, }) }) }) describe('/api/captcha-service/validate', () => { it('能够进行验证', async () => { const id = (await request(app).post('/api/captcha-service/generate') .expect(200)).body.data.id await request(app).post('/api/captcha-service/validate') .send({ id, text: 'validate-text' }) .expect(200, { error: false, data: true, }) }) it('不论大小写', async () => { const id = (await request(app).post('/api/captcha-service/generate') .expect(200)).body.data.id await request(app).post('/api/captcha-service/validate') .send({ id, text: 'VALIDATE-text' }) .expect(200, { error: false, data: true, }) }) it('能够在验证码错误时报错', async () => { const id = (await request(app).post('/api/captcha-service/generate') .expect(200)).body.data.id await request(app).post('/api/captcha-service/validate') .send({ id, text: 'incorrect' }) .expect(400, { error: true, message: 'Incorrect captcha', }) }) it('不能重复验证', async () => { const id = (await request(app).post('/api/captcha-service/generate') .expect(200)).body.data.id await request(app).post('/api/captcha-service/validate') .send({ id, text: 'validate-text' }) await request(app).post('/api/captcha-service/validate') .send({ id, text: 'validate-text' }) .expect(400, { error: true, message: 'Please refresh captcha', }) }) }) ================================================ FILE: captcha-service/__test__/interface.test.js ================================================ const svgCaptcha = require('svg-captcha') describe('svg-captcha 接口测试', () => { it('能够正确返回数据', () => { const captcha = svgCaptcha.create({ size: 6, noise: 2, }) expect(captcha.data).toBeTruthy() expect(captcha.text).toBeTruthy() }) }) ================================================ FILE: captcha-service/base.Dockerfile ================================================ ARG NODE_BASE_IMAGE FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY package.json pnpm-lock.yaml ./ RUN pnpm install COPY . . ================================================ FILE: captcha-service/package.json ================================================ { "name": "captcha-service", "version": "1.0.0", "description": "验证码微服务", "main": "src/index.js", "scripts": { "start": "node src/index.js", "test": "jest", "lint": "eslint --ext .js --ignore-path .gitignore .", "lintfix": "eslint --fix --ext .js --ignore-path .gitignore ." }, "author": "Liu233w ", "license": "GPL-3.0", "dependencies": { "koa": "^2.7.0", "koa-bodyparser": "^4.3.0", "koa-router": "^12.0.0", "node-cache": "^5.1.0", "svg-captcha": "^1.4.0", "uuid": "^9.0.0" }, "devDependencies": { "eslint": "8.57.1", "eslint-plugin-jest": "27.9.0", "jest": "29.7.0", "supertest": "6.3.4", "typescript": "5.9.3" }, "jest": { "testEnvironment": "node", "coverageDirectory": "./coverage/", "collectCoverage": true } } ================================================ FILE: captcha-service/release.Dockerfile ================================================ ARG NODE_BASE_IMAGE ARG SERVICE_BASE_IMAGE FROM ${SERVICE_BASE_IMAGE} AS base RUN rm -rf node_modules FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY package.json pnpm-lock.yaml ./ RUN pnpm install --only=production COPY --from=base /var/project . ENV NODE_ENV production EXPOSE 80 CMD ["pnpm", "start"] ================================================ FILE: captcha-service/src/app.js ================================================ const koa = require('koa') const Router = require('koa-router') const bodyParser = require('koa-bodyparser') const NodeCache = require('node-cache') const { v4: uuid } = require('uuid') let svgCaptcha = require('svg-captcha') if (process.env.E2E) { // E2E 测试时把接口固定 // eslint-disable-next-line jest/no-mocks-import svgCaptcha = require('../__mocks__/svg-captcha') } const restHelper = require('./restHelper') const router = new Router() const cache = new NodeCache() const CAPTCHA_AVAILABLE_TIME = process.env.CAPTCHA_AVAILABLE_TIME ? process.env.CAPTCHA_AVAILABLE_TIME : 5 * 60 /* sec */ // 先把验证码存在项目中。如果遇到性能问题再上redis router.post('/api/captcha-service/generate', async ctx => { const id = uuid() const captcha = svgCaptcha.create({ size: 6, noise: 2, }) cache.set(id, captcha.text, CAPTCHA_AVAILABLE_TIME) ctx.rest({ id, captcha: captcha.data, }) }) router.post('/api/captcha-service/validate', async ctx => { const { id, text } = ctx.request.body const correct = cache.get(id) cache.del(id) if (!correct) { ctx.error('Please refresh captcha') return } if (correct.toLowerCase() !== text.toLowerCase()) { ctx.error('Incorrect captcha') return } ctx.rest(true) }) const app = new koa() .use(bodyParser()) .use(restHelper) .use(router.middleware()) .use(router.allowedMethods) // 将 req.ip 设置为 X-Forward-For 中的 ip app.proxy = true module.exports = app ================================================ FILE: captcha-service/src/index.js ================================================ const app = require('./app') console.log('captcha-service start listening on localhost:80 ...') app.listen(80) ================================================ FILE: captcha-service/src/restHelper.js ================================================ /** * 方便写 rest API 的中间件 */ module.exports = async function (ctx, next) { ctx.rest = function (data) { ctx.response.status = 200 ctx.response.type = 'application/json' ctx.response.body = { error: false, data: data, } } ctx.error = function (message) { ctx.response.status = 400 ctx.response.type = 'application/json' ctx.response.body = { error: true, message: message, } } await next() } ================================================ FILE: codecov.yml ================================================ ignore: - backend/src/AcmStatisticsBackend.EntityFrameworkCore/**/* - backend/src/AcmStatisticsBackend.Migrator/**/* - backend/src/AcmStatisticsBackend.Web.Core/**/* - backend/src/AcmStatisticsBackend.Web.Host/**/* - backend/src/**/Dto/**/* - ohunt/OHunt.Web/Migrations/* coverage: status: project: default: threshold: 5% ================================================ FILE: commitlint.config.js ================================================ module.exports = { extends: ['@commitlint/config-conventional'], rules: { "subject-case": [0], "scope-case": [0], "header-max-length": [1, "always", 72], "body-max-line-length": [0], }, } ================================================ FILE: crawler/.dockerignore ================================================ # dependencies node_modules # logs npm-debug.log # codecov coverage # docker .dockerignore base.Dockerfile release.Dockerfile # make Makefile # vscode .vscode .ionide ================================================ FILE: crawler/.eslintrc.js ================================================ module.exports = { root: true, env: { browser: true, node: true, es6: true, 'jest/globals': true, }, parserOptions: { parser: 'babel-eslint', ecmaVersion: 8, }, extends: [ 'eslint:recommended', // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 'plugin:lodash/recommended', 'plugin:jest/recommended', ], // required to lint *.vue files plugins: [ 'lodash', 'jest', ], // add your custom rules here rules: { 'semi': [2, 'never'], 'no-console': 'off', 'vue/max-attributes-per-line': 'off', // 行末逗号:在多行中强制最后一项有逗号,单行中强制没有 'comma-dangle': ['error', 'always-multiline'], 'quotes': ['error', 'single'], // 服务端不用管这个 'lodash/import-scope': 'off', // 这个方法的可读性太低了 'lodash/matches-prop-shorthand': 'off', }, } ================================================ FILE: crawler/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # next.js build output .next ================================================ FILE: crawler/.vscode/launch.json ================================================ { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "name": "vscode-jest-tests", "request": "launch", "args": [ "--runInBand" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "disableOptimisticBPs": true, "program": "${workspaceFolder}/node_modules/jest/bin/jest" } ] } ================================================ FILE: crawler/Makefile ================================================ ## makefile for crawler include ../build/share.mk help: @echo run \"make help\" in root directory to get help .node-base: cd ../build && $(MAKE) -f node-base.mk build .base: .node-base docker build . \ -f base.Dockerfile \ -t $(CrawlerBaseTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) build: .base docker build . \ -f release.Dockerfile \ -t $(CrawlerTag) \ $(build-args) \ --build-arg CRAWLER_BASE_IMAGE=$(CrawlerBaseTag) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) test: .base docker run --rm -t $(CrawlerBaseTag) pnpm test run: .base docker run $(run-args) $(CrawlerBaseTag) $(run-cmd) clean: docker image rm $(CrawlerTag) $(CrawlerBaseTag); true test-ci: .base docker run --rm \ -v "$(CURDIR)/coverage:/var/project/coverage" \ $(CrawlerBaseTag) \ pnpm test -- --colors "--testPathPattern=__test__/(?!crawlers\\.test).*\\.js" ================================================ FILE: crawler/README.md ================================================ 存放爬虫,可以同时被前端和后端使用。部分爬虫可以同时在服务器 端和浏览器端运行。 ## 爬虫编写要求 ### 爬虫源代码 - 存放在 [./crawlers/](./crawlers/) 目录中 - 一个文件存放一个爬虫的源代码 - 文件名只能包含大小写英文字母、下划线和数字,且不能以数字开头 - 爬虫使用 superagent 来收发请求,使用 cheerio 来解析请求 - 将 `module.exports` 赋值成爬虫函数即可导出爬虫 - 原则上不建议再引入其他的库。如果需要让爬虫在浏览器上运行, 不能导入项目中的其他源代码。 - 爬虫函数中可以抛出任何异常(例如“用户不存在”),系统将会正确 处理这些异常。 #### 爬虫函数格式 参数: - options: {Object} - 爬虫的参数,可以在 `config.yml` 中配置,参见下文 - username: {String} - 要爬取题量的用户名 返回值: 返回一个对象,其中包含如下属性 - solved: {Number} - 用户在此网站上解决的题目数量 - submissions: {Number} - 用户在此网站上的总提交数 - solvedList: {Array|undefined|null} - 用户通过的题目列表,为 null 或 undefined 表示该爬虫目前无法统计题目列表。 对于普通的爬虫(非 virtual judge),可以是如下的格式: "1001" 或者 "301-A" 之类的字符串,不需要附加爬虫名称。 对于 virtual judge 爬虫,请参考下方的文档。 - submissionsByCrawlerName: {Object.{string, number}} - Submissions in each oj, only exists when the crawler is a virtual_judge crawler Key is the name of crawler. If crawler does not exists in config, the name defined by virtual_judge. Value is the submission count of the OJ. ### 配置文件 - 配置文件用来注册爬虫、确定爬虫类型和给爬虫提供额外信息 - `config.yml` 配置文件会在前端编译时被读取,在 crawler-api-backend 运行时被读取。 - 由于 `config.yml` 会被纳入版本控制和 docker 生成的镜像中。您可以使用环 境变量来配置一些敏感信息(例如 vjudge 就需要一个帐号的用户名和密码才能 访问其 API)。 - 环境变量格式如下: `ACM_STATISTICS_CRAWLER_ENV__crawlers__vjudge__crawler_login_user="myuser"` - 必须使用前缀来表示环境变量是爬虫的环境变量,使用`__`来表示对象的字段。 - 结果将作为json解析,因此需要将字符串形式的值放进双引号中。 - 环境变量的名称将指定一个 `config.yml` 中的字段,并用值来覆盖它 - 也可以指定一个json格式的值,并覆盖整个对象,比如 `ACM_STATISTICS_CRAWLER_ENV__crawler_order=["hdu", "poj"]` - 请注意,如果您需要在 config 中填写隐私信息,请将爬虫设置成 server_only。否则编译出的前端静态文件中将会含有您的隐私信息。 - 对于 crawler-api-backend 而言,由于在运行期间才会读取 config 文件,因 此可以用 docker 的 env 选项来设置环境变量。对于 frontend,会在生成 dcoker 镜像期间读取配置文件,因此需要在 docker-build 时指定 env 来覆盖配置。 #### 配置文件格式 - name: {String} - 爬虫的名字, ##### crawlers 是一个对象,含有每个爬虫的配置项 crawlers 中的 key 是爬虫的名字,必须跟 crawlers 文件夹中的爬虫文件名相同 (不需要含有 `js` 后缀名)。 crawlers 中的 value 是一个字典,其中包含以下字段: - server_only: {Boolean} - 如果省略,为 false。 本字段表示爬虫是否只出现在服务器中。 如果为true,爬虫在前端的代码将是一个对服务器的api请求。 即不会在前端进行爬取,只在服务器运行此爬虫。 - meta: 元信息,包含标题等等的信息,可以显示在前端或者用在爬虫API中 - title: {String} - OJ名,这是显示在前端上作为标题的 - description: {String} - OJ的说明,可以补充一些信息,会在前端显示出来。这是可选的 - url: {String} - 到OJ的链接,也是可选的。 - virtual_judge: {Boolean} - 是否是 virtual_judge,在计算题目列表时逻辑会稍有不同。 - 其他字段: 配置文件中可以包含任何其他字段 在运行爬虫时,crawlers中的每一项都会被传递给相应的爬虫(从 options 形参),爬虫可以在运行时读取相应的参数。 您写在 meta 字段中的内容会被编译进前端页面,无论爬虫是否为 server_only ##### crawler_order 一个数组,每个元素是一个字符串,表示爬虫的名字。这里的名字必须和 `crawlers` 中的key对应, 也和爬虫的文件对应。系统将根据这里的配置文件装配爬虫,也就是说只要在配置文件中删除此字段, 本爬虫就不会被装配,不会出现在前端或后端中。这个数组的顺序决定了爬虫在前端页面中的显示顺序。 ### 额外信息 在爬虫的 config 属性里也会被传入额外的信息,此信息会在 configReader 中自动生成,也可以被 配置文件中的同名字段覆盖。 - env: {String} - 当前爬虫在哪里运行 - 'server': 如果爬虫函数正在服务器上运行,传入此值 - 'browser': 浏览器…… ### virtual judge 爬虫 对于 vjudge 这样的爬虫,为了避免重复计算题目列表,需要使用 solvedList 来表示所有通过的题目,然后进行去重。 返回的 solvedList 格式如下: "{爬虫名}-{题目编号}"。爬虫名为对应的爬虫的 name(即文件名)。题目编号必须跟该爬虫返回的编号格式相同。 比如 "hdu-2001"。如果当前不存在此类的爬虫,使用一个和当前爬虫不重复的名字即可。 ### 参考 您可以参考 hdu 爬虫和 vjudge 爬虫来编写您的爬虫,这两个分别是 前后端通用爬虫和server_only爬虫。 ## 测试 `test/crawlers.test.js` 中有爬虫的测试文件,原则上测试用例应该至少覆盖主路径 ================================================ FILE: crawler/__mocks__/fs.js ================================================ const {fs} = require('memfs') module.exports = fs ================================================ FILE: crawler/__test__/__snapshots__/crawlers.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`vjudge should work correctly 1`] = ` Object { "solved": 392, "solvedList": Array [ "hdu-3966", "hdu-2063", "poj-1113", "poj-3264", "timus-1348", "dashiye-2243", "hdu-2243", "poj-1111", "poj-2236", "hdu-3473", "poj-2104", "hdu-4607", "hdu-3714", "hdu-1050", "hdu-1009", "hdu-2037", "hdu-1166", "hdu-2017", "LightOJ-1030", "hdu-1054", "poj-2311", "hdu-1907", "timus-1180", "LightOJ-1186", "hdu-1404", "LightOJ-1247", "LightOJ-1199", "LightOJ-1253", "LightOJ-1192", "hdu-4847", "poj-2318", "LightOJ-1004", "hdu-1848", "poj-3237", "spoj-QTREE", "dashiye-1036", "hdu-4825", "uvalive-7340", "codeforces-165E", "codeforces-492E", "codeforces-338D", "poj-1330", "poj-3468", "codeforces-327C", "codeforces-334C", "dashiye-1500", "dashiye-2002", "hdu-5058", "hdu-4456", "hdu-5692", "dashiye-1854", "poj-1151", "hdu-1394", "hdu-1556", "hdu-1541", "hdu-3038", "hdu-1506", "hdu-4496", "poj-1182", "hdu-5045", "hdu-3652", "hdu-2167", "poj-1185", "poj-2342", "hdu-4055", "hdu-3853", "codeforces-512B", "poj-2411", "hdu-2571", "hdu-2476", "hdu-2084", "hdu-1231", "OpenJ_Bailian-1088", "hdu-1494", "hdu-2191", "poj-1088", "hdu-5094", "hdu-2579", "codeforces-540C", "hdu-1495", "codeforces-429B", "hdu-4127", "hdu-1043", "poj-1077", "hdu-4403", "hdu-2510", "hdu-1175", "hdu-1455", "poj-1011", "codeforces-501E", "codeforces-442A", "hdu-2446", "codeforces-446B", "codeforces-490E", "codeforces-500C", "codeforces-478C", "codeforces-451B", "codeforces-462B", "codeforces-460B", "codeforces-456A", "poj-2387", "codeforces-442B", "codeforces-415A", "codeforces-369A", "poj-1651", "hdu-4763", "hdu-2896", "hdu-1251", "uva-11183", "hdu-4081", "hdu-2222", "hdu-3336", "hdu-1711", "hdu-4430", "poj-1961", "poj-3461", "poj-2752", "hdu-2112", "poj-2728", "poj-1287", "poj-2823", "hdu-3410", "hdu-5444", "poj-1577", "hdu-3415", "poj-2255", "codeforces-689D", "hdu-3791", "poj-1470", "hdu-5289", "uva-10090", "hdu-5443", "dashiye-1012", "hdu-2795", "poj-2182", "poj-2352", "poj-1064", "hdu-1538", "hdu-2177", "poj-1740", "hdu-2176", "hdu-1527", "hdu-1849", "hdu-1564", "poj-2484", "hdu-1847", "hdu-1846", "poj-3122", "codeforces-100989C", "codeforces-100989A", "poj-3301", "poj-3579", "poj-2456", "hdu-4349", "poj-1363", "hdu-3037", "poj-1845", "hdu-5673", "LightOJ-1370", "poj-2992", "hdu-4497", "hdu-1215", "LightOJ-1236", "poj-3090", "hdu-3001", "poj-2096", "poj-3254", "poj-1163", "poj-1157", "hdu-4389", "hdu-2089", "poj-2378", "poj-1463", "codeforces-472C", "codeforces-330C", "codeforces-330B", "codeforces-330A", "poj-2286", "fzu-2150", "codechef-DIGROT", "poj-1190", "uva-12558", "codechef-HOTEL", "poj-3126", "poj-1426", "poj-2251", "poj-1321", "poj-3278", "hdu-2897", "hdu-1730", "codeforces-388C", "codechef-DRAGNXOR", "hdu-2147", "hdu-3389", "poj-2368", "poj-2485", "poj-1861", "poj-1258", "poj-1177", "hdu-2193", "uvalive-4648", "hdu-4006", "poj-1251", "hdu-3068", "zoj-1610", "poj-2632", "poj-2528", "uvalive-6833", "uva-12718", "hdu-2064", "hdu-2013", "hdu-2010", "hdu-2032", "hdu-2012", "hdu-2026", "hdu-2020", "hdu-1164", "hdu-1754", "poj-1990", "poj-2299", "poj-2481", "hdu-4686", "codeforces-675C", "hdu-2629", "uva-10305", "poj-3067", "codeforces-450B", "hdu-1061", "LightOJ-1009", "uva-705", "uva-10050", "uva-540", "uva-11111", "poj-3070", "hdu-2035", "poj-1458", "LightOJ-1046", "LightOJ-1039", "hdu-4850", "codeforces-667C", "LightOJ-1012", "LightOJ-1037", "uva-297", "uva-784", "uva-572", "uva-657", "LightOJ-1032", "LightOJ-1033", "LightOJ-1038", "LightOJ-1044", "uva-401", "uva-10010", "uva-10361", "uva-548", "uva-442", "uva-673", "uva-10152", "uva-133", "uva-712", "uva-127", "uva-112", "uva-340", "uva-101", "LightOJ-1303", "LightOJ-1048", "LightOJ-1056", "hdu-1221", "zoj-2290", "timus-1792", "LightOJ-1212", "LightOJ-1113", "uva-10420", "LightOJ-1031", "LightOJ-1027", "LightOJ-1025", "LightOJ-1021", "LightOJ-1018", "LightOJ-1017", "LightOJ-1013", "LightOJ-1011", "poj-3125", "hdu-1021", "hdu-1285", "poj-2785", "poj-1979", "poj-1995", "poj-1006", "hdu-5612", "hdu-1045", "codeforces-651B", "codeforces-609A", "codeforces-615A", "codeforces-515C", "fzu-1327", "poj-2478", "codeforces-405B", "codeforces-580B", "hdu-4699", "poj-1013", "poj-1012", "hdu-4602", "hdu-4198", "hdu-3833", "hdu-3723", "hdu-4161", "hdu-4151", "hdu-4104", "hdu-3664", "poj-2362", "hdu-3579", "poj-2503", "zoj-2772", "zoj-2388", "hdu-2001", "hdu-2002", "hdu-2003", "hdu-2000", "poj-1915", "poj-1023", "poj-1056", "poj-3258", "poj-3273", "poj-3104", "hdu-1031", "hdu-1225", "hdu-4508", "hdu-4510", "hdu-4505", "poj-2243", "poj-2488", "hdu-1016", "poj-3190", "poj-3624", "poj-1061", "hdu-4864", "poj-3672", "poj-2272", "poj-3984", "poj-1562", "poj-1019", "poj-1007", "hdu-1896", "poj-2393", "poj-2782", "hdu-1023", "poj-1456", "hdu-2303", "poj-2833", "poj-2463", "hdu-1075", "hdu-1022", "hdu-2057", "hdu-4310", "hdu-1018", "hdu-1789", "hdu-1263", "hdu-2051", "hdu-2050", "hdu-1004", "hdu-1027", "hdu-1033", "poj-2242", "hdu-1228", "hdu-1029", "poj-1001", "poj-1573", "hdu-1035", "poj-3750", "uva-1225", "zoj-2482", "hdu-2098", "poj-2769", "poj-3006", "hdu-1019", "hdu-1030", "hdu-1034", "hdu-1013", "poj-2196", "hdu-1002", "hdu-2045", "codeforces-436B", "codeforces-387B", "codeforces-387A", "poj-2993", "poj-2996", "poj-1099", "hdu-2054", "hdu-1032", "codeforces-384A", "codeforces-399A", "SCU-4424", "hdu-2039", ], "submissions": 1282, "submissionsByCrawlerName": Object { "LightOJ": 71, "OpenJ_Bailian": 1, "SCU": 5, "codechef": 7, "codeforces": 109, "dashiye": 24, "fzu": 2, "hdu": 523, "poj": 398, "spoj": 1, "timus": 8, "uva": 111, "uvalive": 6, "zoj": 16, }, } `; ================================================ FILE: crawler/__test__/configReader.test.js ================================================ const configReader = require('../lib/configReader') const _ = require('lodash') test('readConfigs 能够正确读取配置', async () => { const config = await configReader.readConfigs() expect(config.crawlers.length).not.toBe(0) const pojConfig = config.crawlers.poj expect(pojConfig).toBeTruthy() expect(pojConfig.meta).toBeTruthy() }) test('readCrawlerConfigs 能够正确读取配置', async () => { const config = await configReader.readCrawlerConfigs() expect(config.length).not.toBe(0) const pojConfig = _.find(config, item => item.name === 'poj') expect(pojConfig).toBeTruthy() expect(pojConfig.meta).toBeTruthy() }) describe('mergeConfigWithEnv', () => { it('能够正确合并信息', () => { const baseConfig = { a: { b: [{}], d: 333, }, } configReader.mergeConfigWithEnv(baseConfig, { 'ACM_STATISTICS_CRAWLER_ENV__a__b__1__c': 12, }) expect(baseConfig).toMatchObject({ a: { b: [{}, {c: 12}], d: 333, }, }) }) it('能够合并json的信息', () => { const baseConfig = { a: 1, } configReader.mergeConfigWithEnv(baseConfig, { 'ACM_STATISTICS_CRAWLER_ENV__a': '{"b":{"c":"aaa"}}', }) expect(baseConfig).toMatchObject({ a: { b: { c: 'aaa', }, }, }) }) it('只导入有指定前缀的环境变量', () => { const baseConfig = {} configReader.mergeConfigWithEnv(baseConfig, { 'NNNNNN': 'asdf', }) expect(baseConfig).toMatchObject({}) }) it('能够导入字符串环境变量', () => { const baseConfig = {} configReader.mergeConfigWithEnv(baseConfig, { 'ACM_STATISTICS_CRAWLER_ENV__a': '"{asdf}"', }) expect(baseConfig).toMatchObject({ a: '{asdf}', }) }) }) test('readMetaConfigs 能够读取元信息', async () => { const meta = await configReader.readMetaConfigs() expect(meta.vjudge).toBeTruthy() expect(meta.vjudge.title).toBe('VJudge') expect(meta.vjudge.description).toBeTruthy() expect(meta.vjudge.virtual_judge).toBe(true) }) ================================================ FILE: crawler/__test__/crawlers.test.js ================================================ const _ = require('lodash') const poj = require('../crawlers/poj') const hdu = require('../crawlers/hdu') const zoj = require('../crawlers/zoj') const dashiye = require('../crawlers/dashiye') const codeforces = require('../crawlers/codeforces') const uva = require('../crawlers/uva') const uvalive = require('../crawlers/uvalive') const fzu = require('../crawlers/fzu') const spoj = require('../crawlers/spoj') const timus = require('../crawlers/timus') const leetcode_cn = require('../crawlers/leetcode_cn') const vjudge = require('../crawlers/vjudge') const csu = require('../crawlers/csu') const loj = require('../crawlers/loj') const luogu = require('../crawlers/luogu') const nowcoder = require('../crawlers/nowcoder') const uestc = require('../crawlers/uestc') const atcoder = require('../crawlers/atcoder') const aizu = require('../crawlers/aizu') const codechef = require('../crawlers/codechef') const eljudge = require('../crawlers/eljudge') const bnu = require('../crawlers/bnu') const codewars = require('../crawlers/codewars') const uoj = require('../crawlers/uoj') const nbut = require('../crawlers/nbut') const nod = require('../crawlers/nod') const nit = require('../crawlers/nit') const dmoj = require('../crawlers/dmoj') const sdutoj = require('../crawlers/sdutoj') const { readConfigs } = require('../lib/configReader') jest.setTimeout(10000) // 最多10秒 const notExistUsername = 'fmv84zcq3hwu' const username = 'vjudge5' // 另外,感谢 @leoloveacm, @2013300262 同学提供测试帐号 describe('poj', () => { test('should throw when user does not exist', async () => { await expect(poj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(poj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await poj(null, username) checkRes(res) expect(res.solvedList).toContain('1001') }) }) describe('hdu', () => { const config = { env: 'server', } test('should throw when user does not exist', async () => { await expect(hdu(config, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(hdu(config, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await hdu(config, 'vjudge4') checkRes(res) expect(res.solvedList).toContain('1001') }) }) describe('zoj', () => { test('should throw when user does not exist', async () => { await expect(zoj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(zoj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await zoj(null, 'IamRobot') checkRes(res) expect(res.solvedList).toContain('1001') // so it is really slow... }, 30000) }) describe('dashiye', () => { test('should throw when user does not exist', async () => { await expect(dashiye(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(dashiye(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await dashiye(null, 'root') checkRes(res) expect(res.solvedList).toContain('1001') }) }) describe('codeforces', () => { test('should throw when user does not exist', async () => { await expect(codeforces(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(codeforces(null, ' ' + notExistUsername)).rejects.toThrow('handle: Field should contain only Latin letters, digits, underscore or dash characters') }) test('should work correctly', async () => { const res = await codeforces(null, 'leoloveacm') // 没有找到好的测试多页返回的帐号,还是用这个测试单页吧 checkRes(res) expect(new Set(res.solvedList)).toMatchObject(new Set([ '754B', '165E', '492E', '338D', '333A', '703A', '540C', '680B', '680A', '676A', '450B', '667A', '667C', ])) }) }) describe('uva', () => { test('should throw when user does not exist', async () => { await expect(uva(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(uva(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await uva(null, 'leoloveacm') checkRes(res) expect(res.solvedList).toContain('1395') }) }) describe('uvalive', () => { test('should throw when user does not exist', async () => { await expect(uvalive(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(uvalive(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await uvalive(null, 'npuacm') checkRes(res) expect(res.solved).toBe(2) expect(res.submissions).toBe(3) expect(new Set(res.solvedList)).toMatchObject(new Set([ '4445', '3198', ])) }) }) describe('fzu', () => { test('should throw when user does not exist', async () => { await expect(fzu(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(fzu(null, ' ' + notExistUsername)) .rejects.toThrow('The crawler does not support username with spaces') }) test('should work correctly', async () => { const res = await fzu(null, username) checkRes(res) expect(res.solvedList).toContain('1001') }) }) describe('spoj', () => { test('should throw when user does not exist', async () => { await expect(spoj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(spoj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await spoj(null, username) checkRes(res) expect(res.solvedList).toContain('ABA12D') }) }) describe('timus', () => { test('should throw when user does not exist', async () => { await expect(timus(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(timus(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await timus(null, 'vjudge11') checkRes(res) expect(res.submissions).toBeGreaterThan(10) expect(res.solvedList).toContain('1387') }) }) describe('leetcode_cn', () => { test('should throw when user does not exist', async () => { await expect(leetcode_cn(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(leetcode_cn(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) // eslint-disable-next-line jest/expect-expect test('should work correctly', async () => { const res = await leetcode_cn(null, 'wwwlsmcom') checkRes(res) }) }) describe('csu', () => { test('should throw when user does not exist', async () => { await expect(csu(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(csu(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await csu(null, username) checkRes(res) expect(res.solvedList).toContain('1001') }) }) describe('vjudge', () => { let vjConfig beforeAll(async () => { const config = await readConfigs() // config should be read to test the crawler // you can set environment variable according to README.md vjConfig = config.crawlers.vjudge }) test('ensure config exists and is correct', () => { expect(vjConfig).toBeTruthy() expect(vjConfig.crawler_login_user).toBeTruthy() expect(vjConfig.crawler_login_user).not.toBe('用户名') expect(vjConfig.crawler_login_password).toBeTruthy() expect(vjConfig.crawler_login_password).not.toBe('密码') // console.log(vjConfig) }) test('should throw when user does not exist', async () => { await expect(vjudge(vjConfig, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(vjudge(vjConfig, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await vjudge(vjConfig, 'leoloveacm') checkRes(res) expect(res.solvedList).toContain('codeforces-436B') expect(res.submissionsByCrawlerName).toBeTruthy() expect(res.submissionsByCrawlerName.hdu).toBeGreaterThan(100) expect(res).toMatchSnapshot() }, 50000) }) describe('loj', () => { test('should throw when user does not exist', async () => { await expect(loj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await loj(null, 'cz_xuyixuan') // 自定义存在的用户名 checkRes(res) expect(res.solvedList).toContain('103') }, 50000) }) describe('luogu', () => { test('should throw when user does not exist', async () => { await expect(luogu(null, notExistUsername)).rejects.toThrow('The user does not exist') }, 50000) test('can recognize username with space', async () => { await expect(luogu(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }, 50000) test('should work correctly', async () => { const res = await luogu(null, '811437') // user_id checkRes(res) expect(res.solvedList).toContain('P1001') expect(res.solvedList.length).toBeGreaterThan(100) }, 50000) test('should handle the user with submission bigger than 1000 correctly', async () => { const res = await luogu(null, 'NaCly_Fish') checkRes(res) expect(res.submissions).toBeGreaterThan(1000) }, 50000) }) describe('nowcoder', () => { test('should throw when user does not exist', async () => { await expect(nowcoder(null, '11')).rejects.toThrow('The user does not exist') }) test('should recognize usernames that are not ID', async () => { await expect(nowcoder(null, 'wwwlsmcom')).rejects.toThrow('牛客网的输入必须是用户ID(数字格式)') await expect(nowcoder(null, '123wwwlsmcom')).rejects.toThrow('牛客网的输入必须是用户ID(数字格式)') await expect(nowcoder(null, '123 wwwlsmcom')).rejects.toThrow('牛客网的输入必须是用户ID(数字格式)') await expect(nowcoder(null, ' wwwlsmcom')).rejects.toThrow('牛客网的输入必须是用户ID(数字格式)') }) test('should work correctly', async () => { const res = await nowcoder(null, '112946') checkRes(res) expect(res.solvedList).toContain('16632') }) }) describe('uestc', () => { test('should throw when user does not exist', async () => { await expect(uestc(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(uestc(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await uestc(null, 'HeRaNO') checkRes(res) expect(res.solvedList).toContain('1490') const newRes = await uestc(null, 'acm-statistics-test') expect(newRes).toMatchObject({ submissions: 3, solved: 1, solvedList: ['1'], }) }) }) describe('atcoder', () => { test('should throw when user does not exist', async () => { await expect(atcoder(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(atcoder(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await atcoder(null, 'wata') expect(typeof res.solved).toBe('number') expect(typeof res.submissions).toBe('number') expect(res.solved).toBeGreaterThan(0) expect(res.submissions).toBe(res.solved) }) }) describe('aizu', () => { test('should throw when user does not exist', async () => { await expect(aizu(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(aizu(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await aizu(null, username) checkRes(res) expect(res.solvedList).toContain('ALDS1_3_C') }) }) describe('codechef', () => { test('should throw when user does not exist', async () => { await expect(codechef(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(codechef(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { // don't know why, but in vjudge2 - vjudge5, solvedList does not match solved count const res = await codechef(null, 'vjudge') checkRes(res) expect(res.solvedList).toContain('KGOOD') }) }) describe('eljudge', () => { test('should throw when user does not exist', async () => { await expect(eljudge(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(eljudge(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await eljudge(null, 'vjudge5') checkRes(res) expect(res.solvedList).toContain('000') }) }) describe('bnu', () => { test('should throw when user does not exist', async () => { await expect(bnu(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(bnu(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await bnu(null, '51isoft') checkRes(res) expect(res.solvedList).toBeNull() }) }) describe('codewars', () => { test('should throw when user does not exist', async () => { await expect(codewars(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(codewars(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await codewars(null, 'Liu233w') expect(typeof res.solved).toBe('number') expect(typeof res.submissions).toBe('number') expect(res.solved).toBeGreaterThan(0) expect(res.submissions).toBe(res.solved) expect(res.solvedList.length).toBe(res.solved) expect(res.solvedList).toContain('equal-sides-of-an-array') }) }) describe('uoj', () => { test('should throw when user does not exist', async () => { await expect(uoj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(uoj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { // it is an administration account, so I guess it's fine const res = await uoj(null, 'matthew99') checkRes(res) expect(res.solvedList).toContain('30') }) }) describe('nbut', () => { test('should throw when user does not exist', async () => { await expect(nbut(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(nbut(null, ' ' + notExistUsername)) .rejects.toThrow('The crawler does not support username with spaces') }) test('should work correctly', async () => { // it is an administration account, so I guess it's fine const res = await nbut(null, username) checkRes(res) expect(res.solvedList).toContain('1010') }) }) describe('nod', () => { test('should throw when user does not exist', async () => { await expect(nod(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(nod(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { // vjudge const res = await nod(null, '张翼德') checkRes(res) expect(res.solvedList).toContain('1079') }) }) describe('nit', () => { test('should throw when user does not exist', async () => { await expect(nit(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(nit(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await nit(null, 'teito') checkRes(res) expect(res.solvedList).toContain('nit-100') expect(res.solvedList).toContain('hdu-2097') }) }) describe('dmoj', () => { test('should throw when user does not exist', async () => { await expect(dmoj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(dmoj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await dmoj(null, 'Xyene') checkRes(res) expect(res.solvedList).toContain('aplusb') }) }) describe('sdutoj', () => { test('should throw when user does not exist', async () => { await expect(sdutoj(null, notExistUsername)).rejects.toThrow('The user does not exist') }) test('can recognize username with space', async () => { await expect(sdutoj(null, ' ' + notExistUsername)).rejects.toThrow('The user does not exist') }) test('should work correctly', async () => { const res = await sdutoj(null, 'root') checkRes(res) expect(res.solvedList).toContain('1000') }) }) function checkRes(res) { expect(typeof res.solved).toBe('number') expect(typeof res.submissions).toBe('number') expect(res.solved).toBeGreaterThan(0) expect(res.submissions).toBeGreaterThan(0) expect(res.submissions).toBeGreaterThan(res.solved) if (!_.isNil(res.solvedList)) { expect(res.solvedList.length).toBe(res.solved) } } ================================================ FILE: crawler/__test__/functionGenerator.test.js ================================================ const path = require('path') const _ = require('lodash') // used by eval() // eslint-disable-next-line no-unused-vars const superagent = require('superagent') const nock = require('nock') jest.mock('../lib/configReader') jest.mock('fs') const fs = require('fs') describe('generateServerCrawlerFunctions', () => { let functions beforeAll(async () => { for (let item of ['crawler1', 'crawler2', 'crawler_for_server']) { // 因为 functionGenerator 里面 require 的时候带了 js 后缀,这里必须也加上后缀,否则会提示找不到模块 jest.mock(`../crawlers/${item}.js`, () => async function (config, username) { return { config: config, username: username, solved: 0, submissions: username === 'wrong format' ? NaN : 0, } }, { virtual: true }) } const functionGenerator = require('../lib/functionGenerator') functions = await functionGenerator.generateServerCrawlerFunctions() }) it('能够获取到函数', () => { expect(functions).toEqual(expect.objectContaining({ crawler1: expect.any(Function), crawler2: expect.any(Function), crawler_for_server: expect.any(Function), })) }) it('能将用户名传入函数', async () => { const ret = await functions.crawler1('username1') expect(ret.username).toBe('username1') }) it('能让函数取到设置信息', async () => { const ret = await functions.crawler1('username1') expect(ret.config.meta.title).toBe('Crawler1') }) it('能让函数取到环境信息 - server', async () => { const ret = await functions.crawler1('username1') expect(ret.config.env).toBe('server') }) it('should throw when crawler return wrong format results', async () => { await expect(functions.crawler1('wrong format')) .rejects.toThrow('The crawler returned wrong format result. It can be a bug in crawler.') }) }) describe('generateBrowserCrawlerFunctions', () => { let functions let functionStrs const serverFunctionContent = 'This line should not exist in generatedFunctions' beforeAll(async () => { function ensureDirectoryExistence(filePath) { var dirname = path.dirname(filePath) if (fs.existsSync(dirname)) { return true } ensureDirectoryExistence(dirname) fs.mkdirSync(dirname) } function writeCrawlerMockFile(fileName, content) { const filePath = path.join(__dirname, `../crawlers/${fileName}.js`) ensureDirectoryExistence(filePath) fs.writeFileSync(filePath, content) } for (let item of ['crawler1', 'crawler2']) { writeCrawlerMockFile(item, `module.exports = async function (config, username) { return { config: config, username: username, solved: 0, submissions: username === 'wrong format' ? NaN : 0, } }`) } writeCrawlerMockFile('crawler_for_server', serverFunctionContent) const functionGenerator = require('../lib/functionGenerator') functionStrs = await functionGenerator.generateBrowserCrawlerFunctions() functions = _.mapValues(functionStrs, str => eval(str)) }) it('能够获取到函数', () => { expect(functions).toEqual(expect.objectContaining({ crawler1: expect.any(Function), crawler2: expect.any(Function), crawler_for_server: expect.any(Function), })) }) it('能将用户名传入函数', async () => { const ret = await functions.crawler1('username1') expect(ret.username).toBe('username1') }) it('should throw when crawler return wrong format results', async () => { await expect(functions.crawler1('wrong format')) .rejects.toThrow('The crawler returned wrong format result. It can be a bug in crawler.') }) describe('在浏览器和服务器同时使用的配置下', () => { it('能让函数取到设置信息', async () => { const ret = await functions.crawler1('username1') expect(ret.config.meta.title).toBe('Crawler1') }) it('能让函数取到环境信息 - browser', async () => { const ret = await functions.crawler1('username1') expect(ret.config.env).toBe('browser') }) }) describe('在只运行在服务器上的配置下', () => { const crawlerbaseUrl = '/api/crawlers/crawler_for_server/' const resolvedUser = 'resolvedUser' const rejectedUser = 'rejectedUser' const networkErrorUser = 'networkErrorUser' const crawlerErrorMessage = 'User not found' const resolvedData = { solved: 101, submissions: 230, } it('不会打包服务器端的函数', () => { expect(functionStrs.crawler_for_server).not.toContain(serverFunctionContent) }) it('生成的函数在服务器端正常时能够正确返回', async () => { const scope = nock('http://localhost') .get(crawlerbaseUrl + resolvedUser) .reply(200, { error: false, data: resolvedData, }) const res = await functions.crawler_for_server(resolvedUser) expect(res).toMatchObject(resolvedData) scope.done() }) it('生成的函数在服务器端返回错误时能够抛出异常,并包含正确的异常信息', async () => { const scope = nock('http://localhost') .get(crawlerbaseUrl + rejectedUser) .reply(200, { error: true, message: crawlerErrorMessage, }) await expect(functions.crawler_for_server(rejectedUser)) .rejects.toThrow(crawlerErrorMessage) scope.done() }) it('生成的函数在网络错误时能够抛出异常,并且含有异常信息', async () => { const scope = nock('http://localhost') .get(crawlerbaseUrl + networkErrorUser) .replyWithError('something awful happened') await expect(functions.crawler_for_server(networkErrorUser)) .rejects.toThrow(/.+/) scope.done() }) }) }) ================================================ FILE: crawler/base.Dockerfile ================================================ ARG NODE_BASE_IMAGE FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY package.json pnpm-lock.yaml ./ RUN pnpm install COPY . . ================================================ FILE: crawler/config.yml ================================================ crawler_order: - poj - hdu - zoj - dashiye - codeforces - uva - uvalive - fzu - spoj - timus - leetcode_cn - csu - loj - luogu - nowcoder - uestc - atcoder - aizu - codechef - eljudge - bnu - codewars - uoj - nbut - nod # - nit - dmoj - sdutoj - vjudge crawlers: poj: meta: title: POJ description: url: http://poj.org/ hdu: meta: title: HDU description: url: http://acm.hdu.edu.cn/ zoj: meta: title: ZOJ description: Only nickname is supported (Only historical data are available since crawlers are prohibited by Pintia) url: https://zoj.pintia.cn/ dashiye: meta: title: HYSBZ description: url: http://www.lydsy.com/JudgeOnline/ codeforces: meta: title: CodeForces description: Including CodeForces::Gym url: http://codeforces.com/ uva: meta: title: UVA description: url: https://uva.onlinejudge.org/ uvalive: meta: title: ICPC Live Archive description: url: https://icpcarchive.ecs.baylor.edu/index.php fzu: meta: title: FZU description: url: http://acm.fzu.edu.cn/index.php spoj: meta: title: SPOJ description: url: http://www.spoj.com/ timus: meta: title: Timus (URAL) description: url: http://acm.timus.ru/ leetcode_cn: meta: title: LeetCode_CN description: url: https://leetcode.cn csu: meta: title: CSU description: url: http://acm.csu.edu.cn/ loj: meta: title: LibreOJ description: url: https://loj.ac/ luogu: meta: title: 洛谷 description: Both username and user_id are supported url: https://www.luogu.com.cn server_only: true nowcoder: meta: title: 牛客OJ description: 目前只支持输入用户ID(在你的AC列表的URL中) url: https://ac.nowcoder.com/acm/home uestc: meta: title: Lutece (UESTC) description: url: https://acm.uestc.edu.cn/home atcoder: meta: title: AtCoder description: | API provided by kenkoooo (https://github.com/kenkoooo/AtCoderProblems). Only AC number is supported url: https://atcoder.jp aizu: meta: title: AIZU description: url: http://judge.u-aizu.ac.jp/onlinejudge/index.jsp codechef: meta: title: CodeChef description: url: https://www.codechef.com/ eljudge: meta: title: El Judge description: url: http://acm.mipt.ru bnu: meta: title: BNUOJ description: url: http://www.bnuoj.com codewars: meta: title: Codewars description: | Currently it does not have submission number. Username is case sensitive. url: https://www.codewars.com uoj: meta: title: UOJ description: url: http://uoj.ac/ nbut: meta: title: NBUT description: url: https://ac.2333.moe/ nod: meta: title: 51Nod description: Please use your nickname (displayed in your home page) url: https://www.51nod.com nit: meta: title: OurOJ (NIT) description: url: https://www.nitacm.com/ dmoj: meta: title: DMOJ description: url: https://dmoj.ca/ sdutoj: meta: title: SDUT OJ description: url: https://oj.sdutacm.cn/ vjudge: meta: title: VJudge description: virtual judge,这个OJ的题量是单独计算的 url: https://vjudge.net/ virtual_judge: true # 只运行在服务器上,不运行在浏览器上 server_only: true # vjudge 有一个api接口,需要用任意的用户名和密码来接入才能访问 crawler_login_user: 用户名 crawler_login_password: 密码 ================================================ FILE: crawler/crawlers/.eslintrc.js ================================================ module.exports = { root: false, rules: { // 目前爬虫不使用 lodash 'lodash/prefer-lodash-method': 'off', 'lodash/prefer-get': 'off', }, } ================================================ FILE: crawler/crawlers/LICENSE ================================================ BSD 2-Clause License Copyright (c) 2018, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: crawler/crawlers/aizu.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let statusRes try { statusRes = await request('https://judgeapi.u-aizu.ac.jp/users/' + username) } catch (err) { if (err.response && err.response.status === 404) { throw new Error('The user does not exist') } throw err } // seems that the list is big enough, we don't need pages const listRes = await request(`https://judgeapi.u-aizu.ac.jp/solutions/users/${username}?page=0&size=10000`) const solvedSet = new Set(listRes.body.map(a => a.problemId)) return { solved: statusRes.body.status.solved, submissions: statusRes.body.status.submissions, solvedList: [...solvedSet], } } ================================================ FILE: crawler/crawlers/atcoder.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } // request atcoder to detect if user exists, to reduce throughput of kenkoooo's api try { await request .get('https://atcoder.jp/users/' + username) } catch (e) { if (e.message === 'Not Found') { throw new Error('The user does not exist') } else { throw e } } // Thank @kenkoooo for the api // Source code: https://github.com/kenkoooo/AtCoderProblems const res = await request .get('https://kenkoooo.com/atcoder/atcoder-api/v3/user/ac_rank') .query({ user: username }) const solved = res.body.count const submissions = solved return { submissions, solved, } } ================================================ FILE: crawler/crawlers/bnu.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('http://www.bnuoj.com/userinfo.php') .query({ name: username }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('.alert-error:contains("No such user!")').length >= 1) { throw new Error('The user does not exist') } try { // TODO: ac list const acList = null const submissions = $('th:contains("Total Submissions")') .next().text() const solved = $('th:contains("Accepted")') .next().text() return { submissions: parseInt(submissions), solved: parseInt(solved), solvedList: acList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/codechef.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request.get('https://www.codechef.com/users/' + username) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('a[href="/"]:contains("Home")').length === 0) { // not in user profile page throw new Error('The user does not exist') } try { const solvedText = $('h5:contains("Fully Solved")').text().match(/\((\d+)\)/)[1] const solvedList = [] $('h5:contains("Fully Solved") + article a').each(function (i, el) { solvedList.push($(el).text().trim()) }) const submissionText = $('script:contains("Highcharts.chart")').html().replace(/\s/gi, '') const matchObjectText = submissionText.match(/data:\[(.*),\]/)[1] const submitMatchIterator = matchObjectText.matchAll(/y:(\d+)/g) let submissions = 0 for (const a of submitMatchIterator) { submissions += parseInt(a[1]) } return { solved: parseInt(solvedText), solvedList, submissions, } } catch (err) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/codeforces.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const acSet = new Set() const submissions = await queryForNumber(username, 1, acSet) return { solved: acSet.size, submissions: submissions, solvedList: [...acSet], } } const MAX_PAGE_SIZE = 10000 /** * 递归查询题数 * @param username * @param pageCount {Number} - 这个是页数,数字是几就是第几页 * @param acSet {Set<{String}>} - ac的题目列表,会修改此对象 * @returns {Promise} */ async function queryForNumber(username, pageCount, acSet) { // 发起请求 ///////////////////////////////////////////////////////////// const queryObject = { handle: username, from: (pageCount - 1) * MAX_PAGE_SIZE + 1, count: MAX_PAGE_SIZE, } let res = null try { res = await request .get('http://codeforces.com/api/user.status') .query(queryObject) } catch (e) { if (e.response && e.response.body && e.response.body.status) { // 有 response 且以 json 的格式相应 const comment = e.response.body.comment if (/handle: User with handle .* not found/.test(comment)) { throw new Error('The user does not exist') } else { throw new Error(comment) } } else { throw e } } // 处理结果 ///////////////////////////////////////////////////////////// const problemArray = res.body.result if (problemArray.length === 0) { return 0 } problemArray.forEach(function (element) { if (element.verdict === 'OK') { const problem = element.problem const title = problem.contestId + problem.index acSet.add(title) } }) const total = problemArray.length // 递归处理(返回结果或再发起请求) //////////////////////////////////////////// if (total < MAX_PAGE_SIZE) { // 已经读完 return total } else { const ret = await queryForNumber(username, pageCount + 1, acSet) return ret + total } } ================================================ FILE: crawler/crawlers/codewars.js ================================================ const request = require('superagent') // api url : https://dev.codewars.com/#get-user:-completed-challenges module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } // TODO: get submission let totalPage = undefined let currentPage = 0 const acSet = new Set() do { let res try { res = await request .get(`https://www.codewars.com/api/v1/users/${username}/code-challenges/completed`) .query({ page: 0 }) } catch (err) { if (err.response && err.response.status === 404) { throw new Error('The user does not exist') } throw err } res.body.data.forEach(d => { acSet.add(d.slug) }) totalPage = res.body.totalPages ++currentPage } while (currentPage < totalPage) return { solved: acSet.size, submissions: acSet.size, solvedList: [...acSet], } } ================================================ FILE: crawler/crawlers/csu.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('http://acm.csu.edu.cn/csuoj/user/userinfo') .query({user_id: username}) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if (/

No such user<\/p>/.test(res.text)) { throw new Error('The user does not exist') } try { const tds = $('#info_left tbody td') return { solved: Number($(tds[1]).text()), submissions: Number($(tds[2]).text()), solvedList: $('#userinfo_left a[href^="/csuoj/problemset/problem?pid="]') .map((i,elem)=>$(elem).text().trim()) .get(), } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/dashiye.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('http://www.lydsy.com/JudgeOnline/userinfo.php') .query({user: username}) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('body').text().trim().endsWith('No such User!')) { throw new Error('The user does not exist') } try { // p(1000);p(1001);p(1002)....p(XXXX); // 这个题目列表是前端渲染的 const acListScript = $('td[rowspan=14] > script').html().split('\n')[2] // ['p(1000)', 'p(1001)' ...] const singleList = acListScript.split(';').slice(0, -1) const acList = singleList.map(item => item.substring(2, item.length - 1)) return { solved: Number($('td:contains("Solved") + td > a').text()), submissions: Number($('td:contains("Submit") + td > a').text()), solvedList: acList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/dmoj.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res try { res = await request .get('https://dmoj.ca/submissions/user/' + username) } catch (err) { if (err.response && err.response.status === 404) { throw new Error('The user does not exist') } else { throw err } } if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) let submissions try { const codes = $('script:contains("window.results_json")').html().trim().split('\n') const line = codes[codes.length - 1] const json = JSON.parse(line.match(/\{.*\}/)[0]) submissions = json.total } catch (e) { throw new Error('Error while parsing') } res = await request .get('https://dmoj.ca/api/v2/user/' + username) try { const solvedList = res.body.data.object.solved_problems // const solved = res.body.data.object.problem_count return { solved: solvedList.length, submissions, solvedList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/eljudge.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('http://acm.mipt.ru/judge/users.pl') .query({ user: username }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } if (/User .+ does not exist/.test(res.text)) { throw new Error('The user does not exist') } const $ = cheerio.load(res.text) try { const solvedElem = $('font:contains("solved:")') const solvedText = solvedElem.children('b').text() const solvedList = [] solvedElem.nextUntil('font').find('a').each((i, el) => { solvedList.push($(el).text().trim()) }) const submissionElems = $('font:contains("Statistics:")') .nextAll('table') .first() .find('div') let submissions = 0 submissionElems.each((i, el) => { submissions += parseInt($(el).text()) }) return { solved: parseInt(solvedText), solvedList, submissions, } } catch (err) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/fzu.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } if (/\s/.test(username)) { throw new Error('The crawler does not support username with spaces') } const res = await request .get('http://acm.fzu.edu.cn/user.php') .query({uname: username}) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('font').filter((i, el) => $(el).text() === 'No such user or user has been deleted!').length >= 1) { throw new Error('The user does not exist') } try { const acList = $('b > a[href^="problem.php?pid="]') .map((i, elem) => $(elem).text()) .get() return { submissions: Number($('td:contains("Total Submitted") + td').text()), solved: Number($('td:contains("Total Accepted") + td').text()), solvedList: acList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/hdu.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res const RETRY_TIMES = config.env === 'server' ? 1 : 2 for (let i = 0; i < RETRY_TIMES; ++i) { try { res = await request .get('http://acm.hdu.edu.cn/userstatus.php') .query({user: username}) break } catch (e) { if (i >= RETRY_TIMES - 1) { throw e } console.log('HDU connection error, retry ...') } } if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('div').filter((i, el) => $(el).text() === 'No such user.').length >= 1) { throw new Error('The user does not exist') } try { // p(1000,3588,11274);p(1001,1951,7721);p(1002,1535,6550);... // 这个题目列表是前端渲染的 const acListScript = $('h3:has(font:contains("List of solved problems")) + p > script').html() // ['p(1000,3588,11274)', 'p(1001,1951,7721)' ...] const singleList = acListScript.split(';').slice(0, -1) const acList = singleList.map(item => item.match(/\d+/g)[0]) return { submissions: Number($('td:contains("Submissions") + td').text()), solved: Number($('td:contains("Problems Solved") + td').text()), solvedList: acList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/leetcode_cn.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const input = { query: ` query userSessionProgress($userSlug:String!){ userProfileUserQuestionSubmitStats(userSlug:$userSlug){ acSubmissionNum { difficulty count } totalSubmissionNum { difficulty count } } }`, variables: { userSlug: username }, } const res = await request .post('https://leetcode.cn/graphql/') .set('User-Agent', 'ojhunt/1.0.0') .send(input) const data = res.body.data.userProfileUserQuestionSubmitStats const acList = data.acSubmissionNum const subList = data.totalSubmissionNum if (acList.length === 0 && subList.length === 0) { throw new Error('The user does not exist') } const solved = acList.map(item => item.count).reduce((a, b) => a + b) const submissions = subList.map(item => item.count).reduce((a, b) => a + b) return { solved, submissions, } } ================================================ FILE: crawler/crawlers/loj.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .post('https://api.loj.ac/api/user/getUserDetail') .send({ now: new Date().toISOString(), timezone: 'UTC', username, }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } if (res.body.error) { throw new Error('The user does not exist') } const submissions = res.body.meta.submissionCount const solvedList = await resolveSolvedList(username) // if a submission is not public, it can be different from the value of the user api const solved = solvedList.length // const solved = res.body.meta.acceptedProblemCount return { submissions, solved, solvedList, } } async function resolveSolvedList(username) { const acSet = new Set() let maxId = null // eslint-disable-next-line no-constant-condition while (true) { const res = await request .post('https://api.loj.ac/api/submission/querySubmission') .send({ submitter: username, status: 'Accepted', maxId, locale: 'en_US', takeCount: 10, // cannot be changed }) if (!res.body.submissions || res.body.submissions.length === 0) { break } res.body.submissions.forEach(item => { acSet.add(item.problem.id + '') maxId = item.id - 1 }) } return [...acSet] } ================================================ FILE: crawler/crawlers/luogu.js ================================================ const request = require('superagent') async function getUserId(username) { const uidRes = await request .get('https://www.luogu.com.cn/api/user/search') .query({keyword: username}) if (!uidRes.ok) { throw new Error(`Server Response Error: ${uidRes.status}`) } const uidJSON = JSON.parse(uidRes.text) if (uidJSON.users[0] == null) { throw new Error('The user does not exist') } return uidJSON.users[0].uid } function getUserJson(text) { try { return JSON.parse(decodeURIComponent(text.match(/decodeURIComponent\("(.*?)"\)/i)[1])) } catch (e) { throw new Error('Error while parsing') } } module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res = await request .get('https://www.luogu.com.cn/user/' + username) if (!res.ok || getUserJson(res.text).code === 404) { const uid = await getUserId(username) res = await request .get('https://www.luogu.com.cn/user/' + uid) } if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const userJson = getUserJson(res.text) if (userJson.code === 404) { throw new Error('User not found') } if (userJson.code !== 200) { throw new Error(`Parse error. Message from luogu: ${userJson.currentTitle}`) } try { const solvedJson = userJson.currentData.passedProblems const acList = solvedJson.map((p) => p.pid) return { submissions: userJson.currentData.user.submittedProblemCount, solved: userJson.currentData.user.passedProblemCount, solvedList: acList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/nbut.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } if (/\s/.test(username)) { throw new Error('The crawler does not support username with spaces') } const submissionPage = await request .get('https://ac.2333.moe/Problem/status.xhtml') .query({ username }) if (!submissionPage.ok) { throw new Error(`Server Response Error: ${submissionPage.status}`) } const $s = cheerio.load(submissionPage.text) const usernameElement = $s('tbody tr a[href^="/User/view_user.xhtml?id="]') if (usernameElement.length === 0) { throw new Error('The user does not exist') } let userId try { userId = parseInt(usernameElement.first().attr('href').match(/\d+/)[0]) } catch (err) { throw new Error('Error while parsing') } const res = await request .get('https://ac.2333.moe/User/view_user.xhtml') .query({ id: userId }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) try { const [submissions, solved] = $('li#limit').text().match(/\d+/g) const solvedList = $('li#solvedlist .fl a[href^="/Problem/view.xhtml?id="]') .map((i, e) => $(e).text()) .get() return { solved: parseInt(solved), solvedList, submissions: parseInt(submissions), } } catch (err) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/nit.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('https://www.nitacm.com/userinfo.php') .query({ name: username }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('.alert-error:contains("No such user!")').length >= 1) { throw new Error('The user does not exist') } let submissions, solved, acList try { submissions = $('th:contains("Total Submissions")') .next().text() solved = $('th:contains("Accepted")') .next().text() acList = $('#userac a').map((_, el) => parseInt($(el).text())).toArray() } catch (e) { throw new Error('Error while parsing') } const ohuntRes = await request .post('https://ojhunt.com/api/ohunt/problems/resolve-label') .send({ onlineJudge: 'OurOJ', list: [...acList], }) try { const solvedList = Object.values(ohuntRes.body.result).map(label => { const [oj, num] = label.split('-') return `${ojMap(oj)}-${num}` }) return { submissions: parseInt(submissions), solved: parseInt(solved), solvedList, } } catch (e) { throw new Error('Error while parsing') } } function ojMap(oj) { // oj that can map its name to crawler name by changing into lower case const simpleMapOj = new Set([ 'codeforces', 'hdu', 'fzu', 'nbut', 'uva', 'uvalive', // 'zoj', 'spoj', // 'timus', // 'csu', // 'hust', // 'atcoder', 'aizu', 'codechef', ]) // crawler name map const ojMap = { '': 'NO_NAME', 'PKU': 'poj', 'URAL': 'timus', // 'HYSBZ': 'dashiye', // it looks like a typo of vjudge // 'EIJudge': 'eljudge', // 'Gym': 'codeforces', // '51Nod': 'nod', } if (simpleMapOj.has(oj.toLowerCase())) { return oj.toLowerCase() } else if (oj in ojMap) { return ojMap[oj] } else { return oj } } ================================================ FILE: crawler/crawlers/nod.js ================================================ const request = require('superagent') // 51nod module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res = await request .get('https://www.51nod.com/SearchReader/TitleOnly') .query({ searchStr: username }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } if (!res.body) { throw new Error('The user does not exist') } // find user id in search panel let userId = null for (const item of res.body) { if (item.Content === username && item.ContentType === 2) { userId = item.LinkId break } } if (userId === null) { throw new Error('The user does not exist') } try { res = await request .get('https://www.51nod.com/Challenge/UserIndex') .query({ userId }) } catch (err) { if (err.response && err.response.status === 404) { throw new Error('The user does not exist') } } try { const solvedList = [] res.body.ProblemTables.forEach(table => { table.ProblemInfos.forEach(problem => { if (problem.UserProblemSimplify && problem.UserProblemSimplify.IsAccepted) { solvedList.push(problem.ProblemSimplify.ProblemId.toString()) } }) }) return { solved: res.body.UserStat.ProblemAcceptedCount, submissions: res.body.UserStat.ProblemSubmitCount, solvedList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/nowcoder.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('请输入用户ID') } if (isNaN(username)) { throw new Error('牛客网的输入必须是用户ID(数字格式)') } username = Number(username) + '' let solved = null let submissions = null const solvedList = new Set() let lastSubmissionId = Infinity let page = 1 // eslint-disable-next-line no-constant-condition while (true) { const res = await request .get(`https://ac.nowcoder.com/acm/contest/profile/${username}/practice-coding`) .query({ pageSize: 200, statusTypeFilter: 5, languageCategoryFilter: -1, orderType: 'DESC', page, }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('.null-tip').text().trim() === '用户不存在') { throw new Error('The user does not exist') } try { if (solved == null) { solved = Number($('span:contains("题已通过")').prev().text()) submissions = Number($('span:contains("次提交")').prev().text()) } const newSubmissionId = Number($($('a[href^="/acm/contest/view-submission"]')[0]).text()) if (newSubmissionId === lastSubmissionId) { // 已经读完了列表,开始循环了 break } lastSubmissionId = newSubmissionId // 题目名称有可能重复,用题目编号 $('a[href^="/acm/problem/"]') .map((i, elem) => $(elem).attr('href').slice(13)) .get() .slice(1) // 第一项是 "list" .forEach(solvedList.add, solvedList) } catch (e) { throw new Error('Error while parsing') } page += 1 } return { solved, submissions, solvedList: [...solvedList], } } ================================================ FILE: crawler/crawlers/poj.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .get('http://poj.org/userstatus') .query({user_id: username}) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('title').text() === 'Error -- no user found') { throw new Error('The user does not exist') } if (/

  • Sorry,.* doesn't exist<\/li>/.test(res.text)) { throw new Error('The user does not exist') } try { // function p(id)\n{\n......\np(1000)\np(1001)\n...\n // 这个题目列表是前端渲染的 const acListScript = $('td[rowspan=4] > script').html() // js 不支持零宽后发断言,所以没法加上 (?<=p\() 表达式 const solvedList = acListScript.match(/\d+(?=\)\n)/g) return { solved: Number($('a[href^="status?result=0&user_id="]').text()), submissions: Number($('a[href^="status?user_id="]').text()), solvedList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/sdutoj.js ================================================ const request = require('superagent') async function fetchSDUTOJ(api, data) { const res = await request .post(`https://oj.sdutacm.cn/onlinejudge3/api/${api}`) .set('Content-Type', 'application/json;charset=utf-8') .send(data) if (!(res.ok && res.body && res.body.success)) { throw new Error(`Server Response Error: ${res.status}, code: ${res.body ? res.body.code : ''}`) } return res.body.data } module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const userSearchRes = await fetchSDUTOJ('getUserList', { username, page: 1, order: [['accepted','DESC']], limit: 1000, }) const user = userSearchRes.rows.find(user => user.username === username) if (!user) { throw new Error('The user does not exist') } const userId = user.userId const [statsRes, detailRes] = await Promise.all([ fetchSDUTOJ('getUserProblemResultStats', { userId }), fetchSDUTOJ('getUserDetail', { userId }), ]) return { submissions: detailRes.submitted, solved: detailRes.accepted, solvedList: statsRes.acceptedProblemIds.map(pid => `${pid}`), } } ================================================ FILE: crawler/crawlers/spoj.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res = null try { res = await request .get('http://www.spoj.com/users/' + username) } catch (e) { if (e.message === 'Not Found') { throw new Error('The user does not exist') } else { throw e } } if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('#user-profile-left').length == 0) { throw new Error('The user does not exist') } try { return { submissions: Number($('dt:contains("Solutions submitted") + dd').text().trim()), solved: Number($('dt:contains("Problems solved") + dd').text().trim()), solvedList: $('h4:contains("List of solved classical problems") + table a') .map((i, elem) => $(elem).text().trim()) .get() // 移除表格中的空位 .filter(item => item.length > 0), } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/timus.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const idRes = await request .get('http://acm.timus.ru/search.aspx') .query({ Str: username }) const id$ = cheerio.load(idRes.text) const name = id$('td.name').filter((i, el) => id$(el).text() === username) if (name.length === 0) { throw new Error('The user does not exist') } const res = await request .get('http://acm.timus.ru/' + name.find('a').attr('href')) const $ = cheerio.load(res.text) let solved = null try { solved = Number($('td.author_stats_name:contains("Problems solved") + td').text().match(/\d+/g)[0]) } catch (e) { throw new Error('Error while parsing') } const submissionPageUri = $('a').filter((i, el) => $(el).text() === 'Recent submissions') const submissions = await queryList(submissionPageUri.attr('href')) const solvedList = $('td.accepted > a') .map((i, elem) => $(elem).text().trim()) .get() return { solved, submissions, solvedList, } } /** * 进入当前页面,统计页面上的提交数 * @param uri 要进入的页面的链接 * @returns {Promise} - 提交数 */ async function queryList(uri) { const res = await request .get('http://acm.timus.ru/' + uri) const $ = cheerio.load(res.text) const num = $('td.problem').length if (num === 0) { return 0 } const nextLink = $('a:contains("Next")') if (nextLink.length === 0) { return num } else { return num + await queryList(nextLink.attr('href')) } } ================================================ FILE: crawler/crawlers/uestc.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const res = await request .post('https://acm.uestc.edu.cn/graphql') .send({ operationName: 'ProfileGQL', variables: { username }, query: `query ProfileGQL($username: String!) { user(username: $username) { solved statistics { ac tle ce wa re ole mle solve { pk status } } } } `, }) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } if (res.body.errors) { throw new Error('The user does not exist') } try { const solvedList = res.body.data.user.statistics.solve .filter(x => x.status) .map(x => x.pk) const s = res.body.data.user.statistics return { submissions: s.ac + s.tle + s.ce + s.wa + s.re + s.ole + s.mle, solved: res.body.data.user.solved, solvedList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/uoj.js ================================================ const request = require('superagent') const cheerio = require('cheerio') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } let res try { res = await request .get('https://uoj.ac/user/profile/' + username) } catch (err) { if (err.response && err.response.status === 404) { throw new Error('The user does not exist') } else { throw err } } if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } const $ = cheerio.load(res.text) if ($('.panel-danger:contains("不存在该用户")').length === 1) { throw new Error('The user does not exist') } const submissionPage = await request .get('https://uoj.ac/submissions') .query({ submitter: username, page: 999, }) const $$ = cheerio.load(submissionPage.text) try { const solved = $('h4:contains("AC 过的题目:")') .text() .match(/\d+/)[0] const solvedList = $('a[href^="https://uoj.ac/problem/"]') .map((_, el) => $(el).text()) .toArray() let submissions if ($$('.uoj-content tr td').first().text() === '无') { submissions = 0 } else { const pageNum = parseInt($$('li.active').text()) || 1 submissions = (pageNum - 1) * 10 + $$('.uoj-content tbody tr').length } return { solved: parseInt(solved), submissions, solvedList, } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/crawlers/uva.js ================================================ const request = require('superagent') const prefix = 'https://uhunt.onlinejudge.org' /** uva 的 api 接口:https://uhunt.onlinejudge.org/api * 由于uva不支持分页处理,每次必须把全部信息拉取下来,在前端查询时有可能超过 cors-proxy 的长度限制 * 不过普通用户的话也不会有太多数据 */ module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const uidRes = await request.get(prefix + '/api/uname2uid/' + username) if (uidRes.body === 0) { throw new Error('The user does not exist') } const res = await request .get(prefix + '/api/subs-user/' + uidRes.body) const acSet = new Set() const problemArray = res.body.subs problemArray.forEach(function (element) { if (element[2] === 90) { acSet.add(element[1]) } }) const ohuntRes = await request .post('https://ojhunt.com/api/ohunt/problems/resolve-label') .send({ onlineJudge: 'uva', list: [...acSet], }) return { solved: acSet.size, submissions: problemArray.length, solvedList: Object.values(ohuntRes.body.result), } } ================================================ FILE: crawler/crawlers/uvalive.js ================================================ const request = require('superagent') const prefix = 'https://icpcarchive.ecs.baylor.edu/uhunt' /** * It has the same interface as uva. * * See uva.js for more information. */ module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const uidRes = await request.get(prefix + '/api/uname2uid/' + username) if (uidRes.body === 0) { throw new Error('The user does not exist') } const res = await request .get(prefix + '/api/subs-user/' + uidRes.body) const acSet = new Set() const problemArray = res.body.subs problemArray.forEach(function (element) { if (element[2] === 90) { acSet.add(element[1]) } }) const ohuntRes = await request .post('https://ojhunt.com/api/ohunt/problems/resolve-label') .send({ onlineJudge: 'uvalive', list: [...acSet], }) return { solved: acSet.size, submissions: problemArray.length, solvedList: Object.values(ohuntRes.body.result), } } ================================================ FILE: crawler/crawlers/vjudge.js ================================================ const request = require('superagent') const hostName = 'vjudge.net' // put the object at module level to cache the session let agent = null let config = null const MAX_PAGE_SIZE = 500 /** * vjudge 的设置项 * @typedef vjudgeCrawlerConfig * @type {Object} * @param {String} crawler_login_user - 登录 vjudge 使用的用户名,vj需要一个账户才能访问api * @param {String} crawler_login_password */ /** * vjudge 的爬虫函数 * @param {vjudgeCrawlerConfig} config * @param username 要爬取的用户名 * @returns {Promise} - 见 configReader */ module.exports = async function (localConfig, username) { if (!username) { throw new Error('Please enter username') } config = localConfig if (!agent) { await tryLogin() } // console.log(config) const acSet = new Set() const submissionsByCrawlerName = {} let submissions = 0 const queryObject = { username: username, pageSize: MAX_PAGE_SIZE, maxId: undefined, } // eslint-disable-next-line no-constant-condition while (true) { // requesting ///////////////////////////////////////////////////////////// const res = await agent .get(`https://${hostName}/user/submissions`) .query(queryObject) if (!res.ok) { throw new Error(`Server Response Error: ${res.status}`) } if (res.body.error && /login/.test(res.body.error)) { await tryLogin() continue } // processing ///////////////////////////////////////////////////////////// if (res.body.error && /User .* does not exist/.test(res.body.error)) { throw new Error('The user does not exist') } // console.log(res.body) if (!res.body.data) { throw new Error(`Cannot process vjudge data, body: ${JSON.stringify(res.body)}`) } const problemArray = res.body.data /* delete res.body.data console.log('body except data', res.body) */ // console.log(probremArray) // console.log(probremArray[0][0]) if (problemArray.length === 0) { return 0 } problemArray.forEach(element => { const crawlerName = mapOjName(element[2]) if (!submissionsByCrawlerName[crawlerName]) { submissionsByCrawlerName[crawlerName] = 1 } else { submissionsByCrawlerName[crawlerName] += 1 } if (element[4] === 'AC') { const title = crawlerName + '-' + element[3] acSet.add(title) } }) const total = problemArray.length // vj以id从大到小的顺序返回题目情况,把最后一个题目的id-1作为下次查询的MaxId // id必须要减一,否则最后一题会重复(2018-3-17日最后一次实验) queryObject.maxId = problemArray[total - 1][0] - 1 submissions += total if (total < MAX_PAGE_SIZE) { break } } return { solved: acSet.size, submissions: submissions, solvedList: [...acSet], submissionsByCrawlerName, } } async function tryLogin() { // console.log('try login') // console.log(`login vjudge: "${config.crawler_login_user}" "${config.crawler_login_password}"`) agent = request.agent() .set('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36') let loginStatus try { loginStatus = await agent .post(`https://${hostName}/user/login`) .type('form') .send({ 'username': config.crawler_login_user, 'password': config.crawler_login_password, }) } catch (err) { console.error('vjudge login error:', err) const error = new Error('vjudge login failed') error.innerError = err throw error } // console.log('loginStatus', loginStatus) if (loginStatus.text !== 'success') { console.error('vjudge login not success:', loginStatus.text) throw new Error('vjudge login failed') } // console.log('vjudge login success') } /** * take a oj name in virtual judge and map its name to crawler name * * if name cannot be mapped, return original name * @param {string} nameInVjudge */ function mapOjName(nameInVjudge) { // oj that can map its name to crawler name by changing into lower case const simpleMapOj = new Set([ 'codeforces', 'uva', 'uvalive', 'poj', 'hdu', 'zoj', 'fzu', 'spoj', 'timus', 'csu', // 'hust', 'atcoder', 'aizu', 'codechef', 'nbut', ]) // crawler name map const ojMap = { '': 'NO_NAME', 'LibreOJ': 'loj', 'URAL': 'timus', 'HYSBZ': 'dashiye', // it looks like a typo of vjudge 'EIJudge': 'eljudge', 'Gym': 'codeforces', '51Nod': 'nod', } if (simpleMapOj.has(nameInVjudge.toLowerCase())) { return nameInVjudge.toLowerCase() } else if (nameInVjudge in ojMap) { return ojMap[nameInVjudge] } else { return nameInVjudge } } ================================================ FILE: crawler/crawlers/zoj.js ================================================ const request = require('superagent') module.exports = async function (config, username) { if (!username) { throw new Error('Please enter username') } const submissionRes = await request .get('/api/ohunt/submissions') .query({ oj: 'zoj', $filter: `UserName eq '${username}'`, $count: true, $top: 0, }) const submissions = submissionRes.body['@odata.count'] if (submissions === 0) { throw new Error('The user does not exist') } try { const solvedSet = new Set() let skip = 0 let solvedRes do { solvedRes = await request .get('https://ojhunt.com/api/ohunt/submissions') .query({ oj: 'zoj', $filter: `UserName eq '${username}' and Status eq 'Accepted'`, $skip: skip, $select: 'ProblemLabel', }) solvedRes.body.value.forEach(item => { solvedSet.add(item.ProblemLabel) }) skip += 500 } while (solvedRes.body['@odata.nextLink']) return { solved: solvedSet.size, submissions, solvedList: [...solvedSet], } } catch (e) { throw new Error('Error while parsing') } } ================================================ FILE: crawler/index.js ================================================ require('./lib/globalProxy') const {readMetaConfigs} = require('./lib/configReader') const {generateBrowserCrawlerFunctions, generateServerCrawlerFunctions} = require('./lib/functionGenerator') module.exports = { readMetaConfigs, generateServerCrawlerFunctions, generateBrowserCrawlerFunctions, } ================================================ FILE: crawler/lib/__mocks__/configReader.js ================================================ exports.readCrawlerConfigs = async () => { return [ { name: 'crawler1', meta: { title: 'Crawler1', description: 'Description1', url: 'http://www.c1.com', }, }, { name: 'crawler2', meta: { title: 'Crawler2', }, custom_data: 'CustomData', }, { name: 'crawler_for_server', meta: { title: 'CrawlerForServer', }, server_only: true, }, ] } exports.readMetaConfigs = async () => { return { crawler1: { title: 'Crawler1', description: 'Description1', url: 'http://www.c1.com', }, crawler2: { title: 'Crawler2', }, crawler_for_server: { title: 'CrawlerForServer', }, } } ================================================ FILE: crawler/lib/configReader.js ================================================ /* 用于读取用户的爬虫设置,用在前端时,本模块只在编译期间运行,将会返回给用户设置信息 */ const fs = require('fs').promises const yml = require('js-yaml') const join = require('path').join const _ = require('lodash') // require 的路径是相对源文件路径的,而 fs 模块的路径是相对于工作路径的,必须使用 __dirname 来转换 const configPath = join(__dirname, '../config.yml') // 环境变量的前缀 const envConfigPrefix = 'ACM_STATISTICS_CRAWLER_ENV__' /** * 从一个表示环境变量的键值对里面读取配置,将配置合并到 config 中。 * 将使用 _.set 来合并数据 * * 举例:对于环境变量 ACM_STATISTICS_CRAWLER_ENV__a__b__1__c = 12 和配置对象 {a:{b:[{}],d:333}}, * 结果为 {a:{b:[{},{c:12}],d:333}} * * 环境变量的值将使用 JSON.parse 来处理,因此可以使用任意 json 中存在的类型。 * 如果需要传入字符串,需要使用类似于 ACM_STATISTICS_CRAWLER_ENV__a__b__1__c = "12" * 或者 ACM_STATISTICS_CRAWLER_ENV__a = "{asdf}" 这样的形式 * * @param {object} config * @param {object.} env */ exports.mergeConfigWithEnv = (config, env) => { _.forEach(env, (value, key) => { if (_.startsWith(key, envConfigPrefix)) { const keyStr = key.slice(envConfigPrefix.length) _.set(config, _.split(keyStr, '__'), JSON.parse(value)) } else { // pass } }) } /** * 从文件读取配置并和环境变量合并 * * @return {Promise} */ exports.readConfigs = async () => { const config = yml.load(await fs.readFile(configPath, 'utf-8')) exports.mergeConfigWithEnv(config, process.env) return config } /** * 获取爬虫的所有配置 * @return {Promise>} */ exports.readCrawlerConfigs = async () => { const config = await exports.readConfigs() return _.map(config.crawler_order, name => _.assign({name: name}, config.crawlers[name])) } /** * 返回一个对象,其中key是爬虫名,value是一个Object,包含爬虫的元信息 * @returns {Promise>} */ exports.readMetaConfigs = async () => { const config = await exports.readConfigs() let ret = {} for (let name of config.crawler_order) { ret[name] = config.crawlers[name].meta } return ret } ================================================ FILE: crawler/lib/functionGenerator.js ================================================ /* 用于生成爬虫函数,用在前端时,本模块只在编译期间运行,返回给用户已经注入好设置信息的爬虫函数 */ const configReader = require('./configReader') const fs = require('fs').promises const _ = require('lodash') const join = require('path').join /** * 爬虫函数的返回类型 * @typedef {Object} CrawlerReturns * @type {Object} * @property {Number} solved - 用户通过的题量 * @property {Number} submissions - 用户的总提交量 * @property {Array|undefined|null} solvedList - 用户通过的题目列表 */ /** * 为服务端返回的爬虫函数 * @typedef {Function} ServerCrawlerFunction * @type {Function} * @param {String} username - 要爬取的用户名 * @returns {Promise} */ /** * Wrap the result from crawler to make sure it has right format * @param {string} promiseExpression the string of express that evaluate to the promise * of the result * @returns {string} */ exports.crawlerWrapper = promiseExpression => { return `${promiseExpression} .then(res => { ${checkNumberFormat('res.solved')} ${checkNumberFormat('res.submissions')} if (res.solvedList !== null && res.solvedList !== undefined && !(res.solvedList instanceof Array)) { throw new Error('The crawler returned wrong format result. It can be a bug in crawler.') } return res })` function checkNumberFormat(field) { return ` if (!Number.isInteger(${field}) || ${field} < 0) { throw new Error('The crawler returned wrong format result. It can be a bug in crawler.') }` } } /** * 为服务器端返回爬虫函数,会从config.yml读取信息,并返回一个对象 * * @returns {Promise>} */ exports.generateServerCrawlerFunctions = async () => { const config = await configReader.readCrawlerConfigs() const ret = {} for (let item of config) { if (!item.name) { continue } const crawlerConfig = { env: 'server', } _.assign(crawlerConfig, item) // eslint-disable-next-line no-unused-vars const crawlerFunc = require(`../crawlers/${item.name}.js`) ret[item.name] = eval(`username => ${exports.crawlerWrapper('crawlerFunc(crawlerConfig, username)')}`) } return ret } /** * 为客户端返回的爬虫函数的源代码字符串。 * 如果爬虫是server_only的,将会返回一个带 axios 请求的函数, * 函数将会向服务器发起请求,让服务器进行爬取; * 如果爬虫不是server_only的,返回已经注入了设置信息的爬虫源代码。 * 请注意:本函数返回的对象中不含有“函数”,只有“函数的源代码”。 * 需要使用eval或者将源代码拼接进源码文件中使用。 * @typedef {Function} ClientCrawlerFunction * @type {Function} * @param {String} username - 要爬取的用户名 * @returns {Promise} */ /** * 返回给前端使用的爬虫函数,会从 config.yml 读取配置信息,装配配置信息并返回。 * 设置了 server_only 的爬虫会返回一个 axios 的请求 * * @returns {Promise>} */ exports.generateBrowserCrawlerFunctions = async () => { // 生成从服务器端进行查询的代码 const resolveServerQuery = (crawlerName) => _.trim(` new Promise((resolve, reject) => { superagent.get('/api/crawlers/${crawlerName}/'+username) .then(response => { // console.log(response) if (response.body.error) { reject(new Error(response.body.message)) } else { resolve(response.body.data) } }) .catch(err => { // console.error(err) if (err.response && err.response.body && err.response.body.message) { // 服务端的爬虫报的错 reject(new Error(err.response.body.message)) } else { //网络错误或其他错误 reject(err) } }) }) `) const config = await configReader.readCrawlerConfigs() const ret = {} for (let item of config) { if (!item.name) { continue } if (item.server_only) { ret[item.name] = ` (username) => { return ${resolveServerQuery(item.name)} } ` } else { const crawlerFuncStr = await fs.readFile(join(__dirname, `../crawlers/${item.name}.js`), 'utf-8') const crawlerConfig = { env: 'browser', } _.assign(crawlerConfig, item) ret[item.name] = ` (username) => { let module = {exports: {}} ;(function(module, exports) { ${crawlerFuncStr} })(module, module.exports) return ${exports.crawlerWrapper(`module.exports(${JSON.stringify(crawlerConfig)}, username)`)} .catch(err => { if (err.response || err.url) { // 有response字段说明这是由 superagent 抛出的异常 // 有url字段(而没有 response字段)说明是cors的异常 return ${resolveServerQuery(item.name)} } else { throw err } }) } ` } } return ret } ================================================ FILE: crawler/lib/globalProxy.js ================================================ /* 根据环境变量设置 superagent 的 proxy 必须在所有的 superagent 之前引入 */ if (process.env.http_proxy) { const superagent = require('superagent') const request = require('superagent-proxy')(superagent) const OrigRequest = request.Request superagent.Request = function RequestWithAgent(method, url) { console.log(`use stubbed ${method} proxy in url: ${url}`) const req = new OrigRequest(method, url) return req.proxy(process.env.http_proxy) } } // redirect OHunt request (only work on crawler-api-backend) const superagent = require('superagent') const _ = require('lodash') const getFunc = superagent.get superagent.get = url => { if (_.startsWith(url, '/api/ohunt')) { return getFunc('http://ohunt' + url) } else { return getFunc(url) } } ================================================ FILE: crawler/package.json ================================================ { "name": "crawler", "description": "存放所有爬虫", "main": "index.js", "scripts": { "test": "jest", "lint": "eslint --ext .js --ignore-path .gitignore .", "lintfix": "eslint --fix --ext .js --ignore-path .gitignore ." }, "dependencies": { "cheerio": "^1.0.0-rc", "js-yaml": "^4.0.0", "lodash": "^4.17.20", "superagent": "^8.0.0", "superagent-proxy": "^3.0.0" }, "devDependencies": { "eslint": "8.57.1", "eslint-plugin-jest": "27.9.0", "eslint-plugin-lodash": "7.4.0", "jest": "29.7.0", "memfs": "3.5.3", "nock": "13.5.6", "typescript": "5.9.3" }, "jest": { "testPathIgnorePatterns": [ "/node_modules/" ], "testEnvironment": "node", "coverageDirectory": "./coverage/", "collectCoverage": true } } ================================================ FILE: crawler/release.Dockerfile ================================================ ARG CRAWLER_BASE_IMAGE ARG NODE_BASE_IMAGE FROM ${CRAWLER_BASE_IMAGE} AS base RUN rm -rf node_modules FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY package.json pnpm-lock.yaml ./ RUN pnpm install --only=production COPY --from=base /var/project . ================================================ FILE: crawler-api-backend/.dockerignore ================================================ # dependencies node_modules # logs npm-debug.log # codecov coverage # docker .dockerignore base.Dockerfile release.Dockerfile # make Makefile # 日志文件 /logs/ ================================================ FILE: crawler-api-backend/.eslintrc.js ================================================ module.exports = { root: true, env: { browser: false, node: true, es6: true, 'jest/globals': true, }, parserOptions: { parser: 'babel-eslint', ecmaVersion: 8, }, extends: [ 'eslint:recommended', // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 'plugin:lodash/recommended', 'plugin:jest/recommended', ], // required to lint *.vue files plugins: [ 'lodash', 'jest', ], // add your custom rules here rules: { 'semi': [2, 'never'], 'no-console': 'off', 'vue/max-attributes-per-line': 'off', // 行末逗号:在多行中强制最后一项有逗号,单行中强制没有 'comma-dangle': ['error', 'always-multiline'], 'quotes': ['error', 'single'], // 服务端不用管这个 'lodash/import-scope': 'off', // 这个方法的可读性太低了 'lodash/matches-prop-shorthand': 'off', }, } ================================================ FILE: crawler-api-backend/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # next.js build output .next # 日志文件 /logs/ ================================================ FILE: crawler-api-backend/Makefile ================================================ ## makefile for crawler api backend include ../build/share.mk help: @echo run \"make help\" in root directory to get help .crawler: cd ../crawler && $(MAKE) build .node-base: cd ../build && $(MAKE) -f node-base.mk build .base: .node-base .crawler docker build . \ -f base.Dockerfile \ -t $(CrawlerApiBackendBaseTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) \ --build-arg CRAWLER_IMAGE=$(CrawlerTag) build: .base .crawler docker build . \ -f release.Dockerfile \ -t $(CrawlerApiBackendTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) \ --build-arg BACKEND_BASE_IMAGE=$(CrawlerApiBackendBaseTag) \ --build-arg CRAWLER_IMAGE=$(CrawlerTag) test: .base docker run --rm -t $(CrawlerApiBackendBaseTag) pnpm test run: .base docker run $(run-args) $(CrawlerApiBackendBaseTag) $(run-cmd) clean: docker image rm $(CrawlerApiBackendTag) $(CrawlerApiBackendBaseTag); true test-ci: .base docker run --rm \ -v "$(CURDIR)/coverage:/var/project/coverage" \ $(CrawlerApiBackendBaseTag) \ pnpm test -- --colors ================================================ FILE: crawler-api-backend/README.md ================================================ crawler-api-backend === 这是一个爬虫微服务。在这里可以通过 Rest API 调用 `crawler` 文件夹中的所有爬虫。 这些爬虫都是在服务器上运行的,因此您可以在任何地方使用本 API。 ## API ### GET `/api/crawlers/swagger.json` 返回 swagger 的 json 形式的文档。文档在 [swagger.json](./swagger.json) 中编辑。 如果 `swagger.json` 中的描述与本文档有出入,以 `swagger.json` 中的为准。 ### GET `/api/crawlers/:type/:username` 查询某个OJ上的用户题量 #### 参数 - type: OJ类型,只包括在 `/crawler/config.yml` 中定义的类型 - username: 要查询的用户的用户名 #### 成功返回 - 状态码: 200 ```json { "error": false, "data": { "solved": 1, "submissions": 2 } } ``` #### 失败返回 - 状态码: 400 ```json { "error": true, "message": "错误信息" } ``` ### GET `/api/crawlers` 返回所有支持查询的 OJ #### 成功返回 ```json { "error": false, "data": { "poj": { "title": "POJ", "description": "", "url": "http://poj.org/" }, "vjudge": {}, "...其他OJ": {} } } ``` ## 部署 - 使用 `pnpm start` 运行 - 在运行之后会监视 `localhost:80` ================================================ FILE: crawler-api-backend/__mocks__/crawler.js ================================================ /* eslint-disable no-undef */ module.exports = { readMetaConfigs: async () => { return { crawler1: { title: 'Crawler1', description: 'Description1', url: 'http://www.c1.com', }, crawler2: { title: 'Crawler2', }, crawler_for_server: { title: 'CrawlerForServer', }, } }, generateServerCrawlerFunctions: async () => { const crawlerFunc = username => { if (username === 'reject') { throw new Error('The user does not exist') } else { return { solved: 101, submissions: 230, } } } const ret = {} for (let item of ['crawler1', 'crawler2', 'crawler_for_server']) { ret[item] = crawlerFunc } return ret }, } ================================================ FILE: crawler-api-backend/__test__/__snapshots__/apiRouter.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`/api/crawlers/swagger.json swagger should match snapshot 1`] = ` { "definitions": { "CrawlerMeta": { "description": "Crawler's metadata", "properties": { "description": { "description": "Description of the crawler", "type": "string", }, "title": { "description": "Title of the crawler", "type": "string", }, "url": { "description": "Target website of the crawler", "type": "string", }, }, "type": "object", }, "Error": { "properties": { "error": { "description": "true", "type": "boolean", }, "message": { "type": "string", }, }, "type": "object", }, "Ok": { "properties": { "data": { "$ref": "#/definitions/UserState", }, "error": { "description": "false", "type": "boolean", }, }, "type": "object", }, "UserState": { "description": "User performance", "properties": { "solved": { "format": "int64", "type": "integer", }, "solvedList": { "description": "A list which contains the problem the user passes. For non-virtual judge, only problem id is included. If the crawler targets a virtual judge, each problem follows the format of \`crawlerName-problemId\`", "items": { "type": "string", }, "type": "array", }, "submissions": { "format": "int64", "type": "integer", }, "submissionsByCrawlerName": { "additionalProperties": { "type": "number", }, "default": null, "description": "If the crawler is virtual_judge, this field contains its submission count divided by crawler name.", "type": "object", }, }, "type": "object", }, }, "externalDocs": { "description": "Other documents", "url": "https://github.com/Liu233w/acm-statistics/blob/master/crawler-api-backend/README.md", }, "info": { "description": "A crawler microservice that allows users to invoke all crawlers supported by the website. All crawlers run on server.", "title": "crawler-api-backend", "version": "1.0.0", }, "paths": { "/api/crawlers/": { "get": { "consumes": [ "application/json", ], "description": "", "produces": [ "application/json", ], "responses": { "200": { "description": "success", "schema": { "properties": { "data": { "additionalProperties": { "$ref": "#/definitions/CrawlerMeta", }, "description": "name of the crawler", "type": "object", }, "error": { "description": "false", "type": "boolean", }, }, "type": "object", }, }, }, "summary": "Return all supported OJs", }, }, "/api/crawlers/{type}/{username}": { "get": { "consumes": [ "application/json", ], "parameters": [ { "description": "Type of the OJ. Only the type defined in \`/crawler/config.yml\` are included.", "in": "path", "name": "type", "required": true, "type": "string", }, { "in": "path", "name": "username", "required": true, "type": "string", }, ], "produces": [ "application/json", ], "responses": { "200": { "description": "successful", "schema": { "$ref": "#/definitions/Ok", }, }, "400": { "description": "all other failures", "schema": { "$ref": "#/definitions/Error", }, }, }, "summary": "Query the performance of a user on certain OJ", }, }, }, "swagger": "2.0", } `; ================================================ FILE: crawler-api-backend/__test__/apiRouter.test.js ================================================ // 在 require 的时候程序会直接 require 爬虫,如果在 beforeAll 里面 mock 的话就晚了 jest.mock('crawler') const request = require('supertest') const app = require('../app').callback() test('/api/crawlers/swagger.json swagger should match snapshot', async () => { const res = await request(app).get('/api/crawlers/swagger.json') .expect(200) expect(res.body).toMatchSnapshot() }) test('/api/crawlers should return crawler list', async () => { await request(app) .get('/api/crawlers') .expect(200, { error: false, data: { crawler1: { title: 'Crawler1', description: 'Description1', url: 'http://www.c1.com', }, crawler2: { title: 'Crawler2', }, crawler_for_server: { title: 'CrawlerForServer', }, }, }) }) describe('/api/crawlers/:type/:username', () => { it('should work correctly', async () => { await request(app) .get('/api/crawlers/crawler1/user') .expect(200, { error: false, data: { solved: 101, submissions: 230, }, }) }) it('should return 400 when crawler does not exist', async () => { await request(app) .get('/api/crawlers/notExist/user') .expect(400, { error: true, message: 'Crawler of the oj does not exist', }) }) it('should return error when crawler return error', async () => { await request(app) .get('/api/crawlers/crawler1/reject') .expect(400, { error: true, message: 'The user does not exist', }) }) }) test('should return 404 when visiting url that does not exist', async () => { await request(app) .get('/notExists') .expect(404, { error: true, message: '404 Not Found', }) }) ================================================ FILE: crawler-api-backend/apiRouter.js ================================================ const Router = require('koa-router') const _ = require('lodash') const {readMetaConfigs, generateServerCrawlerFunctions} = require('crawler') let crawlers generateServerCrawlerFunctions() .then(res => crawlers = res) let crawlerMeta readMetaConfigs() .then(res => crawlerMeta = res) const swagger = require('./swagger.json') const router = new Router() router.get('/api/crawlers/swagger.json', async (ctx) => { ctx.response.type = 'application/json' ctx.response.state = 200 ctx.response.body = JSON.stringify(swagger) }) router.get('/api/crawlers/:type/:username', async (ctx) => { const ojFunc = crawlers[ctx.params.type] if (!_.isFunction(ojFunc)) { throw new Error('Crawler of the oj does not exist') } ctx.rest(await ojFunc(ctx.params.username)) }) router.get('/api/crawlers', async (ctx) => { ctx.rest(_.mapValues(crawlers, (value, key) => crawlerMeta[key])) }) module.exports = router ================================================ FILE: crawler-api-backend/app.js ================================================ const koa = require('koa') const restHelper = require('./utils/restHelper') const logUtil = require('./utils/logUtil') const rateLimiter = require('./utils/rateLimit') const app = new koa() const apiRouter = require('./apiRouter') const errHelper = async (ctx, next) => { try { await next() } catch (err) { ctx.error(err.message) // re-throw the exception to let it be caught by logUtil throw err } } const notFoundHelper = async (ctx, next) => { await next() if (ctx.response.status === 404) { ctx.error('404 Not Found') ctx.response.status = 404 } } app .use(rateLimiter) .use(logUtil) .use(restHelper) .use(notFoundHelper) .use(errHelper) .use(apiRouter.routes()) .use(apiRouter.allowedMethods()) module.exports = app ================================================ FILE: crawler-api-backend/base.Dockerfile ================================================ ARG CRAWLER_IMAGE ARG NODE_BASE_IMAGE FROM ${CRAWLER_IMAGE} AS crawler FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY --from=crawler /var/project ../crawler COPY package.json pnpm-lock.yaml ./ RUN pnpm install COPY . . ================================================ FILE: crawler-api-backend/config/log.js ================================================ const join = require('path').join //日志根目录 const baseLogPath = join(__dirname, '../logs') //错误日志目录 const errorPath = '/error' //错误日志文件名 const errorFileName = 'error' //错误日志输出完整路径 const errorLogPath = baseLogPath + errorPath + '/' + errorFileName //响应日志目录 const responsePath = '/response' //响应日志文件名 const responseFileName = 'response' //响应日志输出完整路径 const responseLogPath = baseLogPath + responsePath + '/' + responseFileName module.exports = { // 定义两个输出源(appenders) 'appenders': { // 错误日志 'errorOutput': { 'type': 'dateFile', //日志类型 'filename': errorLogPath, //日志输出位置 'alwaysIncludePattern': true, //是否总是有后缀名 'pattern': '-yyyy-MM-dd.log', //后缀,每天创建一个新的日志文件 'path': errorPath, //自定义属性,错误日志的根目录 }, // 响应日志 'responseOutput': { 'type': 'dateFile', 'filename': responseLogPath, 'alwaysIncludePattern': true, 'pattern': '-yyyy-MM-dd.log', 'path': responsePath, }, 'console': { 'type': 'console', }, }, //设置logger名称对应的的日志等级 'categories': { 'error': { 'appenders': ['errorOutput', 'responseOutput', 'console'], 'level': 'ALL', }, 'response': { 'appenders': ['responseOutput', 'console'], 'level': 'ALL', }, 'default': { // 这个目前还不需要 'appenders': ['responseOutput'], 'level': 'ALL', }, }, //设置log输出的根目录 'baseLogPath': baseLogPath, } ================================================ FILE: crawler-api-backend/index.js ================================================ const app = require('./app') // 将 req.ip 设置为 X-Forward-For 中的 ip app.proxy = true console.log('start listening on localhost:80 ...') app.listen(80) ================================================ FILE: crawler-api-backend/package.json ================================================ { "name": "crawler-api-backend", "version": "1.0.0", "description": "OJ爬虫微服务", "main": "index.js", "scripts": { "start": "node index.js", "lint": "eslint --ext .js --ignore-path .gitignore .", "lintfix": "eslint --fix --ext .js --ignore-path .gitignore .", "test": "jest" }, "author": "Liu233w ", "license": "GPL-3.0", "dependencies": { "crawler": "link:../crawler", "koa": "^2.13.1", "koa-ratelimit": "^5.0.1", "koa-router": "^12.0.0", "lodash": "^4.17.21", "log4js": "^6.4.0" }, "devDependencies": { "eslint": "8.57.1", "eslint-plugin-jest": "27.9.0", "eslint-plugin-lodash": "7.4.0", "jest": "29.7.0", "supertest": "6.3.4", "typescript": "5.9.3" }, "jest": { "testEnvironment": "node", "coverageDirectory": "./coverage/", "collectCoverage": true } } ================================================ FILE: crawler-api-backend/release.Dockerfile ================================================ ARG CRAWLER_IMAGE ARG BACKEND_BASE_IMAGE ARG NODE_BASE_IMAGE FROM ${CRAWLER_IMAGE} AS crawler FROM ${BACKEND_BASE_IMAGE} AS base RUN rm -rf node_modules FROM ${NODE_BASE_IMAGE} WORKDIR /var/project COPY --from=crawler /var/project ../crawler COPY package.json pnpm-lock.yaml ./ RUN pnpm install --only=production COPY --from=base /var/project . ENV NODE_ENV production EXPOSE 12001 CMD ["pnpm", "start"] ================================================ FILE: crawler-api-backend/swagger.json ================================================ { "swagger": "2.0", "info": { "description": "A crawler microservice that allows users to invoke all crawlers supported by the website. All crawlers run on server.", "version": "1.0.0", "title": "crawler-api-backend" }, "paths": { "/api/crawlers/": { "get": { "summary": "Return all supported OJs", "description": "", "consumes": [ "application/json" ], "produces": [ "application/json" ], "responses": { "200": { "description": "success", "schema": { "type": "object", "properties": { "error": { "type": "boolean", "description": "false" }, "data": { "type": "object", "description": "name of the crawler", "additionalProperties": { "$ref": "#/definitions/CrawlerMeta" } } } } } } } }, "/api/crawlers/{type}/{username}": { "get": { "summary": "Query the performance of a user on certain OJ", "consumes": [ "application/json" ], "produces": [ "application/json" ], "parameters": [ { "in": "path", "name": "type", "required": true, "type": "string", "description": "Type of the OJ. Only the type defined in `/crawler/config.yml` are included." }, { "in": "path", "name": "username", "required": true, "type": "string" } ], "responses": { "200": { "description": "successful", "schema": { "$ref": "#/definitions/Ok" } }, "400": { "description": "all other failures", "schema": { "$ref": "#/definitions/Error" } } } } } }, "definitions": { "CrawlerMeta": { "type": "object", "description": "Crawler's metadata", "properties": { "title": { "type": "string", "description": "Title of the crawler" }, "description": { "type": "string", "description": "Description of the crawler" }, "url": { "type": "string", "description": "Target website of the crawler" } } }, "UserState": { "type": "object", "description": "User performance", "properties": { "solved": { "type": "integer", "format": "int64" }, "submissions": { "type": "integer", "format": "int64" }, "solvedList": { "type": "array", "description": "A list which contains the problem the user passes. For non-virtual judge, only problem id is included. If the crawler targets a virtual judge, each problem follows the format of `crawlerName-problemId`", "items": { "type": "string" } }, "submissionsByCrawlerName": { "type": "object", "default": null, "description": "If the crawler is virtual_judge, this field contains its submission count divided by crawler name.", "additionalProperties": { "type": "number" } } } }, "Ok": { "type": "object", "properties": { "error": { "type": "boolean", "description": "false" }, "data": { "$ref": "#/definitions/UserState" } } }, "Error": { "type": "object", "properties": { "error": { "type": "boolean", "description": "true" }, "message": { "type": "string" } } } }, "externalDocs": { "description": "Other documents", "url": "https://github.com/Liu233w/acm-statistics/blob/master/crawler-api-backend/README.md" } } ================================================ FILE: crawler-api-backend/utils/logUtil.js ================================================ const log4js = require('log4js') const fs = require('fs') const _ = require('lodash') const logConfig = require('../config/log') // 加载配置文件 log4js.configure(logConfig) // 将配置添加到log4js中 let logUtil = {} // 确定目录是否存在,如果不存在则创建目录 const createPath = (pathStr) => { if (!fs.existsSync(pathStr)) { fs.mkdirSync(pathStr) console.log(`createPath:${pathStr}`) } } // 初始化log相关目录 const initLogPath = () => { //创建log的根目录'logs' if (logConfig.baseLogPath) { //创建log根目录 createPath(logConfig.baseLogPath) //根据不同的logType创建不同的子目录 _.forEach(item => { if (item.path) { createPath(logConfig.baseLogPath + item.path) } }) } } // 自动初始化log输出所需要的目录 initLogPath() const errLogger = log4js.getLogger('error') const resLogger = log4js.getLogger('response') //封装错误日志 logUtil.logError = function (ctx, error, resTime) { if (ctx && error) { errLogger.error(formatError(ctx, error, resTime)) } } //封装响应日志 logUtil.logResponse = function (ctx, resTime) { if (ctx) { resLogger.info(formatRes(ctx, resTime)) } } //格式化响应日志 const formatRes = (ctx, resTime) => { var logText = '' //响应日志开始 logText += '\n' + '*************** response log start ***************' + '\n' //添加请求日志 logText += formatReqLog(ctx.request, resTime) //响应状态码 logText += 'response status: ' + ctx.status + '\n' //响应内容 if (process.env.NODE_ENV === 'development') { logText += 'response body: ' + '\n' + JSON.stringify(ctx.body) + '\n' } else { logText += 'response body: skipped\n' } //响应日志结束 logText += '*************** response log end ***************' + '\n' return logText } //格式化错误日志 const formatError = (ctx, err, resTime) => { var logText = '' //错误信息开始 logText += '\n*************** error log start ***************\n' //添加请求日志 logText += formatReqLog(ctx.request, resTime) //错误名称 logText += `err name:${err.name}\n` //错误信息 logText += `err message:${err.message}\n` //错误详情 logText += `err stack:${err.stack}\n` //错误信息结束 logText += '*************** error log end ***************\n' return logText } //格式化请求日志 const formatReqLog = (req, resTime) => { let logText = '' let method = req.method //访问方法 logText += `request method: ${method}\n` //请求原始地址 logText += `request originalUrl: ${req.originalUrl}\n` //客户端ip logText += `request client ip: ${req.ip}\n` //请求参数 if (method === 'GET') { logText += `request query: ${JSON.stringify(req.query)}\n` } else { logText += `request body: \n${JSON.stringify(req.body)}\n` } //服务器响应时间 logText += `response time:${resTime}\n` return logText } const middleware = async (ctx, next) => { //响应开始时间 const start = new Date() //请求处理完毕的时刻 减去 开始处理请求的时刻 = 处理请求所花掉的时间 let ms try { await next() ms = new Date() - start //记录响应日志 logUtil.logResponse(ctx, ms) } catch (error) { ms = new Date() - start //记录异常日志 logUtil.logError(ctx, error, ms) } } module.exports = middleware ================================================ FILE: crawler-api-backend/utils/rateLimit.js ================================================ const ratelimit = require('koa-ratelimit') const db = new Map() module.exports = ratelimit({ driver: 'memory', db: db, duration: 3 * 60 * 1000, errorMessage: 'Request limit exceed: 30 every 3 minutes', max: 30, }) ================================================ FILE: crawler-api-backend/utils/restHelper.js ================================================ /** * 方便写 rest API 的中间件 */ module.exports = async function (ctx, next) { ctx.rest = function (data) { ctx.response.status = 200 ctx.response.type = 'application/json' ctx.response.body = { error: false, data: data, } } ctx.error = function (message) { ctx.response.status = 400 ctx.response.type = 'application/json' ctx.response.body = { error: true, message: message, } } await next() } ================================================ FILE: e2e/.dockerignore ================================================ /examples /http-mocks node_modules ================================================ FILE: e2e/.eslintignore ================================================ # dependencies /node_modules # cypress example file /examples ================================================ FILE: e2e/.eslintrc.js ================================================ module.exports = { root: true, env: { browser: false, node: true, es6: true, 'cypress/globals': true, }, extends: [ 'eslint:recommended', 'plugin:cypress/recommended', 'plugin:lodash/recommended', ], // required to lint *.vue files plugins: [ 'cypress', 'lodash', ], // add your custom rules here rules: { 'semi': [2, 'never'], 'no-console': 'off', // 行末逗号:在多行中强制最后一项有逗号,单行中强制没有 'comma-dangle': ['error', 'always-multiline'], 'quotes': ['error', 'single'], // 测试端不需要 tree-shaking 'lodash/import-scope': 'off', // 这个方法的可读性太低了 'lodash/matches-prop-shorthand': 'off', 'lodash/prefer-reject': 'off', // cypress 里用不了这个 'lodash/prefer-lodash-method': 'off', }, } ================================================ FILE: e2e/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # next.js build output .next # cypress generation /cypress/screenshots /cypress/videos __diff_output__ ================================================ FILE: e2e/.npmrc ================================================ strict-peer-dependencies=false ================================================ FILE: e2e/Dockerfile ================================================ FROM cypress/base:22.20.0 WORKDIR /e2e RUN npm install --global pnpm@7 COPY package.json pnpm-lock.yaml ./ RUN pnpm install RUN $(pnpm bin)/cypress verify ENV http_proxy=http://localhost:1081 COPY . . ================================================ FILE: e2e/Makefile ================================================ # makefile for e2e include ../build/share.mk # === targets === .PHONY: server .node-base build-http-mocks test open ci .base lint .node-base: cd ../build && $(MAKE) -f node-base.mk build ## 覆盖跟时间和版本有关的变量,用于快照。 server: export VERSION_NUM = 0 server: export BUILD_TIME = 0 server: cd ../build && $(MAKE) -f docker-compose.mk e2e-up ## 等待server就位。后端启动最慢,等它启动就差不多了 wait-server: docker run --rm -t --ipc=host --network=host \ jwilder/dockerize -timeout 30m \ -wait http://localhost:3000/api/services/app/Session/GetCurrentLoginInformations build-http-mocks: .node-base docker build ./http-mocks \ -t $(E2eMockConfigurerTag) \ $(build-args) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) .base: ifeq ($(pull-e2e-base-image),) docker build . \ -t $(E2eBaseTag) \ $(build-args) else docker pull liu233w/acm-statistics-e2e-base docker tag liu233w/acm-statistics-e2e-base $(E2eBaseTag) endif ci: .base docker run --rm -t --ipc=host --network=host \ $(shell printenv | grep -E '^GITHUB' | sed 's/"/\\"/g; s/\(.*\)/"\1"/g; s/^/-e /g') \ -v "$(CURDIR)/cypress:/e2e/cypress" \ $(E2eBaseTag) \ npm test -- --record --key $(CYPRESS_RECORD_KEY) ci-no-record: .base docker run --rm -t --ipc=host --network=host \ $(shell printenv | grep -E '^GITHUB' | sed 's/"/\\"/g; s/\(.*\)/"\1"/g; s/^/-e /g') \ -v "$(CURDIR)/cypress:/e2e/cypress" \ $(E2eBaseTag) \ npm test run: .base docker run $(run-args) $(E2eBaseTag) $(run-cmd) # test 也mount,这样的话就可以查看图片的diff了 test: .base docker run --rm -t --ipc=host --network=host \ -v "$(CURDIR)/cypress:/e2e/cypress" \ $(E2eBaseTag) \ pnpm test open: export http_proxy=http://localhost:1081 open: pnpm start -- --env failOnSnapshotDiff=false update-snapshot: .base docker run --rm -t --ipc=host --network=host \ -v "$(CURDIR)/cypress:/e2e/cypress" \ $(E2eBaseTag) \ pnpm test -- --env updateSnapshots=true upd: .base wait-server update-snapshot test update-html-snapshot clean: docker image rm $(E2eBaseTag) $(E2eMockConfigurerTag); true # ===== 使用 jest 对html进行快照 =========== test-html: .base docker run --rm -t --ipc=host --network=host \ $(E2eBaseTag) pnpm test-html # 更新快照 update-html-snapshot: .base docker run --rm -t --ipc=host --network=host \ -v "$(CURDIR)/__test__:/e2e/__test__" \ $(E2eBaseTag) pnpm test-html --updateSnapshot test-html-ci: .base docker run --rm --ipc=host --network=host \ $(E2eBaseTag) \ pnpm test-html --colors --ci ================================================ FILE: e2e/README.md ================================================ e2e ============================= 用于 E2E 测试的项目。本项目是单独于主项目而运行的。主项目使用类似生产环境的方式部署,用于模拟真实的浏览环境。额外加入了一个 mock server 用于提供一致的外部环境(比如让爬虫请求的外部站点每次返回一样的结果,方便 e2e 测试的断言)。mock server 使用 proxy 的方式实现,用来以侵入性最低的方式来实现mock。 ## 本地启动 - 需要安装 docker - 使用 `make server` 启动项目 - 同时也会启动一个 mock-server 和其配置工具,以便模拟项目的外部环境(主要是模拟爬虫等的外部调用) - 在确保项目完全启动之后,使用 `make open` 启动 cypress。 - 上一步是运行在本地的,因此必须先使用 `pnpm install` 来安装依赖 ## 视觉测试 - 这个项目使用 cypress 来进行视觉测试,测试必须在 docker 中运行,以保证生成的图片一致 - 使用 `make open` 启动的本地项目会忽略视觉测试快照的不一致。`make open` 只是用在编写测试上的。 - 使用 `make test` 在docker中运行全部E2E测试,包括视觉测试 - 使用 `make update-snapshot` 更新本地的视觉测试快照 - 添加开关 `pull-e2e-base-image=1` (比如 `make update-snapshot pull-e2e-base-image=1`) 可直接从 docker hub 拉取构建好的cypress镜像,否则将在本地构建。这样如果因为网络原因导致e2e镜像构建失败,使用此开关可以避免此问题。 ## Mock Server - 项目使用了 mock-server 作为 proxy 来控制外部调用 - `http-mocks` 文件夹里是一个 mock-server 的控制器,用来动态添加mock - `GET http://mock-configurer/路径` 可以激活 `http-mocks/mocks` 文件夹下的相应mock,其中每个js文件可以返回一个object, object可以嵌套,在调用的时候也需要在路径中把它写出来。 - 给 cypress 新增加了一个命令 `mockServer`,用来激活特定的mock。比如 `cy.mockServer('oj/poj/backend_ok')` 将激活 `http-mocks/mocks/oj.js` 文件夹里的 `poj.backend_ok` 函数。 - 因为cypress的task必须要执行完毕。而mock server的某些mock不会结束,因此会阻塞cypress,只能单独拿到另一个项目里。 ## examples - examples 文件夹里是 cypress 自动生成的例子,这个可以留在编写测试的时候进行参考。 ## CI - `make ci` 可以模拟在 CI 中进行测试(使用docker),将会: - 使用 `--report` 参数把报告发送给 `dashboard.cypress.io` - mount .git 文件夹,以便生成报告。 ================================================ FILE: e2e/__test__/pages/__snapshots__/pages_snapshot.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`/ 1`] = ` OJ Analyzer
    OJ Analyzer
    Vuetify.js

    ACM-ICPC 协会

    Welcome to OJ Analyzer

    An online tool to analyze users performance in online judges (coding competition websites)
    Enter AC Statistics

    Guide

    of the query tool.
    Query
    Enter your username and click QUERY. You can save your usernames and use them later.
    Worker Panel
    Use different usernames in different OJs, or multiple usernames in the same OJ.
    Summary
    Click the result badge to view summary. (Login required)
    If you have any questions,
    feel free to discuss on GitHub Start Discussion
    About the website
    This project is the remake of 西北工业大学ACM查询系统 (npuacm.info) . The original version and idea are from Jiduo Zhang.
    About us
    This project is developed and maintained by Shumin Liu and Contributors with ❤. Please check about page for contact information.
    © 2018 - 1970 Shumin Liu and Contributors
    `; exports[`/about 1`] = ` About - OJ Analyzer
    OJ Analyzer
    © 2018 - 1970 Shumin Liu and Contributors
    `; exports[`/history 1`] = ` History - OJ Analyzer
    OJ Analyzer
    Only the latest history per day is saved. You may change your time zone in settings. go to settings
    Id
    10
    Query time
    4/10/2020, 8:00:00 AM
    Solved
    10
    Submissions
    100
    Actions
    Id
    9
    Query time
    4/9/2020, 8:00:00 AM
    Solved
    9
    Submissions
    90
    Actions
    Id
    8
    Query time
    4/8/2020, 8:00:00 AM
    Solved
    8
    Submissions
    80
    Actions
    Id
    7
    Query time
    4/7/2020, 8:00:00 AM
    Solved
    7
    Submissions
    70
    Actions
    Id
    6
    Query time
    4/6/2020, 8:00:00 AM
    Solved
    6
    Submissions
    60
    Actions
    Id
    5
    Query time
    4/5/2020, 8:00:00 AM
    Solved
    5
    Submissions
    50
    Actions
    Id
    4
    Query time
    4/4/2020, 8:00:00 AM
    Solved
    4
    Submissions
    40
    Actions
    Id
    3
    Query time
    4/3/2020, 8:00:00 AM
    Solved
    3
    Submissions
    30
    Actions
    Id
    2
    Query time
    4/2/2020, 8:00:00 AM
    Solved
    2
    Submissions
    20
    Actions
    Id
    1
    Query time
    4/1/2020, 8:00:00 AM
    Solved
    1
    Submissions
    10
    Actions
    © 2018 - 1970 Shumin Liu and Contributors
    `; exports[`/history/{historyId} 1`] = ` History - OJ Analyzer
    OJ Analyzer
    Main username: wwwlsmcom
    SOLVED: 193
    SUBMISSION: 785
    Generated at Sat Jul 11 2020 04:15:22 GMT+0000 (Coordinated Universal Time)
    Crawler
    VJudge (Not Merged)
    Username
    wwwlsmcom
    Solved
    1
    Submission
    1
    Crawler
    CodeChef
    Username
    [wwwlsmcom in VJudge]
    Solved
    1
    Submission
    5
    Crawler
    LeetCode_CN
    Username
    wwwlsmcom
    Solved
    3
    Submission
    9
    Crawler
    Timus (URAL)
    Username
    [wwwlsmcom in VJudge]
    Solved
    2
    Submission
    6
    Crawler
    FZU
    Username
    [wwwlsmcom in VJudge]
    Solved
    1
    Submission
    5
    Crawler
    ICPC Live Archive
    Username
    [wwwlsmcom in VJudge]
    Solved
    1
    Submission
    1
    Crawler
    UVA
    Username
    [wwwlsmcom in VJudge]
    Solved
    11
    Submission
    28
    Crawler
    CodeForces
    Username
    [wwwlsmcom in VJudge]
    Solved
    6
    Submission
    15
    Crawler
    HYSBZ
    Username
    [wwwlsmcom in VJudge]
    Solved
    0
    Submission
    5
    Crawler
    HDU
    Username
    [wwwlsmcom in VJudge], wwwlsmcom
    Solved
    108
    Submission
    385
    Crawler
    POJ
    Username
    [wwwlsmcom in VJudge]
    Solved
    59
    Submission
    325
    WARNINGS
    LeetCode_CN: This crawler does not have a solved list and its result will be directly added to summary.
    © 2018 - 1970 Shumin Liu and Contributors
    `; exports[`/login 1`] = ` OJ Analyzer
    Login
    `; exports[`/register 1`] = ` OJ Analyzer
    Register
    `; exports[`/settings 1`] = ` Settings - OJ Analyzer
    OJ Analyzer
    Sign out
    Logout from this computer.
    Auto save query history
    Change time zone

    You may change your time zone every 24 hours.

    Change Password
    Delete Account
    Delete this account and all data related to it.
    © 2018 - 1970 Shumin Liu and Contributors
    `; exports[`/statistics 1`] = ` Statistics - OJ Analyzer
    OJ Analyzer
    © 2018 - 1970 Shumin Liu and Contributors
    `; ================================================ FILE: e2e/__test__/pages/pages_snapshot.test.js ================================================ const _ = require('lodash') const superagent = require('superagent') const cheerio = require('cheerio') const request = require('superagent') const basePath = 'http://127.0.0.1:3000' async function testPageByPath(path, authToken) { const url = basePath + path console.log(`request url at ${url}`) let request = superagent.get(url) if (authToken) { request = request.set('Cookie', ['OAuthToken=' + authToken]) } const res = await request if (!res.ok) { console.log(`path ${path} does not have a 200 response, the response: `, res) throw Error(`path ${path} does not have a 200 response`) } const $ = cheerio.load(res.text) $('link[href^="/_nuxt/"]').remove() $('script[src^="/_nuxt/"]').remove() // 移除 data-v- 开头的属性和 data-vue-ssr-id 属性 $('*').each((i, el) => { $(el).removeAttr('data-vue-ssr-id') for (let key in $(el).attr()) { // eslint-disable-next-line lodash/prefer-lodash-method if (key.startsWith('data-v-')) { $(el).removeAttr(key) } } }) // remove id="input-XXXX" and for="input-XXXX" $('*').each((i, el) => { for (let key in $(el).attr()) { const value = $(el).attr(key) if (_.startsWith(value, 'input-') && _.includes(['for', 'id'], key)) { $(el).removeAttr(key) } } }) // remove aria-owns="list-XXX" $('*').each((i, el) => { for (let key in $(el).attr()) { const value = $(el).attr(key) if (_.startsWith(value, 'list-') && key === 'aria-owns') { $(el).removeAttr(key) } } }) // 将 css 中的id属性去掉 $('style').each((i, el) => { $(el).html(_.replace($(el).html(), /\[data-v-.*?\]/g, '')) }) // 移除随机数 const storeEl = $(_.filter($('script'), el => /window\.__NUXT__/.test($(el).html()))) storeEl.html(_.replace(storeEl.html(), /,key:\.\d*/g, '')) // remove name="radio-XXX" $('*').each((i, el) => { for (let key in $(el).attr()) { const value = $(el).attr(key) if (_.startsWith(value, 'radio-') && key === 'name') { $(el).removeAttr(key) } } }) // remove aria-labelledby="input-XXX" $('*').each((i, el) => { for (let key in $(el).attr()) { const value = $(el).attr(key) if (_.startsWith(value, 'input-') && key === 'aria-labelledby') { $(el).removeAttr(key) } } }) // remove data-fetch-key="data-v-..." and the value const dataVValues = [] const dataFetchKeyKey = 'data-fetch-key' $('*').each((i, el) => { const value = $(el).attr(dataFetchKeyKey) if (value) { $(el).removeAttr(dataFetchKeyKey) dataVValues.push(value) } }) let html = $(storeEl).html() dataVValues.forEach(v => { html = html.replace(`"${v}":`, '"FETCH_KEY":') }) $(storeEl).html(html) expect($.html()).toMatchSnapshot() } const testPaths = [ '/', '/statistics', '/about', '/login', '/register', ] for (let path of testPaths) { test(path, async () => await testPageByPath(path)) } let authToken // eslint-disable-next-line no-undef beforeAll(async () => { // do login const res = await superagent.post(basePath + '/api/TokenAuth/Authenticate') .send({ userNameOrEmailAddress: 'admin', password: '123qwe', rememberClient: true, }) authToken = res.body.result.accessToken }) const testPathsRequireLogin = [ '/settings', ] for (let path of testPathsRequireLogin) { test(path, () => testPageByPath(path, authToken)) } test('/history', async () => { await request.get(`${basePath}/mock-configurer/history-snapshot/history`) await testPageByPath('/history/', authToken) }) test('/history/{historyId}', async () => { await request.get(`${basePath}/mock-configurer/history-snapshot/summary`) await testPageByPath('/history/1', authToken) }) ================================================ FILE: e2e/cypress/fixtures/example.json ================================================ { "name": "Using fixtures to represent data", "email": "hello@cypress.io", "body": "Fixtures are a great way to mock data for responses to routes" } ================================================ FILE: e2e/cypress/fixtures/history_list-max5.json ================================================ { "result": { "totalCount": 60, "items": [{ "historyId": 10, "summaryId": 10, "creationTime": "2020-04-10T08:00:00Z", "submission": 100, "solved": 10 }, { "historyId": 9, "summaryId": 9, "creationTime": "2020-04-09T08:00:00Z", "submission": 90, "solved": 9 }, { "historyId": 8, "summaryId": 8, "creationTime": "2020-04-08T08:00:00Z", "submission": 80, "solved": 8 }, { "historyId": 7, "summaryId": 7, "creationTime": "2020-04-07T08:00:00Z", "submission": 70, "solved": 7 }, { "historyId": 6, "summaryId": 6, "creationTime": "2020-04-06T08:00:00Z", "submission": 60, "solved": 6 } ] }, "targetUrl": null, "success": true, "error": null, "unAuthorizedRequest": false, "__abp": true } ================================================ FILE: e2e/cypress/fixtures/history_list-skip10.json ================================================ { "result": { "totalCount": 60, "items": [{ "historyId": 20, "summaryId": 20, "creationTime": "2020-04-20T08:00:00Z", "submission": 200, "solved": 20 }, { "historyId": 19, "summaryId": 19, "creationTime": "2020-04-19T08:00:00Z", "submission": 190, "solved": 19 }, { "historyId": 18, "summaryId": 18, "creationTime": "2020-04-18T08:00:00Z", "submission": 180, "solved": 18 }, { "historyId": 17, "summaryId": 17, "creationTime": "2020-04-17T08:00:00Z", "submission": 170, "solved": 17 }, { "historyId": 16, "summaryId": 16, "creationTime": "2020-04-16T08:00:00Z", "submission": 160, "solved": 16 }, { "historyId": 15, "summaryId": 15, "creationTime": "2020-04-15T08:00:00Z", "submission": 150, "solved": 15 }, { "historyId": 14, "summaryId": 14, "creationTime": "2020-04-14T08:00:00Z", "submission": 140, "solved": 14 }, { "historyId": 13, "summaryId": 13, "creationTime": "2020-04-13T08:00:00Z", "submission": 130, "solved": 13 }, { "historyId": 12, "summaryId": 12, "creationTime": "2020-04-12T08:00:00Z", "submission": 120, "solved": 12 }, { "historyId": 11, "summaryId": 11, "creationTime": "2020-04-11T08:00:00Z", "submission": 110, "solved": 11 } ] }, "targetUrl": null, "success": true, "error": null, "unAuthorizedRequest": false, "__abp": true } ================================================ FILE: e2e/cypress/fixtures/history_list.json ================================================ { "result": { "totalCount": 60, "items": [{ "historyId": 10, "summaryId": 10, "creationTime": "2020-04-10T08:00:00Z", "submission": 100, "solved": 10 }, { "historyId": 9, "summaryId": 9, "creationTime": "2020-04-09T08:00:00Z", "submission": 90, "solved": 9 }, { "historyId": 8, "summaryId": 8, "creationTime": "2020-04-08T08:00:00Z", "submission": 80, "solved": 8 }, { "historyId": 7, "summaryId": 7, "creationTime": "2020-04-07T08:00:00Z", "submission": 70, "solved": 7 }, { "historyId": 6, "summaryId": 6, "creationTime": "2020-04-06T08:00:00Z", "submission": 60, "solved": 6 }, { "historyId": 5, "summaryId": 5, "creationTime": "2020-04-05T08:00:00Z", "submission": 50, "solved": 5 }, { "historyId": 4, "summaryId": 4, "creationTime": "2020-04-04T08:00:00Z", "submission": 40, "solved": 4 }, { "historyId": 3, "summaryId": 3, "creationTime": "2020-04-03T08:00:00Z", "submission": 30, "solved": 3 }, { "historyId": 2, "summaryId": 2, "creationTime": "2020-04-02T08:00:00Z", "submission": 20, "solved": 2 }, { "historyId": 1, "summaryId": 1, "creationTime": "2020-04-01T08:00:00Z", "submission": 10, "solved": 1 } ] }, "targetUrl": null, "success": true, "error": null, "unAuthorizedRequest": false, "__abp": true } ================================================ FILE: e2e/cypress/fixtures/poj_notExist.txt ================================================ Error Error Occurred

    • Sorry,Frkfe932fbcv09b doesn't exist

    Home Page   Go Back  To top


    All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
    Any problem, Please Contact Administrator

    ================================================ FILE: e2e/cypress/fixtures/poj_ok.txt ================================================ User -- vjudge5
    Online JudgeProblem SetAuthorsOnline ContestsUser
    Web Board
    Home Page
    F.A.Qs
    Statistical Charts
    Problems
    Submit Problem
    Online Status
    Prob.ID:
    Register
    Update your info
    Authors ranklist
    Current Contest
    Past Contests
    Scheduled Contests
    Award Contest
    User ID:
    Password:
      Register
    vjudge5--黄汉升 @ vjudge.net
    Last Loginned Time:2019-03-31 13:43:20.0

    Compare and
    Rank: 18 Solved Problems List
    Solved: 1968
    Submissions: 277562
    School:
    Email:

    Home Page   Go Back  To top


    All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
    Any problem, Please Contact Administrator

    ================================================ FILE: e2e/cypress/fixtures/summary_hdu.txt ================================================ User Status
    F.A.Q
    Hand In Hand
    Online Acmers
    Forum | Discuss
    Statistical Charts
    Problem Archive
    Realtime Judge Status
    Authors Ranklist
     
         C/C++/Java Exams     
    ACM Steps
    Go to Job
    Contest LiveCast
    ICPC@China
    Best Coder beta
    VIP | STD Contests
    Virtual Contests
        DIY | Web-DIY beta
    Recent Contests
    Author ID 
    Password 
     Register new ID

    wwwlsmcom

    from: 西北工业大学    registered on 2015-09-30

    This fellow left nothing here.


    Nationality
    Rank50375
    Problems Submitted35
    Problems Solved34
    Submissions72
    Accepted35

    Last submissions
    Last accepted submissions


    List of solved problems


    List of unsolved problems



    Hangzhou Dianzi University Online Judge 3.0
    Copyright © 2005-2020 HDU ACM Team. All Rights Reserved.
    Designer & Developer : Wang Rongtao LinLe GaoJie GanLu
    Total 0.015600(s) query 33, Server time : 2020-04-23 15:08:03, Gzip enabled
    ================================================ FILE: e2e/cypress/fixtures/summary_leetcode.txt ================================================ {"data":{"userProfileUserQuestionSubmitStats":{"acSubmissionNum":[{"difficulty":"EASY","count":1},{"difficulty":"MEDIUM","count":1},{"difficulty":"HARD","count":0}],"totalSubmissionNum":[{"difficulty":"EASY","count":2},{"difficulty":"MEDIUM","count":2},{"difficulty":"HARD","count":0}]}}} ================================================ FILE: e2e/cypress/fixtures/summary_vjudge.txt ================================================ {"error":false,"data":{"solved":161,"submissions":704,"solvedList":["poj-2394","poj-1011","poj-2251","poj-1426","poj-1330","hdu-4825","hdu-5090","hdu-5091","hdu-5095","hdu-5099","poj-3126","poj-1321","hdu-1879","hdu-1233","uva-10034","codeforces-415A","codeforces-369A","hdu-2222","poj-3630","hdu-1711","poj-3461","hdu-1878","poj-1094","uva-10033","uva-10020","hdu-1106","hdu-1166","hdu-1251","hdu-1506","poj-3061","poj-2823","hdu-2149","uva-10037","uva-10010","hdu-1527","hdu-3791","hdu-2176","hdu-1849","hdu-2177","timus-1009","hdu-1847","hdu-1846","poj-1988","poj-1611","poj-2955","poj-3280","hdu-5115","hdu-1003","hdu-1421","hdu-1087","hdu-1159","poj-2533","poj-1088","poj-1163","uva-442","hdu-2141","poj-1064","poj-3104","poj-2456","poj-2785","poj-1700","hdu-1114","hdu-2602","poj-2376","poj-1328","hdu-2037","codeforces-330B","timus-1792","hdu-1198","uva-10152","fzu-1327","poj-3009","poj-1564","poj-1562","poj-2488","poj-1111","poj-3984","poj-1915","poj-1979","poj-3278","codeforces-436B","codeforces-393A","codeforces-387A","hdu-2049","hdu-2045","hdu-2007","hdu-2054","hdu-2031","LightOJ-1303","hdu-1263","hdu-1004","hdu-1896","hdu-1873","poj-2259","uva-10935","poj-1363","codechef-DRAGNXOR","UVALive-4648","hdu-4006","uva-10305","hdu-2629","uva-548","hdu-5670","hdu-1221","hdu-5533","hdu-4472","hdu-5612","hdu-1045","uva-10115","hdu-1023","hdu-3823","hdu-2303","poj-1007","poj-2362","hdu-1240","poj-2243","poj-1019","hdu-1030","poj-1023","hdu-1015","hdu-4864","hdu-1016","poj-2503","poj-2051","poj-3190","poj-2782","poj-2393","poj-1456","hdu-1515","hdu-4310","hdu-1789","hdu-1022","hdu-1018","hdu-2057","poj-2833","hdu-2050","hdu-2051","hdu-1009","poj-2463","hdu-1075","poj-2196","hdu-1002","poj-2242","poj-3672","poj-1013","poj-1012","poj-1001","poj-2769","poj-3006","poj-2272","hdu-1013","hdu-1027","hdu-1029","hdu-1019","hdu-1031","hdu-1035","hdu-1228","hdu-1225","hdu-1033","hdu-1034","hdu-1032"],"submissionsByCrawlerName":{"poj":325,"hdu":313,"uva":28,"codeforces":15,"timus":6,"fzu":5,"LightOJ":1,"codechef":5,"UVALive":1,"dashiye":5}}} ================================================ FILE: e2e/cypress/integration/application/auth-redirect.spec.js ================================================ describe('Redirect when visiting un-permitted pages', () => { it('can redirect to /login when visiting /settings without being logined', () => { cy.visit('/settings') cy.shouldHaveUri('/login') }) it('can redirect to /settings when visiting /login and being logined', () => { cy.login('admin') cy.log('---- TEST ----') cy.visit('/login') cy.shouldHaveUri('/settings') }) }) ================================================ FILE: e2e/cypress/integration/application/auto-save-history.spec.js ================================================ // eslint-disable-next-line Cypress.on('uncaught:exception', (err, runnable) => { // returning false here prevents Cypress from // failing the test // Stop the uncaught network error return false }) beforeEach(() => { cy.intercept( 'https://cors.ojhunt.com/http://acm.hdu.edu.cn/userstatus.php?user=wwwlsmcom', { fixture: 'summary_hdu.txt' }).as('summary_hdu') cy.intercept('POST', '/api/services/app/QueryHistory/SaveOrReplaceQueryHistory') .as('save-history') }) function specs(enterStatistics) { describe('at default', () => { it('saves history automatically', () => { cy.registerAndGetUsername() enterStatisticsAndQuery(enterStatistics) cy.wait('@save-history') cy.log('assert') cy.visit('/history') cy.get('i.mdi-delete').should('have.length', 1) }) }) describe('set settings to not save history', () => { let username before(() => { cy.registerAndGetUsername().then(u => username = u) cy.clearCookies() }) it('should change settings successfully', () => { cy.login(username) cy.visit('/settings') cy.contains('Auto save query history').parents('.v-card').within(() => { cy.get('input[value="false"]').click({ force: true }) cy.get('button').contains('save', { matchCase: false }).click() cy.matchImageSnapshot() }) }) it('should not auto save history', () => { cy.login(username) enterStatisticsAndQuery(enterStatistics) cy.log('assert') cy.visit('/history') cy.get('i.mdi-delete').should('have.length', 0) }) it('should go to summary when click view summary', () => { cy.login(username) enterStatisticsAndQuery(enterStatistics) cy.contains('/ submission', { matchCase: false }).click() cy.location('pathname').should('satisfy', val => val.startsWith('/history/')) }) it('should have one record in history', () => { cy.login(username) cy.visit('/history') cy.get('i.mdi-delete').should('have.length', 1) }) }) } describe('when directly enter statistics page', () => specs(() => { cy.visit('/statistics') })) describe('when enter statistics page from other page', () => specs(() => { cy.visit('/about') cy.get('i.mdi-menu').parents('button').click() cy.contains('statistics', { matchCase: false }).click() })) function enterStatisticsAndQuery(enterFunc) { cy.log('save a history') enterFunc() cy.get('div[title="HDU"]').parents('.worker').within(() => { cy.get('div:contains("Username") input').type('wwwlsmcom') // wait for debounce to be executed // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(500) cy.get('button i.mdi-refresh').click() cy.wait('@summary_hdu') cy.contains('34') cy.contains('72') }) } ================================================ FILE: e2e/cypress/integration/application/default-query.spec.js ================================================ describe('Saving default query to cookie when user does not login.', () => { it('can work correctly', () => { // arrange cy.visit('/statistics') cy.get('.v-input:contains("Set all usernames") input').should('have.value', '') cy.get('.worker:contains("CodeForces") input').should('have.value', '') cy.get('.v-input:contains("Set all usernames") input').type('main-name') // wait for other workers to update cy.get('.worker:contains("CodeForces") input').should('have.value', 'main-name') cy.get('.worker:contains("HDU") input').clear() cy.get('.worker:contains("HDU") input').type('user1') cy.get('.worker:contains("POJ") input').clear() // act cy.contains('save username').click() cy.contains('Success!') cy.reload() cy.get('.worker:contains("HDU") input').should('have.value', 'user1') cy.get('.worker:contains("POJ") input').should('have.value', '') cy.get('.v-input:contains("Set all usernames") input').should('have.value', 'main-name') }) }) describe('Saving usernames to server when user has logined.', () => { let username before(() => { cy.registerAndGetUsername().then(u => { username = u }) cy.clearCookies() }) it('can save usernames', () => { cy.login(username) cy.visit('/statistics') cy.get('.v-input:contains("Set all usernames") input').should('have.value', '') cy.get('.worker:contains("CodeForces") input').should('have.value', '') cy.get('.v-input:contains("Set all usernames") input').type('main-name') // wait for other worker to update cy.get('.worker:contains("CodeForces") input').should('have.value', 'main-name') cy.get('.worker:contains("HDU") input').clear() cy.get('.worker:contains("HDU") input').type('user1') cy.get('.worker:contains("POJ") input').clear() cy.contains('save username').click() cy.contains('Success!') }) it('can get saved usernames from server', () => { cy.login(username) cy.visit('/statistics') cy.get('.worker:contains("HDU") input').should('have.value', 'user1') cy.get('.worker:contains("POJ") input').should('have.value', '') cy.get('.v-input:contains("Set all usernames") input').should('have.value', 'main-name') cy.get('.worker:contains("CodeForces") input').should('have.value', 'main-name') }) }) ================================================ FILE: e2e/cypress/integration/application/login-and-register.spec.js ================================================ describe('/login', () => { it('can show login error', () => { cy.visit('/login') cy.contains('Username').parent().type('admin') cy.contains('Password').parent().type('wrong-password') cy.get('button').contains('login').click() cy.contains('Invalid user name or password', { timeout: 60000 }) cy.get('.text-center').matchImageSnapshot('login-failed') }) it('can successfully login', () => { cy.visit('/login') cy.contains('Username').parent().type('admin') cy.contains('Password').parent().type('123qwe') cy.get('button').contains('login').click() cy.shouldHaveUri('/') }) it('can keep user session', () => { cy.visit('/login') cy.contains('Username').parent().type('admin') cy.contains('Password').parent().type('123qwe') cy.contains('Remember me').click() cy.get('button').contains('login').click() cy.shouldHaveUri('/') cy.log('Username still exists after refresh page') cy.reload() cy.contains('admin') }) it('should go to previous page after login', () => { cy.visit('/about') cy.contains('login', { matchCase: false }).click() cy.contains('Username').parent().type('admin') cy.contains('Password').parent().type('123qwe') cy.get('button').contains('login').click() cy.shouldHaveUri('/about') }) }) describe('/register', () => { it('can show captcha error', () => { cy.visit('/register') cy.contains('Username').parent().type('user') cy.contains('Password').parent().type('1234Qwer') cy.contains('Confirm password').parent().type('1234Qwer') cy.contains('Captcha').parent().type('wrong') cy.get('button').contains('register').click() cy.contains('Incorrect captcha', { timeout: 60000 }) cy.get('.text-center').matchImageSnapshot('register-failed') }) }) describe('Register then login', () => { const newUsername = 'user' + ('' + Math.random()).split('.')[1] it('can register new user starting from homepage', () => { cy.log('visit login page from homepage') cy.visit('/') cy.contains('login').click() cy.shouldHaveUri('/login?redirect=%2F') cy.log('visit register page') cy.contains('enter register page').click() cy.shouldHaveUri('/register?redirect=%2F') cy.log('fill user information') // wait dom to refresh (wait captcha) cy.contains('Captcha').parent().type('validate-text') cy.contains('Username').parent().type(newUsername) cy.contains('Password').parent().type('1234Qwer') cy.contains('Confirm password').parent().type('1234Qwer') cy.get('button').contains('register').click() cy.shouldHaveUri('/') cy.log('should back to homepage') cy.contains(newUsername) }) it('login from homepage then logout', () => { cy.log('login from homepage') cy.visit('/') cy.contains('login').click() cy.shouldHaveUri('/login?redirect=%2F') cy.log('enter username and password') cy.contains('Username').parent().type(newUsername) cy.contains('Password').parent().type('1234Qwer') cy.get('button').contains('login').click() cy.shouldHaveUri('/') cy.log('logout') cy.contains(newUsername).click() cy.contains('Logout') cy.shouldHaveUri('/settings') cy.get('button:contains("sign out")').click() cy.shouldHaveUri('/') cy.log('username does not exist after refresh page') cy.reload() cy.contains('login') }) }) ================================================ FILE: e2e/cypress/integration/application/swagger.spec.js ================================================ beforeEach(() => { cy.visit('/swagger') }) it('can load swagger file of crawler-api-backend', () => { cy.get('#select').select('Crawler API', {timeout: 10000}) cy.contains('crawler-api-backend', {timeout: 10000}) }) describe('can load swagger file of backend', () => { it('can visit page', () => { cy.get('#select').select('Backend API V1', {timeout: 10000}) cy.contains('AcmStatisticsBackend API', {timeout: 60000}) }) it.skip('can login correctly', () => { cy.get('#select').select('Backend API V1', {timeout: 10000}) cy.get('#authorize', {timeout: 10000}).within(()=>{ cy.contains('Authorize').click() }) cy.get('#userName').type('admin') cy.get('#password').type('123qwe') cy.get('.auth-btn-wrapper > .authorize').within(()=>{ cy.contains('Login').click() }) cy.contains('Logout', {timeout: 10000}) // 等待dom刷新 // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(1000) cy.contains('/api/services/app/Role/GetRoles').scrollIntoView() cy.contains('/api/services/app/Role/GetRoles').click() cy.contains('Try it out').click() cy.contains('Execute').click() cy.contains('"result"') cy.contains('"items"') }) }) ================================================ FILE: e2e/cypress/integration/frontend/about.spec.js ================================================ describe('overall', () => { beforeEach(() => { cy.visit('/about') }) it('can render correctly', () => { cy.viewport(1920, 1080) cy.matchImageSnapshot() }) it('wechat dialog can be rendered correctly', () => { cy.contains('div[role="listitem"]', '微信公众号').click() cy.get('.v-dialog.v-dialog--active').within(() => { cy.contains('微信公众号') cy.matchImageSnapshot() }) }) }) ================================================ FILE: e2e/cypress/integration/frontend/history.spec.js ================================================ let summaryUrl let username before(() => { cy.registerAndGetUsername().then(u => { username = u }) cy.log('save a history') cy.intercept( 'https://cors.ojhunt.com/http://acm.hdu.edu.cn/userstatus.php?user=wwwlsmcom', { fixture: 'summary_hdu.txt' }) .as('summary_hdu') // FIXME: the two route below do not work in intercept cy.server() cy.route('post', 'https://cors.ojhunt.com/https://leetcode.cn/graphql/', 'fixture:summary_leetcode.txt') .as('summary_leetcode') cy.route('/api/crawlers/vjudge/wwwlsmcom', 'fixture:summary_vjudge.txt') .as('summary_vjudge') cy.visit('/statistics') cy.get('div[title="HDU"]').parents('.worker').within(() => { queryAndWait('@summary_hdu') cy.contains('34') cy.contains('72') }) cy.get('div[title="LeetCode_CN"]').parents('.worker').within(() => { queryAndWait('@summary_leetcode') cy.contains('2') cy.contains('4') }) cy.get('div[title="VJudge"]').parents('.worker').within(() => { queryAndWait('@summary_vjudge') cy.contains('161') cy.contains('704') }) cy.contains('SOLVED: 192 / SUBMISSION', { matchCase: false }).click() cy.url().should('contain', '/history/') .then(s => { summaryUrl = s console.log('url', s) }) cy.clearCookies() }) describe('summary page', () => { it('should render correctly', () => { cy.login(username) cy.visit(summaryUrl) // hide generate time cy.get('strong:contains("Generated at")') .parent() .invoke('attr', 'style', 'background-color: black') cy.get('.v-toolbar__title') .invoke('text', '[GENERATED DATE]') // hide account username cy.get(`button:contains("${username}")`) .invoke('attr', 'style', 'background-color: black') cy.matchImageSnapshot() }) it('should be able to sort the list', () => { cy.login(username) cy.visit(summaryUrl) // hide generate time cy.get('strong:contains("Generated at")') .parent() .invoke('attr', 'style', 'background-color: black') cy.get('.v-toolbar__title') .invoke('text', '[GENERATED DATE]') // hide account username cy.get(`button:contains("${username}")`) .invoke('attr', 'style', 'background-color: black') cy.contains('Solved').click() cy.matchImageSnapshot() }) }) describe('history page', () => { it('should show history correctly', () => { // it already has one record cy.login(username) cy.visit('/history') cy.get('tbody tr').within(() => { cy.contains('192') cy.contains('780') }) }) describe('when click view', () => { it('should go to summary page', () => { cy.login(username) cy.visit('/history') cy.get('i.mdi-eye').parents('a').click() cy.url().should('eq', summaryUrl) }) }) describe('when click delete', () => { before(() => { cy.intercept('/api/services/app/QueryHistory/GetQueryHistoriesAndSummaries?maxResultCount=10&skipCount=0') .as('get-list') }) it('should delete item', () => { cy.login(username) cy.visit('/history') cy.get('i.mdi-delete').parents('button').click() cy.wait('@get-list') cy.contains('no data available', { matchCase: false }) }) }) describe('for history with multiple pages', () => { beforeEach(() => { cy.login(username) // go page from other pages to prevent ssr cy.visit('/about') cy.intercept( '/api/services/app/QueryHistory/GetQueryHistoriesAndSummaries?maxResultCount=10&skipCount=0', { fixture: 'history_list.json' }) .as('get-list') cy.intercept( '/api/services/app/QueryHistory/GetQueryHistoriesAndSummaries?maxResultCount=10&skipCount=10', { fixture: 'history_list-skip10.json' }) .as('get-list-2') cy.intercept( '/api/services/app/QueryHistory/GetQueryHistoriesAndSummaries?maxResultCount=5&skipCount=0', { fixture: 'history_list-max5.json' }) .as('get-list-3') cy.get('i.mdi-menu').parents('button').click() cy.contains('history', { matchCase: false }).click() cy.wait('@get-list') // hide account username cy.get(`button:contains("${username}")`) .invoke('attr', 'style', 'background-color: black') }) it('should render correctly', () => { historyPageSnapshot(cy) }) it('can go to next page', () => { cy.get('i.mdi-chevron-right').parents('button').click() cy.wait('@get-list-2') // cy.get('table').matchImageSnapshot() historyPageSnapshot(cy.get('table')) }) it('can set page size', () => { cy.get('div[aria-haspopup="listbox"]').click() cy.get('div[role="listbox"]') .contains('5') .parents('div[role="option"]') .click() cy.wait('@get-list-3') // cy.get('table').matchImageSnapshot() historyPageSnapshot(cy.get('table')) }) it('can delete multiple items correctly', () => { for (let i = 1; i <= 4; ++i) { cy.get(`tbody tr:nth-child(${i}) td:nth-child(1) > div`).click() } historyPageSnapshot(cy) cy.intercept('POST', '/api/services/app/QueryHistory/DeleteQueryHistory', req => req.reply({ success: true })) .as('delete') cy.contains('delete selected', { matchCase: false }).click() cy.wait('@delete') cy.get('@delete').its('request.body').should('deep.equal', { ids: [7, 8, 9, 10], }) }) }) }) function queryAndWait(waitFor) { cy.get('div:contains("Username") input').type('wwwlsmcom') // wait for debounce to be executed // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(500) cy.get('button i.mdi-refresh').click() cy.wait(waitFor) } // FIXME: temporary settings to make test passes, this only applies to history with // multiple pages function historyPageSnapshot(target = cy) { target.matchImageSnapshot({ failureThreshold: 9000, failureThresholdType: 'pixel', }) } ================================================ FILE: e2e/cypress/integration/frontend/index.spec.js ================================================ describe('overall', () => { beforeEach(() => { cy.visit('/') // remove parallax for snapshot cy.document().then(document => { document.querySelectorAll('.v-parallax__image') .forEach(item => item.setAttribute('style', null)) }) }) it('can render correctly', () => { cy.viewport(1920, 1080) cy.matchImageSnapshot() }) }) describe('parallax test', () => { beforeEach(() => { cy.visit('/') }) describe('first parallax', () => { it('can render correctly', () => { cy.get('.v-parallax').eq(0).matchImageSnapshot() }) }) describe('second parallax', () => { it('can render correctly', () => { cy.get('.v-parallax').eq(1).matchImageSnapshot() }) }) }) describe('other parts', () => { beforeEach(() => { cy.visit('/') }) it('click ENTER AC STATISTICS button to enter', () => { cy.contains('Enter AC Statistics').click() cy.shouldHaveUri('/statistics') }) }) ================================================ FILE: e2e/cypress/integration/frontend/login-register.spec.js ================================================ describe('/login', () => { beforeEach(() => { cy.visit('/login') }) it('can render correctly', () => { cy.viewport(1920, 1080) cy.matchImageSnapshot() }) }) describe('/register', () => { beforeEach(() => { cy.visit('/register') }) it('can render correctly', () => { cy.viewport(1920, 1080) cy.matchImageSnapshot() }) }) ================================================ FILE: e2e/cypress/integration/frontend/settings.spec.js ================================================ let username beforeEach(function () { cy.session('settings session', () => { cy.registerAndGetUsername().then(u => username = u) }) }) describe('overall', () => { it('can render correctly', () => { cy.visit('/settings') // hide account username cy.get(`button:contains("${username}")`) .invoke('attr', 'style', 'background-color: black') cy.matchImageSnapshot() }) }) describe('change password', () => { it('can report error when password is wrong', () => { cy.visit('/settings') cy.contains('Change Password').parent().within(() => { cy.contains('Current Password').parent().type('wrong') cy.contains('New Password').parent().type('1234QWer') cy.contains('Confirm Password').parent().type('1234QWer') cy.contains('submit').click() cy.matchImageSnapshot() }) }) it('can work correctly', () => { cy.visit('/settings') cy.contains('Change Password').parent().within(() => { cy.contains('Current Password').parent().type('1234Qwer') cy.contains('New Password').parent().type('1234QWer') cy.contains('Confirm Password').parent().type('1234QWer') cy.contains('submit').click() cy.contains('Success!') cy.matchImageSnapshot() }) cy.log('re-login to test new password') cy.get('button:contains("sign out")').click() cy.shouldHaveUri('/') cy.login(username, '1234QWer') }) }) describe('change time zone', () => { before(() => { cy.intercept('POST', '/api/services/app/UserConfig/SetUserTimeZone').as('set-time-zone') }) it('should work correctly', () => { cy.visit('/settings') cy.contains('Change time zone').parent().within(() => { cy.get('.v-select').click() cy.root().parents('html') .contains('(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna') .click() cy.contains('save').click() }) cy.wait('@set-time-zone') cy.reload() // hide header cy.get('header').invoke('hide') cy.contains('Change time zone').parent().matchImageSnapshot() }) }) describe('delete account', () => { it('should work correctly', () => { cy.visit('/settings') cy.get('button:contains("delete")').click() cy.get('.v-dialog').within(() => { cy.matchImageSnapshot() cy.get('button:contains("Confirm")').click() }) cy.shouldHaveUri('/') }) }) ================================================ FILE: e2e/cypress/integration/frontend/side-bar.spec.js ================================================ describe('when not logged in', () => { it('should show side bar correctly', () => { cy.visit('/about') cy.get('.v-app-bar__nav-icon').click() cy.get('.v-navigation-drawer__content').matchImageSnapshot() }) }) describe('when logged in', () => { let username before(() => { cy.registerAndGetUsername().then(u => { username = u }) cy.clearCookies() }) beforeEach(() => { cy.login(username) }) it('should show side bar correctly', () => { cy.visit('/about') cy.get('.v-app-bar__nav-icon').click() cy.get('.v-navigation-drawer__content').matchImageSnapshot() }) }) ================================================ FILE: e2e/cypress/integration/frontend/statistics.spec.js ================================================ describe('overall', () => { beforeEach(() => { cy.visit('/statistics') }) it('can render correctly', () => { // reset workers to make heights correct cy.contains('reset', { matchCase: false }).click() snapshot() }) }) describe('crawler test', () => { beforeEach(() => { cy.visit('/statistics') }) it('can start a worker', () => { cy.intercept( 'https://cors.ojhunt.com/http://poj.org/userstatus?user_id=vjudge5', { fixture: 'poj_ok.txt' }) .as('poj_frontend') cy.get('div[title="POJ"]').parents('.worker').within(() => { snapshot('worker-idle') cy.get('div:contains("Username") input').type('vjudge5') cy.get('div:contains("Username") input').blur() snapshot('worker-typed') waitAndRefresh() cy.wait('@poj_frontend') cy.contains('1968') cy.contains('277562') snapshot('worker-done') }) }) it('can request crawler-api-backend when get network error', () => { cy.intercept( 'https://cors.ojhunt.com/http://poj.org/userstatus?user_id=vjudge5', { forceNetworkError: true }).as('poj_frontend') cy.intercept('/api/crawlers/poj/vjudge5').as('poj_backend') cy.mockServer('oj/poj/backend_ok') cy.get('div[title="POJ"]').parents('.worker').within(() => { cy.get('div:contains("Username") input').type('vjudge5') waitAndRefresh() cy.wait('@poj_frontend') cy.wait('@poj_backend') .its('response.statusCode').should('eq', 200) cy.contains('1968') cy.contains('277562') }) }) it('can stop running query', () => { cy.intercept( 'https://cors.ojhunt.com/http://poj.org/userstatus?user_id=vjudge5', { body: 'lololo', delayMs: 10000 }, ).as('poj_frontend') cy.get('div[title="POJ"]').parents('.worker').within(() => { cy.get('div:contains("Username") input').type('vjudge5') waitAndRefresh() cy.get('.v-progress-linear') snapshot('worker-working') cy.get('button i.mdi-stop').click() snapshot('worker-after-stop') }) }) it('can show crawler errors', () => { cy.intercept('https://cors.ojhunt.com/http://poj.org/userstatus?user_id=Frkfe932fbcv09b', { fixture: 'poj_notExist.txt' }) .as('poj_frontend') cy.get('div[title="POJ"]').parents('.worker').within(() => { cy.get('div:contains("Username") input').type('Frkfe932fbcv09b') waitAndRefresh() cy.wait('@poj_frontend') cy.contains('The user does not exist') snapshot('worker-error') }) }) it('can show crawler warnings', () => { cy.get('div[title="POJ"]').parents('.worker').within(() => { cy.get('div:contains("Username") input').type(' name with space') cy.get('div:contains("Username") input').blur() cy.contains('Your username begins with a space.') cy.contains('Your username includes space, which may not be supported by some crawlers.') snapshot('worker-warning') }) }) }) function snapshot(name) { if (name) { cy.matchImageSnapshot(name, { capture: 'viewport', }) } else { cy.matchImageSnapshot({ capture: 'viewport', }) } } function waitAndRefresh() { // wait for debounce to be executed // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(500) cy.get('button i.mdi-refresh').click() } ================================================ FILE: e2e/cypress/support/commands.js ================================================ // *********************************************** // This example commands.js shows you how to // create various custom commands and overwrite // existing commands. // // For more comprehensive examples of custom // commands please read more here: // https://on.cypress.io/custom-commands // *********************************************** // // // -- This is a parent command -- // Cypress.Commands.add("login", (email, password) => { ... }) // // // -- This is a child command -- // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) // // // -- This is a dual command -- // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) // // // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) /* * 使用 cy.mockServer('busuanzi') 或者 cy.mockServer('oj/poj') 这样的命令来进行 */ Cypress.Commands.add('mockServer', path => { cy.request(`http://mock-configurer/${path}`) }) Cypress.Commands.overwrite('matchImageSnapshot', (originalFn, maybeName, commandOptions) => { let waitTimeperiod = 1000 if (!maybeName) { waitTimeperiod = 2000 } // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(waitTimeperiod) return originalFn(maybeName, commandOptions) }) Cypress.Commands.add('registerAndGetUsername', () => { cy.clearCookies() cy.log('<<<<< Start register') const username = 'user' + ('' + Math.random()).slice(2, 8).padEnd(6, '0') cy.visit('/register') cy.contains('Captcha').parent().type('validate-text') cy.contains('Username').parent().type(username) cy.contains('Password').parent().type('1234Qwer') cy.contains('Confirm password').parent().type('1234Qwer') cy.get('button').contains('register').click() cy.shouldHaveUri('/') cy.log('>>>>> End register') return cy.wrap(username) }) Cypress.Commands.add('login', (username, password) => { if (!password) { if (username === 'admin') { password = '123qwe' } else { password = '1234Qwer' } } cy.clearCookies() cy.log('<<<<< Start login') cy.visit('/login') cy.contains('Username').parent().type(username) cy.contains('Password').parent().type(password) cy.get('button').contains('login').click() cy.shouldHaveUri('/') cy.log('>>>>> End login') }) Cypress.Commands.add('shouldHaveUri', (uri, config = {}) => { const timeout = config.timeout || 30000 return cy.url({ timeout: timeout }) .should('eq', Cypress.config().baseUrl + uri) }) ================================================ FILE: e2e/cypress/support/e2e.js ================================================ // *********************************************************** // This example support/e2e.js is processed and // loaded automatically before your test files. // // This is a great place to put global configuration and // behavior that modifies Cypress. // // You can change the location of this file or turn off // automatically serving support files with the // 'supportFile' configuration option. // // You can read more here: // https://on.cypress.io/configuration // *********************************************************** import {addMatchImageSnapshotCommand} from '@simonsmith/cypress-image-snapshot/command' addMatchImageSnapshotCommand() require('cypress-terminal-report/src/installLogsCollector')() require('./commands') ================================================ FILE: e2e/cypress.config.js ================================================ const { defineConfig } = require('cypress') module.exports = defineConfig({ e2e: { baseUrl: 'http://localhost:3000', specPattern: 'cypress/integration/**/*.spec.js', setupNodeEvents(on, config) { require('@simonsmith/cypress-image-snapshot/plugin') .addMatchImageSnapshotPlugin(on, config) require('cypress-terminal-report/src/installLogsPrinter')(on) }, experimentalSessionAndOrigin: true, }, retries: { runMode: 2, openMode: 0, }, projectId: '4s32o7', }) ================================================ FILE: e2e/http-mocks/.dockerignore ================================================ node_modules Dockerfile .gitignore ================================================ FILE: e2e/http-mocks/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # next.js build output .next ================================================ FILE: e2e/http-mocks/Dockerfile ================================================ ARG NODE_BASE_IMAGE FROM ${NODE_BASE_IMAGE} RUN apk add --update --no-cache python3 make gcc g++ WORKDIR /mocks COPY package.json pnpm-lock.yaml ./ RUN pnpm install ADD . /mocks CMD ["pnpm", "start"] ================================================ FILE: e2e/http-mocks/package.json ================================================ { "name": "http-mocks", "scripts": { "start": "nodemon --legacy-watch ./src/index.js" }, "dependencies": { "glob": "10.5.0", "mockserver-client": "5.15.0", "nodemon": "2.0.22", "wait-on": "7.2.0" } } ================================================ FILE: e2e/http-mocks/src/index.js ================================================ const http = require('http') const { join } = require('path') const wait = require('wait-on') const mock = require('./lib/mock') const preActivation = require('./preActivation') const mocks = {} require('fs').readdirSync(join(__dirname, 'mocks')).forEach(file => { if (file.endsWith('.js')) { file = file.replace(/\.js$/, '') mocks[file] = require('./mocks/' + file) } }) console.log('mock list', mocks) const server = http.createServer(async (req, res) => { try { const func = findInPath(mocks, req.url) if (!func) { throw new Error(`mock ${req.url} is not in the list`) } const response = await mock(func) console.log(response) res.writeHead(200, { 'Content-Type': 'text/text' }) res.write(`mock ${req.url} successfully created`) res.end() } catch (e) { console.error(e) res.writeHead(500, { 'Content-Type': 'text/text' }) res.write(`mock ${req.url} yield following error message: ${e.message}`) res.end() } }) /** * 对于 /a/c/d 这样的 path,找到 obj 中的 obj.a.c.d,否则返回 null * @param obj * @param path {string} like /a/c/d * @return {Object|null} */ function findInPath(obj, path) { const findIn = path.substr(1).split('/') if (findIn[0] === 'mock-configurer') { findIn.shift() } console.log('find in array', findIn) let current = obj for (let item of findIn) { if (!current[item]) return null current = current[item] } return current } console.log('waiting for proxy server to be available...') wait({ resources: [ 'tcp:mock-proxy:1080', ], timeout: 60000, }).then(() => { console.log('proxy server started, now starting configurer server') mock(client => client.reset()) .then(() => console.log('All expectations reset')) .catch(console.error) // 激活预先的mock preActivation(mocks) server.listen(80) }) ================================================ FILE: e2e/http-mocks/src/lib/mock.js ================================================ const mockServerClient = require('mockserver-client').mockServerClient const client = mockServerClient('mock-proxy', 1080) /** * 将 client 传入 func,将结果 promise 输出 * @param func 接收 mockServerClient, 返回运行它之后的返回值 * @return {Promise} */ module.exports = func => { const promise = func(client) if (promise instanceof Promise) { return promise } else { return new Promise((resolve, reject) => promise.then(resolve, reject)) } } ================================================ FILE: e2e/http-mocks/src/lib/restClient.js ================================================ const http = require('http') module.exports = json => new Promise((resolve, reject) => { const data = JSON.stringify(json) const reqCfg = { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data), }, } const req = http.request('http://mock-proxy:1080/mockserver/expectation', reqCfg, resp => { let streamData = '' // A chunk of data has been recieved. resp.on('data', (chunk) => { streamData += chunk }) // The whole response has been received. Print out the result. resp.on('end', () => { resolve(streamData) }) }).on('error', reject) req.write(data) req.end() }) ================================================ FILE: e2e/http-mocks/src/mocks/busuanzi.js ================================================ // 让 busuanzi 每次都返回一样的数据 module.exports = client => client.mockWithCallback({ path: '/busuanzi', queryStringParameters: { jsonpCallback: ['.*'], }, headers: { host: ['busuanzi\\.ibruce\\.info(:80)?'], }, }, function (req) { return { statusCode: 200, body: `try{${req.queryStringParameters.jsonpCallback[0]}({"site_uv":3492,"page_pv":2770,"version":2.4,"site_pv":7164});}catch(e){}`, } }, { unlimited: true, }) ================================================ FILE: e2e/http-mocks/src/mocks/googleAds.js ================================================ // block google ads module.exports = client => client.mockAnyResponse({ httpRequest: { headers: { host: ['pagead2.googlesyndication.com'], }, }, httpResponse: { statusCode: 404, }, timeToLive:{ unlimited: true, }, times: { unlimited: true, }, }) ================================================ FILE: e2e/http-mocks/src/mocks/googleAnalysis.js ================================================ // block google analysis module.exports = client => client.mockAnyResponse({ httpRequest: { headers: { host: ['www.googletagmanager.com'], }, }, httpResponse: { statusCode: 404, }, timeToLive:{ unlimited: true, }, times: { unlimited: true, }, }) ================================================ FILE: e2e/http-mocks/src/mocks/history-snapshot.js ================================================ module.exports = { history(client) { return client.mockAnyResponse({ httpRequest: { path: '/api/services/app/QueryHistory/GetQueryHistoriesAndSummaries', headers: { host: ['reverse-proxy'], }, }, httpResponse: { statusCode: 200, headers: { 'Content-Type': ['application/json; charset=utf-8'], }, body: JSON.stringify(historyList), }, }) }, summary(client) { return client.mockAnyResponse({ httpRequest: { path: '/api/services/app/QueryHistory/GetQuerySummary', queryStringParameters: { queryHistoryId: ['1'], }, headers: { host: ['reverse-proxy'], }, }, httpResponse: { statusCode: 200, headers: { 'Content-Type': ['application/json; charset=utf-8'], }, body: JSON.stringify(summaryResponse), }, }) }, } const historyList = { 'result': { 'totalCount': 60, 'items': [{ 'historyId': 10, 'summaryId': 10, 'creationTime': '2020-04-10T08:00:00Z', 'submission': 100, 'solved': 10, }, { 'historyId': 9, 'summaryId': 9, 'creationTime': '2020-04-09T08:00:00Z', 'submission': 90, 'solved': 9, }, { 'historyId': 8, 'summaryId': 8, 'creationTime': '2020-04-08T08:00:00Z', 'submission': 80, 'solved': 8, }, { 'historyId': 7, 'summaryId': 7, 'creationTime': '2020-04-07T08:00:00Z', 'submission': 70, 'solved': 7, }, { 'historyId': 6, 'summaryId': 6, 'creationTime': '2020-04-06T08:00:00Z', 'submission': 60, 'solved': 6, }, { 'historyId': 5, 'summaryId': 5, 'creationTime': '2020-04-05T08:00:00Z', 'submission': 50, 'solved': 5, }, { 'historyId': 4, 'summaryId': 4, 'creationTime': '2020-04-04T08:00:00Z', 'submission': 40, 'solved': 4, }, { 'historyId': 3, 'summaryId': 3, 'creationTime': '2020-04-03T08:00:00Z', 'submission': 30, 'solved': 3, }, { 'historyId': 2, 'summaryId': 2, 'creationTime': '2020-04-02T08:00:00Z', 'submission': 20, 'solved': 2, }, { 'historyId': 1, 'summaryId': 1, 'creationTime': '2020-04-01T08:00:00Z', 'submission': 10, 'solved': 1, }, ], }, 'targetUrl': null, 'success': true, 'error': null, 'unAuthorizedRequest': false, '__abp': true, } const summaryResponse = { 'result': { 'queryHistoryId': 1, 'generateTime': '2020-07-11T04:15:22.010446Z', 'mainUsername': 'wwwlsmcom', 'queryCrawlerSummaries': [{ 'crawlerName': 'vjudge', 'submission': 1, 'solved': 1, 'usernames': [{ 'fromCrawlerName': null, 'username': 'wwwlsmcom', }], 'isVirtualJudge': true, }, { 'crawlerName': 'codechef', 'submission': 5, 'solved': 1, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'leetcode_cn', 'submission': 9, 'solved': 3, 'usernames': [{ 'fromCrawlerName': null, 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'timus', 'submission': 6, 'solved': 2, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'fzu', 'submission': 5, 'solved': 1, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'uvalive', 'submission': 1, 'solved': 1, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'uva', 'submission': 28, 'solved': 11, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'codeforces', 'submission': 15, 'solved': 6, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'dashiye', 'submission': 5, 'solved': 0, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'hdu', 'submission': 385, 'solved': 108, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }, { 'fromCrawlerName': null, 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }, { 'crawlerName': 'poj', 'submission': 325, 'solved': 59, 'usernames': [{ 'fromCrawlerName': 'vjudge', 'username': 'wwwlsmcom', }], 'isVirtualJudge': false, }], 'summaryWarnings': [{ 'crawlerName': 'leetcode_cn', 'content': 'This crawler does not have a solved list and its result will be directly added to summary.', }], 'submission': 785, 'solved': 193, }, 'targetUrl': null, 'success': true, 'error': null, 'unAuthorizedRequest': false, '__abp': true, } ================================================ FILE: e2e/http-mocks/src/mocks/oj.js ================================================ module.exports = { poj: { backend_ok(client) { return client.mockAnyResponse({ httpRequest: { path: '/userstatus', queryStringParameters: { user_id: ['vjudge5'], }, headers: { host: ['poj.org.*'], }, }, httpResponse: { statusCode: 200, headers: { 'Content-Type': ['text/html; charset=utf-8'], }, body: pojResponse, }, }) }, }, } /* SOLVED: 1968 SUBMISSIONS: 277562 */ const pojResponse = `User -- vjudge5
    Online JudgeProblem SetAuthorsOnline ContestsUser
    Web Board
    Home Page
    F.A.Qs
    Statistical Charts
    Problems
    Submit Problem
    Online Status
    Prob.ID:
    Register
    Update your info
    Authors ranklist
    Current Contest
    Past Contests
    Scheduled Contests
    Award Contest
    User ID:
    Password:
      Register
    vjudge5--黄汉升 @ vjudge.net
    Last Loginned Time:2019-03-31 13:43:20.0

    Compare and
    Rank: 18 Solved Problems List
    Solved: 1968
    Submissions: 277562
    School:
    Email:

    Home Page   Go Back  To top


    All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
    Any problem, Please Contact Administrator

    ` ================================================ FILE: e2e/http-mocks/src/mocks/reset.js ================================================ module.exports = client => client.reset() ================================================ FILE: e2e/http-mocks/src/mocks/tajs.js ================================================ // 屏蔽对腾讯分析的请求,防止分析不准确 module.exports = client => client.mockAnyResponse({ httpRequest: { headers: { host: ['tajs.qq.com'], }, }, httpResponse: { statusCode: 404, }, timeToLive:{ unlimited: true, }, times: { unlimited: true, }, }) ================================================ FILE: e2e/http-mocks/src/preActivation.js ================================================ const mock = require('./lib/mock') module.exports = async mocks => { const actived = [ mocks.googleAnalysis, ] for (let item of actived) { await mock(item) } } ================================================ FILE: e2e/jsconfig.json ================================================ { "include": [ "./node_modules/cypress", "cypress/**/*.js" ] } ================================================ FILE: e2e/package.json ================================================ { "name": "e2e", "description": "e2e test", "scripts": { "lint": "eslint --ext .js .", "lintfix": "eslint --fix --ext .js .gitignore .", "test": "cypress run", "start": "cypress open", "test-html": "jest __test__/", "cypress-install": "cypress install" }, "dependencies": { "@simonsmith/cypress-image-snapshot": "8.1.2", "cheerio": "1.0.0-rc.10", "cypress": "10.11.0", "cypress-terminal-report": "5.3.12", "eslint": "8.57.1", "eslint-plugin-cypress": "2.15.2", "eslint-plugin-lodash": "7.4.0", "jest": "29.7.0", "jest-serializer-vue": "3.1.0", "lodash": "4.17.23", "superagent": "8.1.2" }, "jest": { "snapshotSerializers": [ "jest-serializer-vue" ] } } ================================================ FILE: frontend/.dockerignore ================================================ # dependencies node_modules # logs npm-debug.log # Nuxt build .nuxt # Nuxt generate dist # codecov coverage # docker .dockerignore base.Dockerfile release.Dockerfile # make Makefile ================================================ FILE: frontend/.editorconfig ================================================ # editorconfig.org root = true [*] indent_size = 2 indent_style = space end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false ================================================ FILE: frontend/.eslintignore ================================================ # dependencies /node_modules # Nuxt build /.nuxt # Nuxt generate /dist # 静态文件中可能有已经编译好的js文件 /static # coverage /coverage ================================================ FILE: frontend/.eslintrc.js ================================================ module.exports = { root: true, env: { browser: true, node: true, 'jest/globals': true, }, extends: [ 'eslint:recommended', // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 'plugin:vue/strongly-recommended', 'plugin:lodash/recommended', 'plugin:jest/recommended', ], // required to lint *.vue files plugins: [ 'vue', 'lodash', 'jest', 'vuetify', ], // add your custom rules here rules: { 'semi': [2, 'never'], 'no-console': 'off', 'vue/max-attributes-per-line': 'off', 'comma-dangle': ['error', 'always-multiline'], 'quotes': ['error', 'single'], // we don't need to do that since we have babel lodash 'lodash/import-scope': 'off', // low readability 'lodash/matches-prop-shorthand': 'off', 'lodash/prefer-reject': 'off', // force PascalCase 'vue/component-name-in-template-casing': ['error', 'kebab-case', { registeredComponentsOnly: false, }], 'vue/multi-word-component-names': 'off', // for vuetify migration 'vuetify/no-deprecated-classes': 'error', 'vuetify/grid-unknown-attributes': 'error', 'vuetify/no-legacy-grid': 'off', }, } ================================================ FILE: frontend/.gitignore ================================================ # dependencies node_modules # logs npm-debug.log # Nuxt build .nuxt # Nuxt generate dist # codecov coverage # vscode .vscode ================================================ FILE: frontend/.npmrc ================================================ # for pnpm shamefully-hoist=true # disable renovate warning strict-peer-dependencies=false ================================================ FILE: frontend/.nuxtignore ================================================ store/-dynamic store/-dynamic/* ================================================ FILE: frontend/Makefile ================================================ ## makefile for frontend include ../build/share.mk # === targets === help: @echo run \"make help\" in root directory to get help .crawler: cd ../crawler && $(MAKE) build .node-base: cd ../build && $(MAKE) -f node-base.mk build .base: .node-base .crawler docker build . \ -t $(FrontendBaseTag) \ $(build-args) \ -f base.Dockerfile \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) \ --build-arg CRAWLER_IMAGE=$(CrawlerTag) build: .base docker build . \ -f release.Dockerfile \ -t $(FrontendTag) \ $(build-args) \ --build-arg VERSION_NUM=$(VERSION_NUM) \ --build-arg BUILD_TIME=$(BUILD_TIME) \ --build-arg NODE_BASE_IMAGE=$(NodeBaseTag) \ --build-arg FRONTEND_BASE_IMAGE=$(FrontendBaseTag) \ --build-arg CRAWLER_IMAGE=$(CrawlerTag) test: .base docker run --rm -t $(FrontendBaseTag) pnpm test # Update snapshot update-snapshot: .base docker run --rm -t \ -v "$(CURDIR)/__test__:/var/project/__test__" \ $(FrontendBaseTag) pnpm test -- --updateSnapshot # if BUILD_FRONTEND is specified, it will compile the frontend before `run` command ifdef BUILD_FRONTEND run: build docker run $(run-args) $(FrontendTag) $(run-cmd) else run: .base docker run $(run-args) $(FrontendBaseTag) $(run-cmd) endif clean: docker image rm $(FrontendBaseTag) $(FrontendTag); true test-ci: .base docker run --rm \ -v "$(CURDIR)/coverage:/var/project/coverage" \ $(FrontendBaseTag) \ pnpm test -- --colors --ci # Use docker to develop. It runs `pnpm run dev` dev: cd ../build && $(MAKE) -f docker-compose.mk dev-frontend ================================================ FILE: frontend/README.md ================================================ # acm-statistics-frontend > ACM查题网站前端 ## Using Docker - `make dev` 启动开发模式(需要先使用pnpm安装依赖) - `make update-snapshot` 更新快照 - `make test` 或 `make test-ci` 来运行测试 ## Build Setup ``` bash # install dependencies $ pnpm install # Or yarn install # serve with hot reload at localhost:3000 $ pnpm run dev # build for production and launch server $ pnpm run build $ pnpm start ``` ## 其他命令 - `pnpm run lint` 运行代码质量检测 - `pnpm run lintfix` 自动修复部分代码质量问题 - `pnpm run analyze` 分析build出来的文件大小、分布,生成报告 - `pnpm run test` 运行测试 - `pnpm run snapshot` 交互式更新快照 For detailed explanation on how things work, check out the [Nuxt.js](https://github.com/nuxt/nuxt.js) and [Vuetify.js](https://vuetifyjs.com/) documentation. ## 版权声明 - 本产品的主页部分使用了 [vuetifyjs/parallax-starter](https://github.com/vuetifyjs/parallax-starter) 模板,根据其开源协议,本项目的[主页源代码](./pages/index.vue)中包含了其协议声明。 ================================================ FILE: frontend/__test__/StoreContextSimulator.js ================================================ import _ from 'lodash' export default class StoreContextSimulator { /** * 初始化 * @param state {Object} mocked state * @param mutations {Object.} mocked mutations, 如果存在,提交一个 mutations 的时候会调用 * @param getters {Object.} 如果为函数,得到的 getter 会使用此函数和 state 来计算出结果;否则直接以这个值作为结果 */ constructor(state = null, {mutations, getters} = {}) { this.commitHistory = [] this.state = state this.mutations = mutations this.getters = {} if (getters) { for (let key in getters) { const val = getters[key] if (_.isFunction(val)) { Object.defineProperty(this.getters, key, {get: () => val(this.state)}) } else { this.getters[key] = val } } } } getCommitHistory() { return this.commitHistory } getCommiter() { return (type, payload) => { this.commitHistory.push({ type, payload: _.cloneDeep(payload), }) if (this.state && this.mutations) { this.mutations[type](this.state, payload) } } } getGetters() { return this.getters } } ================================================ FILE: frontend/__test__/components/MessagePanel.test.js ================================================ /** * @jest-environment jsdom */ import { createLocalVue, mount } from '@vue/test-utils' import Vuex from 'vuex' import Vuetify from 'vuetify' import Vue from 'vue' Vue.use(Vuetify) const localVue = createLocalVue() localVue.use(Vuex) import MessagePanel from '~/components/MessagePanel.vue' import * as MessageStore from '~/store/message' describe('MessagePanel', () => { let wrapper let store beforeEach(() => { const vuetify = new Vuetify() store = new Vuex.Store({ modules: { message: MessageStore, }, }) wrapper = mount(MessagePanel, { store, localVue, vuetify, }) }) it('can render correctly', async () => { expect(wrapper.vm).toBeTruthy() await wrapper.vm.$nextTick() expect(wrapper.html()).toMatchSnapshot() }) it('can render when there are 1 element', async () => { store.commit('message/add', 'Info') await wrapper.vm.$nextTick() expect(store.state.message.list).toHaveLength(1) expect(wrapper.html()).toMatchSnapshot() }) it('can render when there are 2 elements', async () => { store.commit('message/add', { message: 'Info', type: 'info', }) store.commit('message/add', { message: 'Error', type: 'error', }) await wrapper.vm.$nextTick() expect(store.state.message.list).toHaveLength(2) expect(wrapper.html()).toMatchSnapshot() }) }) ================================================ FILE: frontend/__test__/components/WorkerCard.test.js ================================================ /** * @jest-environment jsdom */ import { shallowMount, createLocalVue, mount } from '@vue/test-utils' import Vuex from 'vuex' import Vuetify from 'vuetify' import Vue from 'vue' Vue.use(Vuetify) const localVue = createLocalVue() localVue.use(Vuex) jest.mock('~/dynamic/crawlers', () => () => ({ metas: { testCrawler: { title: 'crawler title', description: 'crawler description', url: 'http://crawler.url', }, }, crawlers: { testCrawler: () => ({ submissions: 0, pass: 0 }), }, }), { virtual: true }) import { WORKER_STATUS } from '~/components/consts' import WorkerCard from '~/components/WorkerCard.vue' import StatisticsStore from '~/store/-dynamic/statistics' describe('WorkerCard', () => { let vuetify beforeEach(() => { vuetify = new Vuetify() }) it('can be mounted correctly', () => { const wrapper = shallowMount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: StatisticsStore, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.vm).toBeTruthy() }) it('can be rendered correctly', () => { const wrapper = mount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: StatisticsStore, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.html()).toMatchSnapshot() }) it('can render username correctly', () => { const wrapper = mount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: { state: { workers: [{ crawlerName: 'testCrawler', username: 'test_crawler_username', status: WORKER_STATUS.WAITING, solved: 0, submissions: 0, errorMessage: '', tokenKey: null, }], crawlers: { 'testCrawler': { name: 'testCrawler', title: 'crawler title', description: 'crawler description', url: 'http://crawler.url', }, }, }, getters: StatisticsStore.getters, namespaced: true, }, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.vm.username).toBe('test_crawler_username') expect(wrapper.html()).toMatchSnapshot() }) it('can render warning correctly', () => { const wrapper = mount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: { state: { workers: [{ crawlerName: 'testCrawler', username: ' username with space', status: WORKER_STATUS.WAITING, solved: 0, submissions: 0, errorMessage: '', tokenKey: null, }], crawlers: { 'testCrawler': { name: 'testCrawler', title: 'crawler title', description: 'crawler description', url: 'http://crawler.url', }, }, }, getters: StatisticsStore.getters, namespaced: true, }, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.html()).toMatchSnapshot() }) it('can render result correctly', () => { const wrapper = mount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: { state: { workers: [{ crawlerName: 'testCrawler', username: 'test_crawler_username', status: WORKER_STATUS.WAITING, solved: 10, submissions: 20, errorMessage: '', tokenKey: null, }], crawlers: { 'testCrawler': { name: 'testCrawler', title: 'crawler title', description: 'crawler description', url: 'http://crawler.url', }, }, }, getters: StatisticsStore.getters, namespaced: true, }, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.html()).toMatchSnapshot() }) it('can render error correctly', () => { const wrapper = mount(WorkerCard, { store: new Vuex.Store({ modules: { statistics: { state: { workers: [{ crawlerName: 'testCrawler', username: 'test_crawler_username', status: WORKER_STATUS.WAITING, solved: 0, submissions: 0, errorMessage: 'a error is occurred', tokenKey: null, }], crawlers: { 'testCrawler': { name: 'testCrawler', title: 'crawler title', description: 'crawler description', url: 'http://crawler.url', }, }, }, getters: StatisticsStore.getters, namespaced: true, }, }, }), localVue, vuetify, propsData: { index: 0, }, }) expect(wrapper.html()).toMatchSnapshot() }) }) ================================================ FILE: frontend/__test__/components/__snapshots__/MessagePanel.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`MessagePanel can render correctly 1`] = ` `; exports[`MessagePanel can render when there are 1 element 1`] = `
    `; exports[`MessagePanel can render when there are 2 elements 1`] = `
    `; ================================================ FILE: frontend/__test__/components/__snapshots__/WorkerCard.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`WorkerCard can be rendered correctly 1`] = `
    crawler title
    crawler description
    `; exports[`WorkerCard can render error correctly 1`] = `
    crawler title
    crawler description
    `; exports[`WorkerCard can render result correctly 1`] = `
    crawler title
    crawler description
    `; exports[`WorkerCard can render username correctly 1`] = `
    crawler title
    crawler description
    `; exports[`WorkerCard can render warning correctly 1`] = `
    crawler title
    crawler description
    Your username begins with a space.
    Your username includes space, which may not be supported by some crawlers.
    `; ================================================ FILE: frontend/__test__/components/statisticsLayoutBuilder.test.js ================================================ import statisticsLayoutBuilder from '~/components/statisticsLayoutBuilder' describe('statisticsLayoutBuilder', () => { it('can get worker information 1', () => { const result = statisticsLayoutBuilder([ { crawlerName: 'c1', key: 0.1 }, { crawlerName: 'c1', key: 0.2 }, { crawlerName: 'c2', key: 0.3 }, { crawlerName: 'c3', key: 0.4 }, { crawlerName: 'c3', key: 0.5 }, { crawlerName: 'c3', key: 0.6 }, { crawlerName: 'c4', key: 0.7 }, { crawlerName: 'c5', key: 0.8 }, ], 3) expect(result).toMatchObject([ [0, 1, 2], [3, 4, 5], [6, 7], ]) }) it('can get worker information 2', () => { const result = statisticsLayoutBuilder([ { crawlerName: 'c1', key: 0.01 }, { crawlerName: 'c1', key: 0.02 }, { crawlerName: 'c2', key: 0.03 }, { crawlerName: 'c3', key: 0.04 }, { crawlerName: 'c3', key: 0.05 }, { crawlerName: 'c3', key: 0.06 }, { crawlerName: 'c4', key: 0.07 }, { crawlerName: 'c5', key: 0.08 }, { crawlerName: 'c6', key: 0.09 }, { crawlerName: 'c7', key: 0.10 }, { crawlerName: 'c8', key: 0.11 }, { crawlerName: 'c9', key: 0.12 }, { crawlerName: 'c10', key: 0.13 }, ], 4) expect(result).toMatchObject([ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12], ]) }) it('can get worker information 3', () => { const result = statisticsLayoutBuilder([ { crawlerName: 'c1', key: 0.1 }, { crawlerName: 'c1', key: 0.1 }, { crawlerName: 'c2', key: 0.1 }, { crawlerName: 'c3', key: 0.1 }, { crawlerName: 'c3', key: 0.1 }, { crawlerName: 'c3', key: 0.1 }, ], 3) expect(result).toMatchObject([ [0, 1], [2, 3], [4, 5], ]) }) }) ================================================ FILE: frontend/__test__/components/statisticsUtils.test.js ================================================ import {warningHelper, mapVirtualJudgeProblemTitle} from '~/components/statisticsUtils' describe('warningHelper', () => { it('does not generate warning when it is correct', () => { const worker = { username: 'user1', status: 'WORKING', submissions: 0, solved: 0, errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.66666666, } expect(warningHelper(worker, {}, {})).toMatchObject([]) worker.username = '' expect(warningHelper(worker, {}, {})).toMatchObject([]) }) it('can generate warning with username that beginning with space', () => { const worker = { username: ' user1', status: 'WORKING', submissions: 0, solved: 0, errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.66666666, } expect(warningHelper(worker, {}, {})).toMatchObject([ 'Your username begins with a space.', 'Your username includes space, which may not be supported by some crawlers.', ]) }) it('can generate warning that username contains space', () => { const worker = { username: 'user 1', status: 'WORKING', submissions: 0, solved: 0, errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.66666666, } expect(warningHelper(worker, {}, {})).toMatchObject([ 'Your username includes space, which may not be supported by some crawlers.', ]) }) it('can warn that there are collapses with ac list of vjudge and other workers', () => { const worker = { solvedList: [ 'A-001', 'B-001', 'B-002', 'C-001', ], solved: 4, crawlerName: 'vjudge', } const crawlerMeta = { virtual_judge: true, } const getters = { nullSolvedListCrawlers: { 'A': 'a title', 'B': 'b title', }, } const res = warningHelper(worker, crawlerMeta, getters) expect(res).toMatchObject([ 'Crawler a title did not return AC problem list, its result may overlap with this crawler\'s', 'Crawler b title did not return AC problem list, its result may overlap with this crawler\'s', ]) }) it('can warn that multiple worker crawler can have redundant problems', () => { const worker = { solvedList: null, crawlerName: 'cr1', } const crawlerMeta = {} const getters = { nullSolvedListCrawlers: { 'cr1': 'cr1 title', }, workerNumberOfCrawler: { 'cr1': 2, }, } const res = warningHelper(worker, crawlerMeta, getters) expect(res).toMatchObject([ 'This crawler did not return AC problem list, so the same problem in different OJs can be recognized as different problems.', ]) }) it('can warn when solved and solvedList.length is not equal', () => { const worker = { solved: 2, solvedList: ['1001'], } const res = warningHelper(worker, {}, {}) expect(res).toMatchObject([ 'The solved number of this crawler is 2, however, there are 1 problems in the solved list, which can be an error of the crawler.', ]) }) }) describe('mapVirtualJudgeProblemTitle', () => { it('can work correctly', () => { const solvedList = [ 'aa-001', 'b-002', 'C-003', ] const crawlers = { aa: { title: 'AA', }, b: { title: 'B', }, } const res = mapVirtualJudgeProblemTitle(solvedList, crawlers) expect(res).toMatchObject([ 'AA-001', 'B-002', 'C-003', ]) }) }) ================================================ FILE: frontend/__test__/e2eMocks/crawler.js ================================================ const _ = require('lodash') const crawlerNames = _.map(_.range(5), i => `crawler${i}`) const metas = _.zipObject( crawlerNames, _.map(crawlerNames, str => ({ title: str, })), ) metas.withDescription = { title: 'with description', description: 'a description', } metas.withUrl = { title: 'with url', url: 'http://test.aaa.com', } metas.withAll = { title: 'with all', description: 'with all description and url', url: 'http://test.aaa.com', } module.exports = { readMetaConfigs: () => { return Promise.resolve(metas) }, generateBrowserCrawlerFunctions: () => { const result = {} for (let key in metas) { result[key] = 'username => ({submissions: 0, solved: 0})' } return Promise.resolve(result) }, } ================================================ FILE: frontend/__test__/store/statistics.test.js ================================================ import StoreContextSimulator from '../StoreContextSimulator' import { MUTATION_TYPES } from '../../store/-dynamic/statistics' jest.mock('~/dynamic/crawlers', () => function () { return { metas: { cr1: { title: 'crawler 1', }, cr2: { title: 'crawler 2, should throw exception', }, cr3: { title: 'crawler 3, return at next tick', }, }, crawlers: { // eslint-disable-next-line no-unused-vars cr1: username => Promise.resolve({ submissions: 10, solved: 5, solvedList: ['1001', '1002'] }), // eslint-disable-next-line no-unused-vars cr2: (username) => Promise.reject(new Error('The user does not exist')), // eslint-disable-next-line no-unused-vars cr3: (username) => { return new Promise(resolve => setImmediate(() => resolve({ submissions: 10, solved: 1, solvedList: null, }))) }, }, } }, { virtual: true }) const store = require('../../store/-dynamic/statistics') describe('state', () => { it('can generate state correctly', () => { const state = store.state() expect(state).toMatchObject({ mainUsername: '', crawlers: { cr1: { name: 'cr1', title: 'crawler 1', }, cr2: { title: 'crawler 2, should throw exception', }, cr3: { title: 'crawler 3, return at next tick', }, }, workers: [ { crawlerName: 'cr1', username: '', solved: 0, submissions: 0, solvedList: [], errorMessage: '', tokenKey: null, key: expect.any(Number), }, { crawlerName: 'cr2', username: '', solved: 0, submissions: 0, solvedList: [], errorMessage: '', tokenKey: null, key: expect.any(Number), }, { crawlerName: 'cr3', username: '', solved: 0, submissions: 0, solvedList: [], errorMessage: '', tokenKey: null, key: expect.any(Number), }, ], }) }) }) describe('mutations', () => { describe('updateUsername', () => { it('can reset data when username changed', () => { const state = { workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, solvedList: ['1', '2'], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, ], } store.mutations.updateUsername(state, { index: 0, username: 'user2' }) expect(state).toMatchObject({ workers: [ { username: 'user2', status: 'WAITING', submissions: 0, solved: 0, solvedList: [], errorMessage: '', tokenKey: null, crawlerName: 'cr1', key: 0.6666666, }, ], }) }) it('can change username to empty string when it is set to null', () => { const state = { workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, ], } store.mutations.updateUsername(state, { index: 0, username: null }) expect(state).toMatchObject({ workers: [ { username: '', status: 'WAITING', submissions: 0, solved: 0, solvedList: [], errorMessage: '', tokenKey: null, crawlerName: 'cr1', key: 0.6666666, }, ], }) }) }) describe('updateMainUsername', () => { it('can update every workers\'s username', () => { const state = { mainUsername: 'mainUser', workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, solvedList: ['1', '2'], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user2', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.7777777, }, ], } store.mutations.updateMainUsername(state, { username: 'main2' }) expect(state).toMatchObject({ mainUsername: 'main2', workers: [ { username: 'main2', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: 0.6666666, }, { username: 'main2', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr2', key: 0.7777777, }, ], }) }) }) describe('updateUsernamesFromObject', () => { let startState beforeEach(() => { startState = { mainUsername: 'mainUser', crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user2', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user2', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } }) it('can update data correctly', () => { store.mutations.updateUsernamesFromObject(startState, { main: 'main2', subs: { cr1: ['nu1', 'nu2'], cr2: ['nu3'], }, }) expect(startState).toMatchObject({ mainUsername: 'main2', workers: [ { username: 'nu1', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: 'nu2', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: 'nu3', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr2', key: expect.any(Number), }, ], }) }) it('can set username to mainUsername when its data do not exist', () => { store.mutations.updateUsernamesFromObject(startState, { main: 'main2', subs: { cr2: ['nu3'], }, }) expect(startState).toMatchObject({ mainUsername: 'main2', workers: [ { username: 'main2', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: 'nu3', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr2', key: expect.any(Number), }, ], }) }) it('does not add redundant worker when certain data do not exist', () => { store.mutations.updateUsernamesFromObject(startState, { main: 'main2', subs: { cr1: ['nu1'], cr2: ['nu3'], cr3: ['nnnn'], }, }) expect(startState).toMatchObject({ mainUsername: 'main2', workers: [ { username: 'nu1', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: 'nu3', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr2', key: expect.any(Number), }, ], }) }) it('can generate worker correctly when certain username is empty string', () => { store.mutations.updateUsernamesFromObject(startState, { main: 'main2', subs: { cr1: ['nu1', ''], cr2: [''], }, }) expect(startState).toMatchObject({ mainUsername: 'main2', workers: [ { username: 'nu1', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: '', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: '', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr2', key: expect.any(Number), }, ], }) }) }) describe('stopWorker', () => { it('should reset tokenKey and status', () => { const state = { crawlers: { cr1: { name: 'cr1', }, }, workers: [ { username: 'user1', status: 'WORKING', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.66666666, }, ], } store.mutations.stopWorker(state, { index: 0 }) expect(state).toMatchObject({ crawlers: { cr1: { name: 'cr1', }, }, workers: [ { username: 'user1', status: 'WAITING', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: null, crawlerName: 'cr1', key: 0.66666666, }, ], }) }) }) describe('addWorkerForCrawler', () => { it('should add worker to the end when other worker does not exist', () => { const state = { crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, solvedList: ['1', '2'], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr2', key: 0.66666666, }, ], } store.mutations.addWorkerForCrawler(state, { crawlerName: 'cr1' }) expect(state).toMatchObject({ crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.66666666, }, { username: '', status: 'WAITING', submissions: 0, solved: 0, solvedList: [], errorMessage: '', tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, ], }) }) it('should add new worker after existing one with same crawler', () => { const state = { crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user0', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } store.mutations.addWorkerForCrawler(state, { crawlerName: 'cr1' }) expect(state).toMatchObject({ crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user0', status: 'DONE', submissions: 33, solved: 22, solvedList: ['1', '2'], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: '', status: 'WAITING', submissions: 0, solved: 0, errorMessage: '', solvedList: [], tokenKey: null, crawlerName: 'cr1', key: expect.any(Number), }, { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], }) }) }) describe('clearWorkers', () => { it('can reset workers', () => { const state = { mainUsername: 'wwwwww', crawlers: { cr1: { name: 'cr1', title: 'crawler 1', }, }, workers: [ { crawlerName: 'cr1', username: 'asdfg', solved: 0, submissions: 0, errorMessage: '', solvedList: [], tokenKey: 0.123, key: 0.23333, }, { crawlerName: 'cr1', username: 'qwert', solved: 0, submissions: 0, errorMessage: '', solvedList: [], tokenKey: 0.456, key: 0.666, }, ], } store.mutations[MUTATION_TYPES.clearWorkers](state) expect(state).toMatchObject({ mainUsername: '', crawlers: { cr1: { name: 'cr1', title: 'crawler 1', }, }, workers: [{ crawlerName: 'cr1', username: '', solved: 0, submissions: 0, solvedList: [], errorMessage: '', tokenKey: null, key: expect.any(Number), }], }) }) }) }) describe('getters', () => { describe('solvedNum', () => { it('can collect data of ordinary workers', () => { const state = { workers: [ { solved: 1, solvedList: null, crawlerName: 'cr1', }, { solved: 2, solvedList: null, crawlerName: 'cr1', }, { solved: 4, solvedList: null, crawlerName: 'cr2', }, ], crawlers: { cr1: {}, cr2: {}, }, } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.solvedNum(state, { nullSolvedListWorkers }) expect(res).toBe(7) }) it('can collect data of workers with list', () => { const state = { workers: [ { solved: 1, solvedList: ['1001'], crawlerName: 'cr1', }, { solved: 2, solvedList: ['1001', '1002'], crawlerName: 'cr2', }, { solved: 1, solvedList: ['1001'], crawlerName: 'cr2', }, ], crawlers: { cr1: {}, cr2: {}, }, } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.solvedNum(state, { nullSolvedListWorkers }) expect(res).toBe(3) }) it('can collect data of workers with mixed type', () => { const state = { workers: [ { solved: 1, solvedList: ['1001'], crawlerName: 'cr1', }, { solved: 4, solvedList: null, crawlerName: 'cr1', }, { solved: 2, solvedList: ['1001', '1002'], crawlerName: 'cr2', }, ], crawlers: { cr1: {}, cr2: {}, }, } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.solvedNum(state, { nullSolvedListWorkers }) expect(res).toBe(7) }) it('can collect data of virtual_judge workers', () => { const state = { workers: [ { solved: 1, solvedList: ['1001'], crawlerName: 'cr1', }, { solved: 4, solvedList: null, crawlerName: 'cr1', }, { solved: 2, solvedList: ['1001', '1002'], crawlerName: 'cr2', }, { solved: 5, solvedList: ['cr1-1001', 'cr1-1002', 'cr2-1002', 'cr2-1003', 'NN-1001'], crawlerName: 'cr3', }, { // redundant name solved: 1, solvedList: ['cr1-1001'], crawlerName: 'cr4', }, ], crawlers: { cr1: {}, cr2: {}, cr3: { virtual_judge: true, }, cr4: { virtual_judge: true, }, }, } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.solvedNum(state, { nullSolvedListWorkers }) expect(res).toBe(10) }) it('works correctly when vj returns label with its own oj name', () => { const state = { workers: [ { solved: 1, solvedList: ['1001'], crawlerName: 'cr1', }, { solved: 4, solvedList: null, crawlerName: 'cr1', }, { solved: 2, solvedList: ['1001', '1002'], crawlerName: 'cr2', }, { solved: 5, solvedList: ['cr1-1001', 'cr1-1002', 'cr2-1002', 'cr2-1003', 'NN-1001', 'cr3-1001'], crawlerName: 'cr3', }, { // redundant name solved: 1, solvedList: ['cr1-1001', 'cr3-1001', 'cr4-1001'], crawlerName: 'cr4', }, ], crawlers: { cr1: {}, cr2: {}, cr3: { virtual_judge: true, }, cr4: { virtual_judge: true, }, }, } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.solvedNum(state, { nullSolvedListWorkers }) expect(res).toBe(12) }) }) describe('notWorkingRate', () => { it('can work correctly', () => { const state = { workers: [ { status: 'DONE' }, { status: 'WORKING' }, { status: 'WAITING' }, { status: 'DONE' }, ], } expect(store.getters.notWorkingRate(state)).toBe(75) }) it('can get 0', () => { const state = { workers: [ { status: 'WORKING' }, { status: 'WORKING' }, { status: 'WORKING' }, { status: 'WORKING' }, ], } expect(store.getters.notWorkingRate(state)).toBe(0) }) it('can get 100', () => { const state = { workers: [ { status: 'DONE' }, { status: 'DONE' }, { status: 'DONE' }, { status: 'DONE' }, ], } expect(store.getters.notWorkingRate(state)).toBe(100) }) }) describe('workerNumberOfCrawler', () => { it('can get worker count of certain crawler', () => { const state = { workers: [ { crawlerName: 'cr1', }, { crawlerName: 'cr1', }, { crawlerName: 'cr2', }, { crawlerName: 'cr3', }, ], } expect(store.getters.workerNumberOfCrawler(state)).toMatchObject({ cr1: 2, cr2: 1, cr3: 1, }) }) }) describe('workerIdxOfCrawler', () => { it('can get worker index', () => { const state = { workers: [ { crawlerName: 'cr1', }, { crawlerName: 'cr1', }, { crawlerName: 'cr2', }, { crawlerName: 'cr3', }, ], } expect(store.getters.workerIdxOfCrawler(state)).toMatchObject([ 1, 2, 1, 1, ]) }) }) describe('nullSolvedListCrawlers', () => { it('can get correct result', () => { const state = { crawlers: { cr1: { title: 'cr1 title', }, cr2: { title: 'cr2 title', }, cr3: { title: 'cr3 title', }, }, workers: [ { solvedList: null, crawlerName: 'cr1', }, { solvedList: ['1', '2'], crawlerName: 'cr2', }, { solvedList: null, crawlerName: 'cr3', }, ], } const nullSolvedListWorkers = store.getters.nullSolvedListWorkers(state) const res = store.getters.nullSolvedListCrawlers(state, { nullSolvedListWorkers }) expect(res).toMatchObject({ cr1: 'cr1 title', cr3: 'cr3 title', }) }) }) }) describe('helper functions', () => { describe('getUsernameObjectFromState', () => { it('can generate data correctly', () => { const state = { mainUsername: 'mainUser', crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user2', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: 'user2', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } const result = store.getUsernameObjectFromState(state) expect(result).toMatchObject({ main: 'mainUser', subs: { cr1: ['user1', 'user2'], cr2: ['user2'], }, }) }) it('can generate data correctly with empty username', () => { const state = { mainUsername: 'mainUser', crawlers: { cr1: { name: 'cr1', }, cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: '', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, { username: '', status: 'DONE', submissions: 33, solved: 22, errorMessage: '.....', solvedList: ['1', '2'], tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } const result = store.getUsernameObjectFromState(state) expect(result).toMatchObject({ main: 'mainUser', subs: { cr1: ['user1', ''], cr2: [''], }, }) }) }) describe('addProblemPrefix', () => { it('can get correct result', () => { const res = store.addProblemPrefix(['1001', '1002'], 'A') expect(res).toMatchObject(['A-1001', 'A-1002']) }) }) describe('pushSet', () => { it('can get correct result', () => { const set = new Set([1, 2]) store.pushSet(set, [2, 3]) expect(set).toMatchObject(new Set([1, 2, 3])) }) }) }) describe('actions', () => { describe('startOne', () => { it('can be executed correctly', async () => { const state = { crawlers: { cr1: { // mock at file beginning ({submissions: 10, solved: 5, solvedList: ['1001','1002']}), name: 'cr1', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 0, solved: 0, errorMessage: '.....', solvedList: [], tokenKey: 0.23333, crawlerName: 'cr1', key: 0.6666666, }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations }) await store.actions.startOne({ state, commit: actionTester.getCommiter() }, { index: 0 }) const history = actionTester.getCommitHistory() expect(history).toHaveLength(2) expect(state).toMatchObject({ crawlers: { cr1: { name: 'cr1', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 10, solved: 5, solvedList: ['1001', '1002'], errorMessage: '', tokenKey: expect.any(Number), crawlerName: 'cr1', key: 0.6666666, }, ], }) }) it('can work correctly when crawler does not return ac list', async () => { const state = { crawlers: { cr3: { name: 'cr3', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 0, solved: 0, errorMessage: '.....', solvedList: [], tokenKey: 0.23333, crawlerName: 'cr3', key: 0.6666666, }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations }) await store.actions.startOne({ state, commit: actionTester.getCommiter() }, { index: 0 }) const history = actionTester.getCommitHistory() expect(history).toHaveLength(2) expect(state).toMatchObject({ crawlers: { cr3: { name: 'cr3', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 10, solved: 1, solvedList: null, errorMessage: '', tokenKey: expect.any(Number), crawlerName: 'cr3', key: 0.6666666, }, ], }) }) it('can set status when crawler throw error', async () => { const state = { crawlers: { cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations }) await store.actions.startOne({ state, commit: actionTester.getCommiter() }, { index: 0 }) const history = actionTester.getCommitHistory() expect(history).toHaveLength(2) expect(state).toMatchObject({ crawlers: { cr2: { name: 'cr2', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 0, solved: 0, solvedList: [], errorMessage: 'The user does not exist', tokenKey: expect.any(Number), crawlerName: 'cr2', key: 0.6666666, }, ], }) }) it('will not submit result when tokenKey has been changed', async () => { const state = { crawlers: { cr3: { name: 'cr3', }, }, workers: [ { username: 'user1', status: 'DONE', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr3', key: 0.6666666, }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations }) // Execute current frame const promise = store.actions.startOne({ state, commit: actionTester.getCommiter() }, { index: 0 }) // tokenKey should be set before query expect(state.workers[0].tokenKey).toBeTruthy() // reset tokenKey state.workers[0].tokenKey = null // start query await promise const history = actionTester.getCommitHistory() expect(history).toHaveLength(1) expect(state).toMatchObject({ crawlers: { cr3: { name: 'cr3', }, }, workers: [ { username: 'user1', // state is not updated due to query cancellation status: 'WORKING', submissions: 0, solved: 0, solvedList: [], errorMessage: '', tokenKey: null, crawlerName: 'cr3', key: 0.6666666, }, ], }) }) it('does not query when username is empty', async () => { const state = { crawlers: { cr1: { name: 'cr2', }, }, workers: [ { username: '', status: 'DONE', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations }) // Execute current frame await store.actions.startOne({ state, commit: actionTester.getCommiter() }, { index: 0 }) const history = actionTester.getCommitHistory() expect(history).toHaveLength(0) expect(state).toMatchObject({ crawlers: { cr1: { name: 'cr2', }, }, workers: [ { username: '', status: 'DONE', submissions: 0, solved: 0, solvedList: [], errorMessage: '.....', tokenKey: 0.23333, crawlerName: 'cr2', key: 0.6666666, }, ], }) }) }) describe('addWorkerForCrawler', () => { it('can add worker correctly', () => { const state = { crawlers: { cr1: { name: 'cr1', }, }, } const actionTester = new StoreContextSimulator() store.actions.addWorkerForCrawler( { state, commit: actionTester.getCommiter() }, { crawlerName: 'cr1' }) const history = actionTester.getCommitHistory() expect(history).toHaveLength(1) expect(history[0]).toMatchObject({ type: 'addWorkerForCrawler', payload: { crawlerName: 'cr1' }, }) }) it('can throw when crawler does not exist', () => { const state = { crawlers: {}, } const actionTester = new StoreContextSimulator() const action = () => { store.actions.addWorkerForCrawler( { state, commit: actionTester.getCommiter() }, { crawlerName: 'cr1' }) } expect(action).toThrow('Crawler does not exist') const history = actionTester.getCommitHistory() expect(history).toHaveLength(0) }) }) describe('removeWorkerAtIndex', () => { it('can remove worker', () => { const state = { workers: [ { username: 'user1', crawlerName: 'cr1', }, { username: 'user2', crawlerName: 'cr1', }, ], } const actionTester = new StoreContextSimulator(state, { mutations: store.mutations, getters: store.getters }) store.actions.removeWorkerAtIndex( { state, commit: actionTester.getCommiter(), getters: actionTester.getGetters() }, { index: 0 }) expect(actionTester.getCommitHistory()).toHaveLength(1) expect(state).toMatchObject({ workers: [ { username: 'user2', crawlerName: 'cr1', }, ], }) }) }) }) ================================================ FILE: frontend/app.html ================================================ {{ HEAD }} {{ APP }} ================================================ FILE: frontend/assets/README.md ================================================ # ASSETS This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. More information about the usage of this directory in the documentation: https://nuxtjs.org/guide/assets#webpacked **This directory is not required, you can delete it if you don't want to use it.** ================================================ FILE: frontend/assets/style/app.scss ================================================ @import "~vuetify/src/styles/styles.sass"; // override default font $body-font-family: "Noto Serif SC", sans-serif; $heading-font-family: $body-font-family; @each $heading, $style in $headings { $headings: map-merge( $headings, ( $heading: map-merge( $style, ( "font-family": $heading-font-family ) ) ) ); } // page transitions .page-enter-active, .page-leave-active { transition: opacity 0.2s; } .page-enter, .page-leave-to { opacity: 0; } @import "~vuetify/src/styles/main.sass"; ================================================ FILE: frontend/babel.config.js ================================================ module.exports = api => { const isTest = api.env('test') if (!isTest) { throw new Error('the config is only for jest test') } return { plugins: [ '@babel/plugin-transform-runtime', ], presets: [['@babel/preset-env', { modules: false }]], env: { test: { presets: [['@babel/preset-env', { targets: { node: 'current' } }]], }, }, } } ================================================ FILE: frontend/base.Dockerfile ================================================ ARG CRAWLER_IMAGE ARG NODE_BASE_IMAGE FROM ${CRAWLER_IMAGE} AS crawler FROM ${NODE_BASE_IMAGE} WORKDIR /var/project RUN apk add --no-cache make gcc g++ python3 COPY --from=crawler /var/project ../crawler COPY package.json pnpm-lock.yaml .npmrc ./ RUN pnpm install COPY . . ENV VERSION_NUM=development ENV BUILD_TIME=0 ENV NODE_OPTIONS=--openssl-legacy-provider ================================================ FILE: frontend/components/GithubButton.vue ================================================ ================================================ FILE: frontend/components/MessagePanel.vue ================================================ ================================================ FILE: frontend/components/README.md ================================================ # COMPONENTS The components directory contains your Vue.js Components. Nuxt.js doesn't supercharge these components. **This directory is not required, you can delete it if you don't want to use it.** ================================================ FILE: frontend/components/ResultOverlay.vue ================================================ ================================================ FILE: frontend/components/UserStatus.vue ================================================ ================================================ FILE: frontend/components/WorkerCard.vue ================================================ ================================================ FILE: frontend/components/consts.js ================================================ export const WORKER_STATUS = { WAITING: 'WAITING', WORKING: 'WORKING', DONE: 'DONE', } export const PROJECT_TITLE = 'OJ Analyzer' export const TIMEZONE_LIST = [ { value: 'UTC', text: '(GMT) UTC' }, { value: 'Morocco Standard Time', text: '(GMT) Casablanca' }, { value: 'GMT Standard Time', text: '(GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London' }, { value: 'Greenwich Standard Time', text: '(GMT) Monrovia, Reykjavik' }, { value: 'W. Europe Standard Time', text: '(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' }, { value: 'Central Europe Standard Time', text: '(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague' }, { value: 'Romance Standard Time', text: '(GMT+01:00) Brussels, Copenhagen, Madrid, Paris' }, { value: 'Central European Standard Time', text: '(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb' }, { value: 'W. Central Africa Standard Time', text: '(GMT+01:00) West Central Africa' }, { value: 'Jordan Standard Time', text: '(GMT+02:00) Amman' }, { value: 'GTB Standard Time', text: '(GMT+02:00) Athens, Bucharest, Istanbul' }, { value: 'Middle East Standard Time', text: '(GMT+02:00) Beirut' }, { value: 'Egypt Standard Time', text: '(GMT+02:00) Cairo' }, { value: 'South Africa Standard Time', text: '(GMT+02:00) Harare, Pretoria' }, { value: 'FLE Standard Time', text: '(GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius' }, { value: 'Israel Standard Time', text: '(GMT+02:00) Jerusalem' }, { value: 'E. Europe Standard Time', text: '(GMT+02:00) Minsk' }, { value: 'Namibia Standard Time', text: '(GMT+02:00) Windhoek' }, { value: 'Arabic Standard Time', text: '(GMT+03:00) Baghdad' }, { value: 'Arab Standard Time', text: '(GMT+03:00) Kuwait, Riyadh' }, { value: 'Russian Standard Time', text: '(GMT+03:00) Moscow, St. Petersburg, Volgograd' }, { value: 'E. Africa Standard Time', text: '(GMT+03:00) Nairobi' }, { value: 'Georgian Standard Time', text: '(GMT+03:00) Tbilisi' }, { value: 'Iran Standard Time', text: '(GMT+03:30) Tehran' }, { value: 'Arabian Standard Time', text: '(GMT+04:00) Abu Dhabi, Muscat' }, { value: 'Azerbaijan Standard Time', text: '(GMT+04:00) Baku' }, { value: 'Mauritius Standard Time', text: '(GMT+04:00) Port Louis' }, { value: 'Caucasus Standard Time', text: '(GMT+04:00) Yerevan' }, { value: 'Afghanistan Standard Time', text: '(GMT+04:30) Kabul' }, { value: 'Ekaterinburg Standard Time', text: '(GMT+05:00) Ekaterinburg' }, { value: 'Pakistan Standard Time', text: '(GMT+05:00) Islamabad, Karachi' }, { value: 'West Asia Standard Time', text: '(GMT+05:00) Tashkent' }, { value: 'India Standard Time', text: '(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi' }, { value: 'Sri Lanka Standard Time', text: '(GMT+05:30) Sri Jayawardenepura' }, { value: 'Nepal Standard Time', text: '(GMT+05:45) Kathmandu' }, { value: 'N. Central Asia Standard Time', text: '(GMT+06:00) Almaty, Novosibirsk' }, { value: 'Central Asia Standard Time', text: '(GMT+06:00) Astana, Dhaka' }, { value: 'Myanmar Standard Time', text: '(GMT+06:30) Yangon (Rangoon)' }, { value: 'SE Asia Standard Time', text: '(GMT+07:00) Bangkok, Hanoi, Jakarta' }, { value: 'North Asia Standard Time', text: '(GMT+07:00) Krasnoyarsk' }, { value: 'China Standard Time', text: '(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi' }, { value: 'North Asia East Standard Time', text: '(GMT+08:00) Irkutsk, Ulaan Bataar' }, { value: 'Singapore Standard Time', text: '(GMT+08:00) Kuala Lumpur, Singapore' }, { value: 'W. Australia Standard Time', text: '(GMT+08:00) Perth' }, { value: 'Taipei Standard Time', text: '(GMT+08:00) Taipei' }, { value: 'Tokyo Standard Time', text: '(GMT+09:00) Osaka, Sapporo, Tokyo' }, { value: 'Korea Standard Time', text: '(GMT+09:00) Seoul' }, { value: 'Yakutsk Standard Time', text: '(GMT+09:00) Yakutsk' }, { value: 'Cen. Australia Standard Time', text: '(GMT+09:30) Adelaide' }, { value: 'AUS Central Standard Time', text: '(GMT+09:30) Darwin' }, { value: 'E. Australia Standard Time', text: '(GMT+10:00) Brisbane' }, { value: 'AUS Eastern Standard Time', text: '(GMT+10:00) Canberra, Melbourne, Sydney' }, { value: 'West Pacific Standard Time', text: '(GMT+10:00) Guam, Port Moresby' }, { value: 'Tasmania Standard Time', text: '(GMT+10:00) Hobart' }, { value: 'Vladivostok Standard Time', text: '(GMT+10:00) Vladivostok' }, { value: 'Central Pacific Standard Time', text: '(GMT+11:00) Magadan, Solomon Is., New Caledonia' }, { value: 'New Zealand Standard Time', text: '(GMT+12:00) Auckland, Wellington' }, { value: 'Fiji Standard Time', text: '(GMT+12:00) Fiji, Kamchatka, Marshall Is.' }, { value: 'Tonga Standard Time', text: '(GMT+13:00) Nuku\'alofa' }, { value: 'Azores Standard Time', text: '(GMT-01:00) Azores' }, { value: 'Cape Verde Standard Time', text: '(GMT-01:00) Cape Verde Is.' }, { value: 'Mid-Atlantic Standard Time', text: '(GMT-02:00) Mid-Atlantic' }, { value: 'E. South America Standard Time', text: '(GMT-03:00) Brasilia' }, { value: 'Argentina Standard Time', text: '(GMT-03:00) Buenos Aires' }, { value: 'SA Eastern Standard Time', text: '(GMT-03:00) Georgetown' }, { value: 'Greenland Standard Time', text: '(GMT-03:00) Greenland' }, { value: 'Montevideo Standard Time', text: '(GMT-03:00) Montevideo' }, { value: 'Newfoundland Standard Time', text: '(GMT-03:30) Newfoundland' }, { value: 'Atlantic Standard Time', text: '(GMT-04:00) Atlantic Time (Canada)' }, { value: 'SA Western Standard Time', text: '(GMT-04:00) La Paz' }, { value: 'Central Brazilian Standard Time', text: '(GMT-04:00) Manaus' }, { value: 'Pacific SA Standard Time', text: '(GMT-04:00) Santiago' }, { value: 'Venezuela Standard Time', text: '(GMT-04:30) Caracas' }, { value: 'SA Pacific Standard Time', text: '(GMT-05:00) Bogota, Lima, Quito, Rio Branco' }, { value: 'Eastern Standard Time', text: '(GMT-05:00) Eastern Time (US & Canada)' }, { value: 'US Eastern Standard Time', text: '(GMT-05:00) Indiana (East)' }, { value: 'Central America Standard Time', text: '(GMT-06:00) Central America' }, { value: 'Central Standard Time', text: '(GMT-06:00) Central Time (US & Canada)' }, { value: 'Central Standard Time (Mexico)', text: '(GMT-06:00) Guadalajara, Mexico City, Monterrey' }, { value: 'Canada Central Standard Time', text: '(GMT-06:00) Saskatchewan' }, { value: 'US Mountain Standard Time', text: '(GMT-07:00) Arizona' }, { value: 'Mountain Standard Time (Mexico)', text: '(GMT-07:00) Chihuahua, La Paz, Mazatlan' }, { value: 'Mountain Standard Time', text: '(GMT-07:00) Mountain Time (US & Canada)' }, { value: 'Pacific Standard Time', text: '(GMT-08:00) Pacific Time (US & Canada)' }, { value: 'Pacific Standard Time (Mexico)', text: '(GMT-08:00) Tijuana, Baja California' }, { value: 'Alaskan Standard Time', text: '(GMT-09:00) Alaska' }, { value: 'Hawaiian Standard Time', text: '(GMT-10:00) Hawaii' }, { value: 'Samoa Standard Time', text: '(GMT-11:00) Midway Island, Samoa' }, { value: 'Dateline Standard Time', text: '(GMT-12:00) International Date Line West' }, ] ================================================ FILE: frontend/components/rulesMixin.js ================================================ export default { data() { return { rules: { required: value => !!value || 'Required', email: value => /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ .test(value) || 'Please enter a valid email address.', // from http://regexlib.com/REDetails.aspx?regexp_id=1923 password: value => /(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$/ .test(value) || 'Passwords must be at least 8 characters, contain a lowercase, uppercase, and number.', }, } }, } ================================================ FILE: frontend/components/statisticsLayoutBuilder.js ================================================ /** * 确定查题页面中 worker 的排列方式。使用竖向排列: * 1 5 9 * 2 6 10 * 3 7 * 4 8 * * 多余的会从第一列向后补充 * @param workers {Array<{Object}>} * @param columnNum {number} */ export default function (workers, columnNum) { const length = workers.length const maxItemNumberInColumn = Math.ceil(length / columnNum) const layout = new Array(columnNum) let i = 0 // 填充除了最后一列之外的其他列 for (let column = 0; column < columnNum - 1; ++column) { // 填充一列(这时候即使遍历完所有除了最后一列之外的列,也不可能用完 worker) layout[column] = new Array(maxItemNumberInColumn) for (let j = 0; j < maxItemNumberInColumn; ++j) { layout[column][j] = i ++i } } // 填充剩余的 worker (此时worker数量一定小于总体的列数) layout[columnNum - 1] = [] for (; i < length; ++i) { layout[columnNum - 1].push(i) } return layout } ================================================ FILE: frontend/components/statisticsUtils.js ================================================ import _ from 'lodash' /** * 根据 worker 信息生成对应的警告 * @param worker * @param crawlerMeta * @param nullSolvedListCrawlers * @param workerNumberOfCrawler * @return {Array} */ export function warningHelper(worker, crawlerMeta, {nullSolvedListCrawlers, workerNumberOfCrawler}) { const warnings = [] if (_.startsWith(worker.username, ' ')) { warnings.push('Your username begins with a space.') } if (_.includes(worker.username, ' ')) { warnings.push('Your username includes space, which may not be supported by some crawlers.') } if (crawlerMeta.virtual_judge && worker.solvedList) { const allCrawlerNames = new Set(_.map( worker.solvedList, item => _.split(item, '-', 2)[0])) for (let item of allCrawlerNames) { if (item in nullSolvedListCrawlers) { warnings.push(`Crawler ${nullSolvedListCrawlers[item]} did not return AC problem list, its result may overlap with this crawler's`) } } } if (!crawlerMeta.virtual_judge && worker.solvedList === null && workerNumberOfCrawler[worker.crawlerName] >= 2) { warnings.push('This crawler did not return AC problem list, so the same problem in different OJs can be recognized as different problems.') } if (!_.isNil(worker.solvedList) && worker.solvedList.length !== worker.solved) { warnings.push(`The solved number of this crawler is ${worker.solved}, however, there are ${worker.solvedList.length}` + ' problems in the solved list, which can be an error of the crawler.') } return warnings } /** * 在 vjudge 中,如果返回的 ac 题目列表包含了支持的爬虫,将其名称换成 爬虫的 title,否则保留原来的名称 * @param {String[]} solvedList * @param {{title: String}} crawlers * @return {String[]} */ export function mapVirtualJudgeProblemTitle(solvedList, crawlers) { return _.map(solvedList, item => { const [oj, problem] = _.split(item, '-', 2) if (oj in crawlers) { return `${crawlers[oj].title}-${problem}` } else { return item } }) } ================================================ FILE: frontend/components/utils.js ================================================ import _ from 'lodash' /** * 从 linux 格式的 timestamp(精确到秒)生成 javascript 的 Date 格式的对象 * @param {string} timestamp * @return {Date} */ export function getDateFromTimestamp(timestamp) { return new Date(parseInt(timestamp) * 1000) } /** * 从axios访问abp的异常中找出错误信息 * @param {Error} err axios抛出的异常 */ export function getAbpErrorMessage(err) { console.error(err) return _.get(err, 'response.data.error.message', 'Network Error') } // from https://stackoverflow.com/a/39538518 export function delay(t, v) { return new Promise(function (resolve) { setTimeout(resolve.bind(null, v), t) }) } ================================================ FILE: frontend/configs/sensitive-url-router.js ================================================ const { sortRoutes } = require('@nuxt/utils') const sensitiveRoutes = [ '/index.html', '/index.php', '/index.jsp', '/admin/', '/wp-login.php', '/readme.html', '/license.txt', '/wp-includes/js/wplink.js', '/wp-admin/js/customize-controls.js', '/wp-admin/js/nav-menu.js', '/wp-includes/js/plupload', '/wp-includes/js/tinymce/', '/README', '/phpMyAdmin/', '/phpmyadmin/', '/pma/', '/solr/', '/wcm/', '/swagger/elpsycongroo', '/ZeroClipboard.swf', '/js/ZeroClipboard.swf', '/script/ZeroClipboard.swf', '/lib/ZeroClipboard.swf', '/api.php', '/checktable.php', '/theme/default/images/kindeditor/save.gif', '/js/kindeditor/Makefile', '/theme/default/images/treeview/file.gif', '/js/jquery/treeview/min.js', '/theme/default/images/main/logo.png', '/js/jquery/syntaxhighlighter/scripts/shBrushPlain.js', '/theme/default/style.css', '/js/my.full.js', '/theme/zui/fonts/zenicon.eot', '/README.md', ] module.exports = function (routes, resolve) { for (let route of sensitiveRoutes) { routes.push({ path: route, component: resolve(__dirname, '../pages/jojo.vue'), }) } sortRoutes(routes) } ================================================ FILE: frontend/layouts/README.md ================================================ # LAYOUTS This directory contains your Application Layouts. More information about the usage of this directory in the documentation: https://nuxtjs.org/guide/views#layouts **This directory is not required, you can delete it if you don't want to use it.** ================================================ FILE: frontend/layouts/default.vue ================================================ ================================================ FILE: frontend/layouts/error.vue ================================================ ================================================ FILE: frontend/layouts/login.vue ================================================ ================================================ FILE: frontend/layouts/none.vue ================================================ ================================================ FILE: frontend/middleware/README.md ================================================ # MIDDLEWARE This directory contains your Application Middleware. The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). More information about the usage of this directory in the documentation: https://nuxtjs.org/guide/routing#middleware **This directory is not required, you can delete it if you don't want to use it.** ================================================ FILE: frontend/middleware/auth.js ================================================ /** * 用来管理页面访问的中间件 * @param {Context} param0 nuxt context */ export default function ({ route, redirect, store }) { switch (route.path) { case '/login': case '/register': if (store.state.session.login) { redirect('/settings') } break case '/settings': if (!store.state.session.login) { redirect('/login') } break } } ================================================ FILE: frontend/modules/crawlerLoader/README.md ================================================ crawlerLoader ============================ 专门用来引入爬虫的库。 ## 引入原因 由于需要让爬虫同时在前端和后端工作,且使用同一套源代码, 本项目采用的方式是将爬虫的源代码在编译期间进行处理,然后作为 Plugin 引入页面中。loader 对爬虫的源代码进行了特殊的处理,server_only 的爬虫会被转换成一个对服务端的 ajax 请求,使用 axios 发送;其他爬虫使用 superagent 直接在浏览器端发起爬取请求。 本项目同时使用了两套 request 库(axios, superagent),axios专门用来向 服务端发送 ajax 请求,superagent 只用在爬虫中。 ## 关于 `cors.js` 由于浏览器端的爬虫需要绕过“跨域请求限制”,我对 superagent 进行了一些魔改, 因此在前端的 superagent 只能用在爬虫上。 参见 [cors.js](./cors.js) 我采用前端爬虫的原因就是为了减轻服务器的负担,使用 cors-proxy 把请求操作转移 到别人的服务器上也不失为一种好办法_(:3」∠)_ ================================================ FILE: frontend/modules/crawlerLoader/cors.js ================================================ /** * 魔改 superagent 以解决同源问题——使用 cors proxy */ import superagent from 'superagent' const corsProxyUrl = 'https://cors.ojhunt.com/' const getFunc = superagent.get const postFunc = superagent.post superagent.get = function (url) { // eslint-disable-next-line lodash/prefer-lodash-method if (url.startsWith('/')) { // 调用爬虫API return getFunc(url) } else { return getFunc(corsProxyUrl + url) } } superagent.post = function (url) { // eslint-disable-next-line lodash/prefer-lodash-method if (url.startsWith('/')) { // 调用爬虫API return postFunc(url) } else { return postFunc(corsProxyUrl + url) } } ================================================ FILE: frontend/modules/crawlerLoader/index.js ================================================ const {readMetaConfigs, generateBrowserCrawlerFunctions} = require('crawler') const path = require('path') const fs = require('fs-extra') const VirtualModulePlugin = require('webpack-virtual-modules') async function buildSources() { const corsModule = await fs.readFile(path.join(__dirname, 'cors.js'), 'utf-8') let crawlersModule = ` /* eslint-disable */ ${corsModule} export default () => { const metas = ${JSON.stringify(await readMetaConfigs())}; const crawlers = { ` const functions = await generateBrowserCrawlerFunctions() for (let key in functions) { crawlersModule += `${key}: ${functions[key]},\n` } crawlersModule += ` } return { metas, crawlers, } }` return crawlersModule } module.exports = async function () { this.options.build.plugins.push(new VirtualModulePlugin({ 'dynamic/crawlers.js': await buildSources(), })) } ================================================ FILE: frontend/nuxt.config.js ================================================ // eslint-disable-next-line no-unused-vars const resolve = (dir) => require('path').join(__dirname, dir) const _ = require('lodash') const sensitiveRouter = require('./configs/sensitive-url-router') const { readMetaConfigs } = require('crawler') module.exports = async () => ({ /* ** Headers of the page */ head: { title: 'OJ Analyzer', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'An online tool (crawler) to analyze users performance in online judges (coding competition websites). ' + 'Supported OJ: ' + _.map(await readMetaConfigs(), 'title').join(', '), }, ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Noto+Serif+SC:300,400,500,700' }, ], }, plugins: [ '~/plugins/debug.js', '~/plugins/font.js', { src: '~/plugins/chartjs.js', mode: 'client' }, ], css: [ '~/assets/style/app.scss', ], /* ** Customize the progress bar color */ loading: { color: '#3B8070' }, /* ** Build configuration */ build: { babel: { plugins: [ 'lodash', ], }, extractCSS: true, terser: { terserOptions: { compress: { drop_console: true, }, }, }, }, modules: [ '~/modules/crawlerLoader', '@nuxtjs/component-cache', ['nuxt-env', { keys: ['VERSION_NUM', 'BUILD_TIME'], }], ['@nuxtjs/axios', { baseURL: 'http://reverse-proxy', browserBaseURL: '/', debug: true, }], ], buildModules: [ '@nuxtjs/eslint-module', '@nuxtjs/vuetify', ], vuetify: { optionsPath: './vuetify.options.js', }, watchers: { // 尽管这是文档里的默认值,但是不设置它的话并不会生效。估计这是一个bug webpack: { aggregateTimeout: 300, poll: 1000, }, }, router: { extendRoutes: sensitiveRouter, middleware: [ 'auth', ], }, }) ================================================ FILE: frontend/package.json ================================================ { "name": "acm-statistics-frontend", "version": "1.0.0", "description": "ACM查题网站前端", "author": "Liu233w ", "private": true, "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue .", "lintfix": "eslint --fix --ext .js,.vue .", "analyze": "nuxt build --analyze", "test": "jest __test__/", "snapshot": "jest __test__/ --watch" }, "dependencies": { "@fortawesome/fontawesome-free": "6.7.2", "@nuxtjs/axios": "5.13.6", "@nuxtjs/component-cache": "1.1.6", "@nuxtjs/vuetify": "1.12.3", "chart.js": "3.9.1", "cheerio": "1.0.0-rc.10", "crawler": "link:../crawler", "html2canvas": "1.4.1", "js-cookie": "3.0.5", "lodash": "4.17.23", "nuxt": "2.16.3", "nuxt-env": "0.1.0", "stylus": "0.64.0", "superagent": "8.1.2", "vue-chartjs": "4.1.2", "webpack-virtual-modules": "0.6.2" }, "devDependencies": { "@babel/core": "7.22.1", "@babel/preset-env": "7.22.2", "@mdi/font": "7.4.47", "@nuxtjs/eslint-module": "4.1.0", "@vue/test-utils": "1.3.6", "@vue/vue2-jest": "29.2.6", "babel-jest": "29.7.0", "babel-plugin-lodash": "3.3.4", "eslint": "8.57.1", "eslint-plugin-jest": "27.9.0", "eslint-plugin-lodash": "7.4.0", "eslint-plugin-vue": "9.33.0", "eslint-plugin-vuetify": "1.1.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-serializer-vue": "3.1.0", "stylus-loader": "7.1.3", "typescript": "5.9.3" }, "jest": { "moduleFileExtensions": [ "js", "json", "vue" ], "snapshotSerializers": [ "jest-serializer-vue" ], "transform": { "^.+\\.js$": "/node_modules/babel-jest", ".*\\.(vue)$": "@vue/vue2-jest" }, "transformIgnorePatterns": [ "/node_modules/" ], "moduleNameMapper": { "~(?!/dynamic)(.*)$": "/$1" }, "coverageDirectory": "./coverage/", "collectCoverage": true } } ================================================ FILE: frontend/pages/README.md ================================================ # PAGES This directory contains your Application Views and Routes. The framework reads all the .vue files inside this directory and creates the router of your application. More information about the usage of this directory in the documentation: https://nuxtjs.org/guide/routing ================================================ FILE: frontend/pages/about.vue ================================================ ================================================ FILE: frontend/pages/history/_id/-GoHistoryPage.vue ================================================ ================================================ FILE: frontend/pages/history/_id/-HistoryToolbar.vue ================================================ ================================================ FILE: frontend/pages/history/_id/index.vue ================================================ ================================================ FILE: frontend/pages/history/index.vue ================================================ ================================================ FILE: frontend/pages/index.vue ================================================ ================================================ FILE: frontend/pages/jojo.vue ================================================ ================================================ FILE: frontend/pages/login.vue ================================================ ================================================ FILE: frontend/pages/register.vue ================================================ ================================================ FILE: frontend/pages/settings.vue ================================================ ================================================ FILE: frontend/pages/statistics.vue ================================================ ================================================ FILE: frontend/plugins/README.md ================================================ # PLUGINS This directory contains your Javascript plugins that you want to run before instantiating the root vue.js application. More information about the usage of this directory in the documentation: https://nuxtjs.org/guide/plugins **This directory is not required, you can delete it if you don't want to use it.** ================================================ FILE: frontend/plugins/chartjs.js ================================================ import 'chart.js/auto' import { Line, Bar } from 'vue-chartjs/legacy' import Vue from 'vue' Vue.component('LineChart', Line) Vue.component('BarChart', Bar) ================================================ FILE: frontend/plugins/debug.js ================================================ import axios from 'axios' import Vue from 'vue' // eslint-disable-next-line no-unused-vars export default ({app}, inject) => { if (app.context.isDev && process.client) { window.$app = app window.$axios = axios // 打开性能分析 Vue.config.performance = true } } ================================================ FILE: frontend/plugins/font.js ================================================ import '@fortawesome/fontawesome-free/css/all.css' import '@mdi/font/css/materialdesignicons.css' ================================================ FILE: frontend/release.Dockerfile ================================================ ARG FRONTEND_BASE_IMAGE ARG NODE_BASE_IMAGE ARG CRAWLER_IMAGE FROM ${CRAWLER_IMAGE} AS crawler FROM ${FRONTEND_BASE_IMAGE} AS base RUN pnpm run build RUN rm -rf node_modules FROM ${NODE_BASE_IMAGE} ARG VERSION_NUM ARG BUILD_TIME WORKDIR /var/project COPY --from=crawler /var/project ../crawler COPY package.json pnpm-lock.yaml .npmrc ./ RUN pnpm install --only=production COPY --from=base /var/project . ENV \ HOST=0.0.0.0 \ NODE_ENV=production \ PORT=3000 \ VERSION_NUM="${VERSION_NUM}" \ BUILD_TIME="${BUILD_TIME}" \ ;=; EXPOSE 3000 CMD ["pnpm", "start"] ================================================ FILE: frontend/static/google90cac42981c276fb.html ================================================ google-site-verification: google90cac42981c276fb.html ================================================ FILE: frontend/static/swagger/abp.js ================================================ var abp = abp || {}; (function () { /* Application paths *****************************************/ // Current application root path (including virtual directory if exists). abp.appPath = abp.appPath || '/'; /* AUTHORIZATION **********************************************/ // Implements Authorization API that simplifies usage of authorization scripts generated by Abp. abp.auth = abp.auth || {}; abp.auth.tokenCookieName = 'Abp.AuthToken'; abp.auth.tokenHeaderName = 'Authorization'; abp.auth.setToken = function (authToken, expireDate) { abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath); }; abp.auth.getToken = function () { return abp.utils.getCookieValue(abp.auth.tokenCookieName); } abp.auth.clearToken = function () { abp.auth.setToken(); } /* UTILS ***************************************************/ abp.utils = abp.utils || {}; /** * Sets a cookie value for given key. * This is a simple implementation created to be used by ABP. * Please use a complete cookie library if you need. * @param {string} key * @param {string} value * @param {Date} expireDate (optional). If not specified the cookie will expire at the end of session. * @param {string} path (optional) */ abp.utils.setCookieValue = function (key, value, expireDate, path) { var cookieValue = encodeURIComponent(key) + '='; if (value) { cookieValue = cookieValue + encodeURIComponent(value); } if (expireDate) { cookieValue = cookieValue + "; expires=" + expireDate.toUTCString(); } if (path) { cookieValue = cookieValue + "; path=" + path; } document.cookie = cookieValue; }; /** * Gets a cookie with given key. * This is a simple implementation created to be used by ABP. * Please use a complete cookie library if you need. * @param {string} key * @returns {string} Cookie value or null */ abp.utils.getCookieValue = function (key) { var equalities = document.cookie.split('; '); for (var i = 0; i < equalities.length; i++) { if (!equalities[i]) { continue; } var splitted = equalities[i].split('='); if (splitted.length != 2) { continue; } if (decodeURIComponent(splitted[0]) === key) { return decodeURIComponent(splitted[1] || ''); } } return null; }; /** * Deletes cookie for given key. * This is a simple implementation created to be used by ABP. * Please use a complete cookie library if you need. * @param {string} key * @param {string} path (optional) */ abp.utils.deleteCookie = function (key, path) { var cookieValue = encodeURIComponent(key) + '='; cookieValue = cookieValue + "; expires=" + (new Date(new Date().getTime() - 86400000)).toUTCString(); if (path) { cookieValue = cookieValue + "; path=" + path; } document.cookie = cookieValue; } /* SECURITY ***************************************/ abp.security = abp.security || {}; abp.security.antiForgery = abp.security.antiForgery || {}; abp.security.antiForgery.tokenCookieName = 'XSRF-TOKEN'; abp.security.antiForgery.tokenHeaderName = 'X-XSRF-TOKEN'; abp.security.antiForgery.getToken = function () { return abp.utils.getCookieValue(abp.security.antiForgery.tokenCookieName); }; })(); ================================================ FILE: frontend/static/swagger/abp.swagger.js ================================================ var abp = abp || {}; (function () { /* Swagger */ abp.swagger = abp.swagger || {}; abp.swagger.addAuthToken = function () { var authToken = abp.auth.getToken(); if (!authToken) { return false; } var cookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.auth.tokenHeaderName, 'Bearer ' + authToken, 'header'); swaggerUi.api.clientAuthorizations.add('bearerAuth', cookieAuth); return true; } abp.swagger.addCsrfToken = function () { var csrfToken = abp.security.antiForgery.getToken(); if (!csrfToken) { return false; } var csrfCookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.security.antiForgery.tokenHeaderName, csrfToken, 'header'); swaggerUi.api.clientAuthorizations.add(abp.security.antiForgery.tokenHeaderName, csrfCookieAuth); return true; } function addAntiForgeryTokenToXhr(xhr) { var antiForgeryToken = abp.security.antiForgery.getToken(); if (antiForgeryToken) { xhr.setRequestHeader(abp.security.antiForgery.tokenHeaderName, antiForgeryToken); } } function loginUserInternal(tenantId, callback) { var usernameOrEmailAddress = document.getElementById('userName').value; if (!usernameOrEmailAddress) { alert('Username or Email Address is required, please try with a valid value !'); return false; } var password = document.getElementById('password').value; if (!password) { alert('Password is required, please try with a valid value !'); return false; } var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { var responseJSON = JSON.parse(xhr.responseText); var result = responseJSON.result; var expireDate = new Date(Date.now() + (result.expireInSeconds * 1000)); abp.auth.setToken(result.accessToken, expireDate); callback(); } else { alert('Login failed !'); } } }; xhr.open('POST', '/api/TokenAuth/Authenticate', true); xhr.setRequestHeader('Abp.TenantId', tenantId); xhr.setRequestHeader('Content-type', 'application/json'); addAntiForgeryTokenToXhr(xhr); xhr.send( JSON.stringify( { usernameOrEmailAddress: usernameOrEmailAddress, password: password } ) ); } abp.swagger.login = function (callback) { //Get TenantId first var tenancyName = document.getElementById('tenancyName').value; if (tenancyName) { var xhrTenancyName = new XMLHttpRequest(); xhrTenancyName.onreadystatechange = function () { if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) { var responseJSON = JSON.parse(xhrTenancyName.responseText); var result = responseJSON.result; if (result.state === 1) { // Tenant exists and active. loginUserInternal(result.tenantId, callback); // Login for tenant } else { alert('There is no such tenant or tenant is not active !'); } } }; xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true); xhrTenancyName.setRequestHeader('Content-type', 'application/json'); addAntiForgeryTokenToXhr(xhrTenancyName); xhrTenancyName.send( JSON.stringify({ tenancyName: tenancyName }) ); } else { loginUserInternal(null, callback); // Login for host } }; abp.swagger.logout = function () { abp.auth.clearToken(); } abp.swagger.closeAuthDialog = function () { if (document.getElementById('abp-auth-dialog')) { document.getElementsByClassName("swagger-ui")[1].removeChild(document.getElementById('abp-auth-dialog')); } } abp.swagger.openAuthDialog = function (loginCallback) { abp.swagger.closeAuthDialog(); var abpAuthDialog = document.createElement('div'); abpAuthDialog.className = 'dialog-ux'; abpAuthDialog.id = 'abp-auth-dialog'; document.getElementsByClassName("swagger-ui")[1].appendChild(abpAuthDialog); // -- backdrop-ux var backdropUx = document.createElement('div'); backdropUx.className = 'backdrop-ux'; abpAuthDialog.appendChild(backdropUx); // -- modal-ux var modalUx = document.createElement('div'); modalUx.className = 'modal-ux'; abpAuthDialog.appendChild(modalUx); // -- -- modal-dialog-ux var modalDialogUx = document.createElement('div'); modalDialogUx.className = 'modal-dialog-ux'; modalUx.appendChild(modalDialogUx); // -- -- -- modal-ux-inner var modalUxInner = document.createElement('div'); modalUxInner.className = 'modal-ux-inner'; modalDialogUx.appendChild(modalUxInner); // -- -- -- -- modal-ux-header var modalUxHeader = document.createElement('div'); modalUxHeader.className = 'modal-ux-header'; modalUxInner.appendChild(modalUxHeader); var modalHeader = document.createElement('h3'); modalHeader.innerText = 'Authorize'; modalUxHeader.appendChild(modalHeader); // -- -- -- -- modal-ux-content var modalUxContent = document.createElement('div'); modalUxContent.className = 'modal-ux-content'; modalUxInner.appendChild(modalUxContent); modalUxContent.onkeydown = function (e) { if (e.keyCode === 13) { //try to login when user presses enter on authorize modal abp.swagger.login(loginCallback); } }; //Inputs createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)'); createInput(modalUxContent, 'userName', 'Username or email address'); createInput(modalUxContent, 'password', 'Password', 'password'); //Buttons var authBtnWrapper = document.createElement('div'); authBtnWrapper.className = 'auth-btn-wrapper'; modalUxContent.appendChild(authBtnWrapper); //Close button var closeButton = document.createElement('button'); closeButton.className = 'btn modal-btn auth btn-done button'; closeButton.innerText = 'Close'; closeButton.style.marginRight = '5px'; closeButton.onclick = abp.swagger.closeAuthDialog; authBtnWrapper.appendChild(closeButton); //Authorize button var authorizeButton = document.createElement('button'); authorizeButton.className = 'btn modal-btn auth authorize button'; authorizeButton.innerText = 'Login'; authorizeButton.onclick = function() { abp.swagger.login(loginCallback); }; authBtnWrapper.appendChild(authorizeButton); } function createInput(container, id, title, type) { var wrapper = document.createElement('div'); wrapper.className = 'wrapper'; container.appendChild(wrapper); var label = document.createElement('label'); label.innerText = title; wrapper.appendChild(label); var section = document.createElement('section'); section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop'; wrapper.appendChild(section); var input = document.createElement('input'); input.id = id; input.type = type ? type : 'text'; input.style.width = '100%'; section.appendChild(input); } })(); ================================================ FILE: frontend/static/swagger/index.html ================================================ Swagger UI
    ================================================ FILE: frontend/static/swagger/oauth2-redirect.html ================================================ ================================================ FILE: frontend/static/swagger/swagger-ui-bundle.js ================================================ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/dist",t(t.s=1229)}([function(e,t,n){"use strict";e.exports=n(92)},function(e,t,n){e.exports=n(1009)()},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){"use strict";t.__esModule=!0;var r=n(337),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(){function e(e,t){for(var n=0;n>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?d(e)+t:t}function v(){return!0}function g(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function y(e,t){return b(e,t,0)}function _(e,t){return b(e,t,t)}function b(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}function x(e){this.next=e}function w(e,t,n,r){var i=0===e?t:1===e?n:[t,n];return r?r.value=i:r={value:i,done:!1},r}function k(){return{value:void 0,done:!0}}function E(e){return!!A(e)}function S(e){return e&&"function"==typeof e.next}function C(e){var t=A(e);return t&&t.call(e)}function A(e){var t=e&&(wn&&e[wn]||e[kn]);if("function"==typeof t)return t}function D(e){return e&&"number"==typeof e.length}function O(e){return null===e||void 0===e?B():o(e)?e.toSeq():z(e)}function M(e){return null===e||void 0===e?B().toKeyedSeq():o(e)?a(e)?e.toSeq():e.fromEntrySeq():L(e)}function T(e){return null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e.toIndexedSeq():q(e)}function P(e){return(null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e:q(e)).toSetSeq()}function I(e){this._array=e,this.size=e.length}function R(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function j(e){this._iterable=e,this.size=e.length||e.size}function N(e){this._iterator=e,this._iteratorCache=[]}function F(e){return!(!e||!e[Sn])}function B(){return Cn||(Cn=new I([]))}function L(e){var t=Array.isArray(e)?new I(e).fromEntrySeq():S(e)?new N(e).fromEntrySeq():E(e)?new j(e).fromEntrySeq():"object"==typeof e?new R(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function q(e){var t=U(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function z(e){var t=U(e)||"object"==typeof e&&new R(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function U(e){return D(e)?new I(e):S(e)?new N(e):E(e)?new j(e):void 0}function W(e,t,n,r){var i=e._cache;if(i){for(var o=i.length-1,a=0;a<=o;a++){var s=i[n?o-a:a];if(!1===t(s[1],r?s[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function V(e,t,n,r){var i=e._cache;if(i){var o=i.length-1,a=0;return new x(function(){var e=i[n?o-a:a];return a++>o?k():w(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function H(e,t){return t?J(t,e,"",{"":e}):G(e)}function J(e,t,n,r){return Array.isArray(t)?e.call(r,n,T(t).map(function(n,r){return J(e,n,r,t)})):X(t)?e.call(r,n,M(t).map(function(n,r){return J(e,n,r,t)})):t}function G(e){return Array.isArray(e)?T(e).map(G).toList():X(e)?M(e).map(G).toMap():e}function X(e){return e&&(e.constructor===Object||void 0===e.constructor)}function Y(e,t){if(e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if(e=e.valueOf(),t=t.valueOf(),e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function K(e,t){if(e===t)return!0;if(!o(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||a(e)!==a(t)||s(e)!==s(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!u(e);if(l(e)){var r=e.entries();return t.every(function(e,t){var i=r.next().value;return i&&Y(i[1],e)&&(n||Y(i[0],t))})&&r.next().done}var i=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{i=!0;var c=e;e=t,t=c}var p=!0,f=t.__iterate(function(t,r){if(n?!e.has(t):i?!Y(t,e.get(r,vn)):!Y(e.get(r,vn),t))return p=!1,!1});return p&&e.size===f}function $(e,t){if(!(this instanceof $))return new $(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(An)return An;An=this}}function Z(e,t){if(!e)throw new Error(t)}function Q(e,t,n){if(!(this instanceof Q))return new Q(e,t,n);if(Z(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),t>>1&1073741824|3221225471&e}function oe(e){if(!1===e||null===e||void 0===e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!==e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)e/=4294967295,n^=e;return ie(n)}if("string"===t)return e.length>Nn?ae(e):se(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return ue(e);if("function"==typeof e.toString)return se(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ae(e){var t=Ln[e];return void 0===t&&(t=se(e),Bn===Fn&&(Bn=0,Ln={}),Bn++,Ln[e]=t),t}function se(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}function ce(e){Z(e!==1/0,"Cannot perform this action with an infinite size.")}function pe(e){return null===e||void 0===e?we():fe(e)&&!l(e)?e:we().withMutations(function(t){var r=n(e);ce(r.size),r.forEach(function(e,n){return t.set(n,e)})})}function fe(e){return!(!e||!e[qn])}function he(e,t){this.ownerID=e,this.entries=t}function de(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function me(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function ve(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function ge(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function ye(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&be(e._root)}function _e(e,t){return w(e,t[0],t[1])}function be(e,t){return{node:e,index:0,__prev:t}}function xe(e,t,n,r){var i=Object.create(zn);return i.size=e,i._root=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function we(){return Un||(Un=xe(0))}function ke(e,t,n){var r,i;if(e._root){var o=c(gn),a=c(yn);if(r=Ee(e._root,e.__ownerID,0,void 0,t,n,o,a),!a.value)return e;i=e.size+(o.value?n===vn?-1:1:0)}else{if(n===vn)return e;i=1,r=new he(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=i,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?xe(i,r):we()}function Ee(e,t,n,r,i,o,a,s){return e?e.update(t,n,r,i,o,a,s):o===vn?e:(p(s),p(a),new ge(t,r,[i,o]))}function Se(e){return e.constructor===ge||e.constructor===ve}function Ce(e,t,n,r,i){if(e.keyHash===r)return new ve(t,r,[e.entry,i]);var o,a=(0===n?e.keyHash:e.keyHash>>>n)&mn,s=(0===n?r:r>>>n)&mn;return new de(t,1<>>=1)a[s]=1&n?t[o++]:void 0;return a[r]=i,new me(e,o+1,a)}function Me(e,t,r){for(var i=[],a=0;a>1&1431655765,e=(858993459&e)+(e>>2&858993459),e=e+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function Ne(e,t,n,r){var i=r?e:h(e);return i[t]=n,i}function Fe(e,t,n,r){var i=e.length+1;if(r&&t+1===i)return e[t]=n,e;for(var o=new Array(i),a=0,s=0;s0&&io?0:o-n,l=a-n;return l>dn&&(l=dn),function(){if(i===l)return Yn;var e=t?--l:i++;return r&&r[e]}}function i(e,r,i){var s,u=e&&e.array,l=i>o?0:o-i>>r,c=1+(a-i>>r);return c>dn&&(c=dn),function(){for(;;){if(s){var e=s();if(e!==Yn)return e;s=null}if(l===c)return Yn;var o=t?--c:l++;s=n(u&&u[o],r-hn,i+(o<=e.size||t<0)return e.withMutations(function(e){t<0?Ye(e,t).set(0,n):Ye(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,i=e._root,o=c(yn);return t>=$e(e._capacity)?r=Je(r,e.__ownerID,0,t,n,o):i=Je(i,e.__ownerID,e._level,t,n,o),o.value?e.__ownerID?(e._root=i,e._tail=r,e.__hash=void 0,e.__altered=!0,e):We(e._origin,e._capacity,e._level,i,r):e}function Je(e,t,n,r,i,o){var a=r>>>n&mn,s=e&&a0){var l=e&&e.array[a],c=Je(l,t,n-hn,r,i,o);return c===l?e:(u=Ge(e,t),u.array[a]=c,u)}return s&&e.array[a]===i?e:(p(o),u=Ge(e,t),void 0===i&&a===u.array.length-1?u.array.pop():u.array[a]=i,u)}function Ge(e,t){return t&&e&&t===e.ownerID?e:new ze(e?e.array.slice():[],t)}function Xe(e,t){if(t>=$e(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&mn],r-=hn;return n}}function Ye(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new f,i=e._origin,o=e._capacity,a=i+t,s=void 0===n?o:n<0?o+n:i+n;if(a===i&&s===o)return e;if(a>=s)return e.clear();for(var u=e._level,l=e._root,c=0;a+c<0;)l=new ze(l&&l.array.length?[void 0,l]:[],r),u+=hn,c+=1<=1<p?new ze([],r):d;if(d&&h>p&&ahn;g-=hn){var y=p>>>g&mn;v=v.array[y]=Ge(v.array[y],r)}v.array[p>>>hn&mn]=d}if(s=h)a-=h,s-=h,u=hn,l=null,m=m&&m.removeBefore(r,0,a);else if(a>i||h>>u&mn;if(_!==h>>>u&mn)break;_&&(c+=(1<i&&(l=l.removeBefore(r,u,a-c)),l&&ha&&(a=l.size),o(u)||(l=l.map(function(e){return H(e)})),i.push(l)}return a>e.size&&(e=e.setSize(a)),Ie(e,t,i)}function $e(e){return e>>hn<=dn&&a.size>=2*o.size?(i=a.filter(function(e,t){return void 0!==e&&s!==t}),r=i.toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=i.__ownerID=e.__ownerID)):(r=o.remove(t),i=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=o,i=a.set(s,[t,n])}else r=o.set(t,a.size),i=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=i,e.__hash=void 0,e):et(r,i)}function rt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function it(e){this._iter=e,this.size=e.size}function ot(e){this._iter=e,this.size=e.size}function at(e){this._iter=e,this.size=e.size}function st(e){var t=Dt(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=Ot,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===xn){var r=e.__iterator(t,n);return new x(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===bn?_n:bn,n)},t}function ut(e,t,n){var r=Dt(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,i){var o=e.get(r,vn);return o===vn?i:t.call(n,o,r,e)},r.__iterateUncached=function(r,i){var o=this;return e.__iterate(function(e,i,a){return!1!==r(t.call(n,e,i,a),i,o)},i)},r.__iteratorUncached=function(r,i){var o=e.__iterator(xn,i);return new x(function(){var i=o.next();if(i.done)return i;var a=i.value,s=a[0];return w(r,s,t.call(n,a[1],s,e),i)})},r}function lt(e,t){var n=Dt(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=st(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=Ot,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function ct(e,t,n,r){var i=Dt(e);return r&&(i.has=function(r){var i=e.get(r,vn);return i!==vn&&!!t.call(n,i,r,e)},i.get=function(r,i){var o=e.get(r,vn);return o!==vn&&t.call(n,o,r,e)?o:i}),i.__iterateUncached=function(i,o){var a=this,s=0;return e.__iterate(function(e,o,u){if(t.call(n,e,o,u))return s++,i(e,r?o:s-1,a)},o),s},i.__iteratorUncached=function(i,o){var a=e.__iterator(xn,o),s=0;return new x(function(){for(;;){var o=a.next();if(o.done)return o;var u=o.value,l=u[0],c=u[1];if(t.call(n,c,l,e))return w(i,r?l:s++,c,o)}})},i}function pt(e,t,n){var r=pe().asMutable();return e.__iterate(function(i,o){r.update(t.call(n,i,o,e),0,function(e){return e+1})}),r.asImmutable()}function ft(e,t,n){var r=a(e),i=(l(e)?Ze():pe()).asMutable();e.__iterate(function(o,a){i.update(t.call(n,o,a,e),function(e){return e=e||[],e.push(r?[a,o]:o),e})});var o=At(e);return i.map(function(t){return Et(e,o(t))})}function ht(e,t,n,r){var i=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=i:n|=0),g(t,n,i))return e;var o=y(t,i),a=_(n,i);if(o!==o||a!==a)return ht(e.toSeq().cacheResult(),t,n,r);var s,u=a-o;u===u&&(s=u<0?0:u);var l=Dt(e);return l.size=0===s?s:e.size&&s||void 0,!r&&F(e)&&s>=0&&(l.get=function(t,n){return t=m(this,t),t>=0&&ts)return k();var e=i.next();return r||t===bn?e:t===_n?w(t,u-1,void 0,e):w(t,u-1,e.value[1],e)})},l}function dt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var a=0;return e.__iterate(function(e,i,s){return t.call(n,e,i,s)&&++a&&r(e,i,o)}),a},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var a=e.__iterator(xn,i),s=!0;return new x(function(){if(!s)return k();var e=a.next();if(e.done)return e;var i=e.value,u=i[0],l=i[1];return t.call(n,l,u,o)?r===xn?e:w(r,u,l,e):(s=!1,k())})},r}function mt(e,t,n,r){var i=Dt(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate(function(e,o,l){if(!s||!(s=t.call(n,e,o,l)))return u++,i(e,r?o:u-1,a)}),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(xn,o),u=!0,l=0;return new x(function(){var e,o,c;do{if(e=s.next(),e.done)return r||i===bn?e:i===_n?w(i,l++,void 0,e):w(i,l++,e.value[1],e);var p=e.value;o=p[0],c=p[1],u&&(u=t.call(n,c,o,a))}while(u);return i===xn?e:w(i,o,c,e)})},i}function vt(e,t){var r=a(e),i=[e].concat(t).map(function(e){return o(e)?r&&(e=n(e)):e=r?L(e):q(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===i.length)return e;if(1===i.length){var u=i[0];if(u===e||r&&a(u)||s(e)&&s(u))return u}var l=new I(i);return r?l=l.toKeyedSeq():s(e)||(l=l.toSetSeq()),l=l.flatten(!0),l.size=i.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),l}function gt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){function a(e,l){var c=this;e.__iterate(function(e,i){return(!t||l0}function kt(e,n,r){var i=Dt(e);return i.size=new I(r).map(function(e){return e.size}).min(),i.__iterate=function(e,t){for(var n,r=this.__iterator(bn,t),i=0;!(n=r.next()).done&&!1!==e(n.value,i++,this););return i},i.__iteratorUncached=function(e,i){var o=r.map(function(e){return e=t(e),C(i?e.reverse():e)}),a=0,s=!1;return new x(function(){var t;return s||(t=o.map(function(e){return e.next()}),s=t.some(function(e){return e.done})),s?k():w(e,a++,n.apply(null,t.map(function(e){return e.value})))})},i}function Et(e,t){return F(e)?t:e.constructor(t)}function St(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Ct(e){return ce(e.size),d(e)}function At(e){return a(e)?n:s(e)?r:i}function Dt(e){return Object.create((a(e)?M:s(e)?T:P).prototype)}function Ot(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):O.prototype.cacheResult.call(this)}function Mt(e,t){return e>t?1:et?-1:0}function on(e){if(e.size===1/0)return 0;var t=l(e),n=a(e),r=t?1:0;return an(e.__iterate(n?t?function(e,t){r=31*r+sn(oe(e),oe(t))|0}:function(e,t){r=r+sn(oe(e),oe(t))|0}:t?function(e){r=31*r+oe(e)|0}:function(e){r=r+oe(e)|0}),r)}function an(e,t){return t=Mn(t,3432918353),t=Mn(t<<15|t>>>-15,461845907),t=Mn(t<<13|t>>>-13,5),t=(t+3864292196|0)^e,t=Mn(t^t>>>16,2246822507),t=Mn(t^t>>>13,3266489909),t=ie(t^t>>>16)}function sn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}var un=Array.prototype.slice;e(n,t),e(r,t),e(i,t),t.isIterable=o,t.isKeyed=a,t.isIndexed=s,t.isAssociative=u,t.isOrdered=l,t.Keyed=n,t.Indexed=r,t.Set=i;var ln="@@__IMMUTABLE_ITERABLE__@@",cn="@@__IMMUTABLE_KEYED__@@",pn="@@__IMMUTABLE_INDEXED__@@",fn="@@__IMMUTABLE_ORDERED__@@",hn=5,dn=1<r?k():w(e,i,n[t?r-i++:i++])})},e(R,M),R.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},R.prototype.has=function(e){return this._object.hasOwnProperty(e)},R.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,i=r.length-1,o=0;o<=i;o++){var a=r[t?i-o:o];if(!1===e(n[a],a,this))return o+1}return o},R.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,i=r.length-1,o=0;return new x(function(){var a=r[t?i-o:o];return o++>i?k():w(e,a,n[a])})},R.prototype[fn]=!0,e(j,T),j.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=this._iterable,r=C(n),i=0;if(S(r))for(var o;!(o=r.next()).done&&!1!==e(o.value,i++,this););return i},j.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=this._iterable,r=C(n);if(!S(r))return new x(k);var i=0;return new x(function(){var t=r.next();return t.done?t:w(e,i++,t.value)})},e(N,T),N.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n=this._iterator,r=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[i]=t.value}return w(e,i,r[i++])})};var Cn;e($,T),$.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},$.prototype.get=function(e,t){return this.has(e)?this._value:t},$.prototype.includes=function(e){return Y(this._value,e)},$.prototype.slice=function(e,t){var n=this.size;return g(e,t,n)?this:new $(this._value,_(t,n)-y(e,n))},$.prototype.reverse=function(){return this},$.prototype.indexOf=function(e){return Y(this._value,e)?0:-1},$.prototype.lastIndexOf=function(e){return Y(this._value,e)?this.size:-1},$.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?k():w(e,o++,a)})},Q.prototype.equals=function(e){return e instanceof Q?this._start===e._start&&this._end===e._end&&this._step===e._step:K(this,e)};var Dn;e(ee,t),e(te,ee),e(ne,ee),e(re,ee),ee.Keyed=te,ee.Indexed=ne,ee.Set=re;var On,Mn="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){e|=0,t|=0;var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0},Tn=Object.isExtensible,Pn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(e){return!1}}(),In="function"==typeof WeakMap;In&&(On=new WeakMap);var Rn=0,jn="__immutablehash__";"function"==typeof Symbol&&(jn=Symbol(jn));var Nn=16,Fn=255,Bn=0,Ln={};e(pe,te),pe.of=function(){var e=un.call(arguments,0);return we().withMutations(function(t){for(var n=0;n=e.length)throw new Error("Missing value for key: "+e[n]);t.set(e[n],e[n+1])}})},pe.prototype.toString=function(){return this.__toString("Map {","}")},pe.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},pe.prototype.set=function(e,t){return ke(this,e,t)},pe.prototype.setIn=function(e,t){return this.updateIn(e,vn,function(){return t})},pe.prototype.remove=function(e){return ke(this,e,vn)},pe.prototype.deleteIn=function(e){return this.updateIn(e,function(){return vn})},pe.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},pe.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=Re(this,Tt(e),t,n);return r===vn?void 0:r},pe.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):we()},pe.prototype.merge=function(){return Me(this,void 0,arguments)},pe.prototype.mergeWith=function(e){return Me(this,e,un.call(arguments,1))},pe.prototype.mergeIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.merge?e.merge.apply(e,t):t[t.length-1]})},pe.prototype.mergeDeep=function(){return Me(this,Te,arguments)},pe.prototype.mergeDeepWith=function(e){var t=un.call(arguments,1);return Me(this,Pe(e),t)},pe.prototype.mergeDeepIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,t):t[t.length-1]})},pe.prototype.sort=function(e){return Ze(bt(this,e))},pe.prototype.sortBy=function(e,t){return Ze(bt(this,t,e))},pe.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},pe.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new f)},pe.prototype.asImmutable=function(){return this.__ensureOwner()},pe.prototype.wasAltered=function(){return this.__altered},pe.prototype.__iterator=function(e,t){return new ye(this,e,t)},pe.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},pe.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?xe(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},pe.isMap=fe;var qn="@@__IMMUTABLE_MAP__@@",zn=pe.prototype;zn[qn]=!0,zn.delete=zn.remove,zn.removeIn=zn.deleteIn,he.prototype.get=function(e,t,n,r){for(var i=this.entries,o=0,a=i.length;o=Wn)return Ae(e,u,r,i);var d=e&&e===this.ownerID,m=d?u:h(u);return f?s?l===c-1?m.pop():m[l]=m.pop():m[l]=[r,i]:m.push([r,i]),d?(this.entries=m,this):new he(e,m)}},de.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=1<<((0===e?t:t>>>e)&mn),o=this.bitmap;return 0==(o&i)?r:this.nodes[je(o&i-1)].get(e+hn,t,n,r)},de.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=1<=Vn)return Oe(e,f,l,s,d);if(c&&!d&&2===f.length&&Se(f[1^p]))return f[1^p];if(c&&d&&1===f.length&&Se(d))return d;var m=e&&e===this.ownerID,v=c?d?l:l^u:l|u,g=c?d?Ne(f,p,d,m):Be(f,p,m):Fe(f,p,d,m);return m?(this.bitmap=v,this.nodes=g,this):new de(e,v,g)},me.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=(0===e?t:t>>>e)&mn,o=this.nodes[i];return o?o.get(e+hn,t,n,r):r},me.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=i===vn,l=this.nodes,c=l[s];if(u&&!c)return this;var p=Ee(c,e,t+hn,n,r,i,o,a);if(p===c)return this;var f=this.count;if(c){if(!p&&--f=0&&e>>t&mn;if(r>=this.array.length)return new ze([],e);var i,o=0===r;if(t>0){var a=this.array[r];if((i=a&&a.removeBefore(e,t-hn,n))===a&&o)return this}if(o&&!i)return this;var s=Ge(this,e);if(!o)for(var u=0;u>>t&mn;if(r>=this.array.length)return this;var i;if(t>0){var o=this.array[r];if((i=o&&o.removeAfter(e,t-hn,n))===o&&r===this.array.length-1)return this}var a=Ge(this,e);return a.array.splice(r+1),i&&(a.array[r]=i),a};var Xn,Yn={};e(Ze,pe),Ze.of=function(){return this(arguments)},Ze.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Ze.prototype.get=function(e,t){var n=this._map.get(e);return void 0!==n?this._list.get(n)[1]:t},Ze.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):tt()},Ze.prototype.set=function(e,t){return nt(this,e,t)},Ze.prototype.remove=function(e){return nt(this,e,vn)},Ze.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Ze.prototype.__iterate=function(e,t){var n=this;return this._list.__iterate(function(t){return t&&e(t[1],t[0],n)},t)},Ze.prototype.__iterator=function(e,t){return this._list.fromEntrySeq().__iterator(e,t)},Ze.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map.__ensureOwner(e),n=this._list.__ensureOwner(e);return e?et(t,n,e,this.__hash):(this.__ownerID=e,this._map=t,this._list=n,this)},Ze.isOrderedMap=Qe,Ze.prototype[fn]=!0,Ze.prototype.delete=Ze.prototype.remove;var Kn;e(rt,M),rt.prototype.get=function(e,t){return this._iter.get(e,t)},rt.prototype.has=function(e){return this._iter.has(e)},rt.prototype.valueSeq=function(){return this._iter.valueSeq()},rt.prototype.reverse=function(){var e=this,t=lt(this,!0);return this._useKeys||(t.valueSeq=function(){return e._iter.toSeq().reverse()}),t},rt.prototype.map=function(e,t){var n=this,r=ut(this,e,t);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(e,t)}),r},rt.prototype.__iterate=function(e,t){var n,r=this;return this._iter.__iterate(this._useKeys?function(t,n){return e(t,n,r)}:(n=t?Ct(this):0,function(i){return e(i,t?--n:n++,r)}),t)},rt.prototype.__iterator=function(e,t){if(this._useKeys)return this._iter.__iterator(e,t);var n=this._iter.__iterator(bn,t),r=t?Ct(this):0;return new x(function(){var i=n.next();return i.done?i:w(e,t?--r:r++,i.value,i)})},rt.prototype[fn]=!0,e(it,T),it.prototype.includes=function(e){return this._iter.includes(e)},it.prototype.__iterate=function(e,t){var n=this,r=0;return this._iter.__iterate(function(t){return e(t,r++,n)},t)},it.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t),r=0;return new x(function(){var t=n.next();return t.done?t:w(e,r++,t.value,t)})},e(ot,P),ot.prototype.has=function(e){return this._iter.includes(e)},ot.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){return e(t,t,n)},t)},ot.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){var t=n.next();return t.done?t:w(e,t.value,t.value,t)})},e(at,M),at.prototype.entrySeq=function(){return this._iter.toSeq()},at.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){if(t){St(t);var r=o(t);return e(r?t.get(1):t[1],r?t.get(0):t[0],n)}},t)},at.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){for(;;){var t=n.next();if(t.done)return t;var r=t.value;if(r){St(r);var i=o(r);return w(e,i?r.get(0):r[0],i?r.get(1):r[1],t)}}})},it.prototype.cacheResult=rt.prototype.cacheResult=ot.prototype.cacheResult=at.prototype.cacheResult=Ot,e(Pt,te),Pt.prototype.toString=function(){return this.__toString(Rt(this)+" {","}")},Pt.prototype.has=function(e){return this._defaultValues.hasOwnProperty(e)},Pt.prototype.get=function(e,t){if(!this.has(e))return t;var n=this._defaultValues[e];return this._map?this._map.get(e,n):n},Pt.prototype.clear=function(){if(this.__ownerID)return this._map&&this._map.clear(),this;var e=this.constructor;return e._empty||(e._empty=It(this,we()))},Pt.prototype.set=function(e,t){if(!this.has(e))throw new Error('Cannot set unknown key "'+e+'" on '+Rt(this));if(this._map&&!this._map.has(e)){if(t===this._defaultValues[e])return this}var n=this._map&&this._map.set(e,t);return this.__ownerID||n===this._map?this:It(this,n)},Pt.prototype.remove=function(e){if(!this.has(e))return this;var t=this._map&&this._map.remove(e);return this.__ownerID||t===this._map?this:It(this,t)},Pt.prototype.wasAltered=function(){return this._map.wasAltered()},Pt.prototype.__iterator=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterator(e,t)},Pt.prototype.__iterate=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterate(e,t)},Pt.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map&&this._map.__ensureOwner(e);return e?It(this,t,e):(this.__ownerID=e,this._map=t,this)};var $n=Pt.prototype;$n.delete=$n.remove,$n.deleteIn=$n.removeIn=zn.removeIn,$n.merge=zn.merge,$n.mergeWith=zn.mergeWith,$n.mergeIn=zn.mergeIn,$n.mergeDeep=zn.mergeDeep,$n.mergeDeepWith=zn.mergeDeepWith,$n.mergeDeepIn=zn.mergeDeepIn,$n.setIn=zn.setIn,$n.update=zn.update,$n.updateIn=zn.updateIn,$n.withMutations=zn.withMutations,$n.asMutable=zn.asMutable,$n.asImmutable=zn.asImmutable,e(Ft,re),Ft.of=function(){return this(arguments)},Ft.fromKeys=function(e){return this(n(e).keySeq())},Ft.prototype.toString=function(){return this.__toString("Set {","}")},Ft.prototype.has=function(e){return this._map.has(e)},Ft.prototype.add=function(e){return Lt(this,this._map.set(e,!0))},Ft.prototype.remove=function(e){return Lt(this,this._map.remove(e))},Ft.prototype.clear=function(){return Lt(this,this._map.clear())},Ft.prototype.union=function(){var e=un.call(arguments,0);return e=e.filter(function(e){return 0!==e.size}),0===e.length?this:0!==this.size||this.__ownerID||1!==e.length?this.withMutations(function(t){for(var n=0;n=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Xt(e,t)},Jt.prototype.pushAll=function(e){if(e=r(e),0===e.size)return this;ce(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Xt(t,n)},Jt.prototype.pop=function(){return this.slice(1)},Jt.prototype.unshift=function(){return this.push.apply(this,arguments)},Jt.prototype.unshiftAll=function(e){return this.pushAll(e)},Jt.prototype.shift=function(){return this.pop.apply(this,arguments)},Jt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Yt()},Jt.prototype.slice=function(e,t){if(g(e,t,this.size))return this;var n=y(e,this.size);if(_(t,this.size)!==this.size)return ne.prototype.slice.call(this,e,t);for(var r=this.size-n,i=this._head;n--;)i=i.next;return this.__ownerID?(this.size=r,this._head=i,this.__hash=void 0,this.__altered=!0,this):Xt(r,i)},Jt.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Xt(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Jt.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Jt.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new x(function(){if(r){var t=r.value;return r=r.next,w(e,n++,t)}return k()})},Jt.isStack=Gt;var rr="@@__IMMUTABLE_STACK__@@",ir=Jt.prototype;ir[rr]=!0,ir.withMutations=zn.withMutations,ir.asMutable=zn.asMutable,ir.asImmutable=zn.asImmutable,ir.wasAltered=zn.wasAltered;var or;t.Iterator=x,Kt(t,{toArray:function(){ce(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new it(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new rt(this,!0)},toMap:function(){return pe(this.toKeyedSeq())},toObject:function(){ce(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Ze(this.toKeyedSeq())},toOrderedSet:function(){return Ut(a(this)?this.valueSeq():this)},toSet:function(){return Ft(a(this)?this.valueSeq():this)},toSetSeq:function(){return new ot(this)},toSeq:function(){return s(this)?this.toIndexedSeq():a(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Jt(a(this)?this.valueSeq():this)},toList:function(){return Le(a(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return Et(this,vt(this,un.call(arguments,0)))},includes:function(e){return this.some(function(t){return Y(t,e)})},entries:function(){return this.__iterator(xn)},every:function(e,t){ce(this.size);var n=!0;return this.__iterate(function(r,i,o){if(!e.call(t,r,i,o))return n=!1,!1}),n},filter:function(e,t){return Et(this,ct(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return ce(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){ce(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!==r&&void 0!==r?r.toString():""}),t},keys:function(){return this.__iterator(_n)},map:function(e,t){return Et(this,ut(this,e,t))},reduce:function(e,t,n){ce(this.size);var r,i;return arguments.length<2?i=!0:r=t,this.__iterate(function(t,o,a){i?(i=!1,r=t):r=e.call(n,r,t,o,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Et(this,lt(this,!0))},slice:function(e,t){return Et(this,ht(this,e,t,!0))},some:function(e,t){return!this.every(Qt(e),t)},sort:function(e){return Et(this,bt(this,e))},values:function(){return this.__iterator(bn)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return d(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return pt(this,e,t)},equals:function(e){return K(this,e)},entrySeq:function(){var e=this;if(e._cache)return new I(e._cache);var t=e.toSeq().map(Zt).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Qt(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,i,o){if(e.call(t,n,i,o))return r=[i,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(v)},flatMap:function(e,t){return Et(this,yt(this,e,t))},flatten:function(e){return Et(this,gt(this,e,!0))},fromEntrySeq:function(){return new at(this)},get:function(e,t){return this.find(function(t,n){return Y(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,i=Tt(e);!(n=i.next()).done;){var o=n.value;if((r=r&&r.get?r.get(o,vn):vn)===vn)return t}return r},groupBy:function(e,t){return ft(this,e,t)},has:function(e){return this.get(e,vn)!==vn},hasIn:function(e){return this.getIn(e,vn)!==vn},isSubset:function(e){return e="function"==typeof e.includes?e:t(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return e="function"==typeof e.isSubset?e:t(e),e.isSubset(this)},keyOf:function(e){return this.findKey(function(t){return Y(t,e)})},keySeq:function(){return this.toSeq().map($t).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return xt(this,e)},maxBy:function(e,t){return xt(this,t,e)},min:function(e){return xt(this,e?en(e):rn)},minBy:function(e,t){return xt(this,t?en(t):rn,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Et(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Et(this,mt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Qt(e),t)},sortBy:function(e,t){return Et(this,bt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Et(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Et(this,dt(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Qt(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=on(this))}});var ar=t.prototype;ar[ln]=!0,ar[En]=ar.values,ar.__toJS=ar.toArray,ar.__toStringMapper=tn,ar.inspect=ar.toSource=function(){return this.toString()},ar.chain=ar.flatMap,ar.contains=ar.includes,Kt(n,{flip:function(){return Et(this,st(this))},mapEntries:function(e,t){var n=this,r=0;return Et(this,this.toSeq().map(function(i,o){return e.call(t,[o,i],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Et(this,this.toSeq().flip().map(function(r,i){return e.call(t,r,i,n)}).flip())}});var sr=n.prototype;return sr[cn]=!0,sr[En]=ar.entries,sr.__toJS=ar.toObject,sr.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+tn(e)},Kt(r,{toKeyedSeq:function(){return new rt(this,!1)},filter:function(e,t){return Et(this,ct(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Et(this,lt(this,!1))},slice:function(e,t){return Et(this,ht(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=y(e,e<0?this.count():this.size);var r=this.slice(0,e);return Et(this,1===n?r:r.concat(h(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Et(this,gt(this,e,!1))},get:function(e,t){return e=m(this,e),e<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=m(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,i,o,a,s=e.textContent,u=0,l=s[0],c=1,p=e.innerHTML="",f=0;r=n,n=f<7&&"\\"==n?1:c;){if(c=l,l=s[++u],o=p.length>1,!c||f>8&&"\n"==c||[/\S/.test(c),1,1,!/[$\w]/.test(c),("/"==n||"\n"==n)&&o,'"'==n&&o,"'"==n&&o,s[u-4]+r+n=="--\x3e",r+n=="*/"][f])for(p&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][f?f<3?2:f>6?4:f>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(p):0]),a.appendChild(t.createTextNode(p))),i=f&&f<7?f:i,p="",f=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(c),/[\])]/.test(c),/[$\w]/.test(c),"/"==c&&i<2&&"<"!=n,'"'==c,"'"==c,c+l+s[u+1]+s[u+2]=="\x3c!--",c+l=="/*",c+l=="//","#"==c][--f];);p+=c}}(e)}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"key",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:L.default.Map();if(!L.default.Map.isMap(e)||!e.size)return L.default.List();if(Array.isArray(t)||(t=[t]),t.length<1)return e.merge(n);var r=L.default.List(),i=t[0],o=!0,a=!1,s=void 0;try{for(var u,l=(0,T.default)(e.entries());!(o=(u=l.next()).done);o=!0){var c=u.value,p=(0,O.default)(c,2),f=p[0],h=p[1],d=b(h,t.slice(1),n.set(i,f));r=L.default.List.isList(d)?r.concat(d):r.push(d)}}catch(e){a=!0,s=e}finally{try{!o&&l.return&&l.return()}finally{if(a)throw s}}return r}function x(e){var t=/filename="([^;]*);?"/i.exec(e);return null===t&&(t=/filename=([^;]*);?/i.exec(e)),null!==t&&t.length>1?t[1]:null}function w(e){return(0,V.default)((0,U.default)(e))}function k(e){return w(e.replace(/\.[^.\/]*$/,""))}function E(e){return"string"!=typeof e||""===e?"":(0,q.sanitizeUrl)(e)}function S(e){if(!L.default.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&(0,j.default)(e.get("content")||{}).length>0}),n=e.get("default")||L.default.OrderedMap(),r=(n.get("content")||L.default.OrderedMap()).keySeq().toJS(),i=r.length?n:null;return t||i}Object.defineProperty(t,"__esModule",{value:!0}),t.getExtensions=t.escapeDeepLinkPath=t.createDeepLinkPath=t.shallowEqualKeys=t.buildFormData=t.sorters=t.btoa=t.serializeSearch=t.parseSearch=t.getSampleSchema=t.validateParam=t.validatePattern=t.validateMinLength=t.validateMaxLength=t.validateGuid=t.validateDateTime=t.validateString=t.validateBoolean=t.validateFile=t.validateInteger=t.validateNumber=t.validateMinimum=t.validateMaximum=t.propChecker=t.memoize=t.isImmutable=void 0;var C=n(37),A=r(C),D=n(18),O=r(D),M=n(96),T=r(M),P=n(27),I=r(P),R=n(47),j=r(R),N=n(48),F=r(N);t.isJSONObject=i,t.objectify=o,t.arrayify=a,t.fromJSOrdered=s,t.bindToState=u,t.normalizeArray=l,t.isFn=c,t.isObject=p,t.isFunc=f,t.isArray=h,t.objMap=d,t.objReduce=m,t.systemThunkMiddleware=v,t.defaultStatusCode=g,t.getList=y,t.highlight=_,t.mapToList=b,t.extractFileNameFromContentDispositionHeader=x,t.pascalCase=w,t.pascalCaseFilename=k,t.sanitizeUrl=E,t.getAcceptControllingResponse=S;var B=n(7),L=r(B),q=n(520),z=n(952),U=r(z),W=n(440),V=r(W),H=n(436),J=r(H),G=n(226),X=r(G),Y=n(970),K=r(Y),$=n(119),Z=r($),Q=n(173),ee=n(36),te=r(ee),ne=n(710),re=r(ne),ie="default",oe=t.isImmutable=function(e){return L.default.Iterable.isIterable(e)},ae=(t.memoize=J.default,t.propChecker=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return(0,j.default)(e).length!==(0,j.default)(t).length||((0,K.default)(e,function(e,n){if(r.includes(n))return!1;var i=t[n];return L.default.Iterable.isIterable(e)?!L.default.is(e,i):("object"!==(void 0===e?"undefined":(0,F.default)(e))||"object"!==(void 0===i?"undefined":(0,F.default)(i)))&&e!==i})||n.some(function(n){return!(0,Z.default)(e[n],t[n])}))},t.validateMaximum=function(e,t){if(e>t)return"Value must be less than Maximum"}),se=t.validateMinimum=function(e,t){if(et)return"Value must be less than MaxLength"},ve=t.validateMinLength=function(e,t){if(e.length2&&void 0!==arguments[2]&&arguments[2],r=[],i=t&&"body"===e.get("in")?e.get("value_xml"):e.get("value"),o=e.get("required"),a=n?e.get("schema"):e;if(!a)return r;var s=a.get("maximum"),u=a.get("minimum"),l=a.get("type"),c=a.get("format"),p=a.get("maxLength"),f=a.get("minLength"),h=a.get("pattern");if(l&&(o||i)){var d="string"===l&&i,m="array"===l&&Array.isArray(i)&&i.length,v="array"===l&&L.default.List.isList(i)&&i.count(),g="file"===l&&i instanceof te.default.File,y="boolean"===l&&(i||!1===i),_="number"===l&&(i||0===i),b="integer"===l&&(i||0===i);if(o&&!(d||m||v||g||y||_||b))return r.push("Required field is not provided"),r;if(h){var x=ge(i,h);x&&r.push(x)}if(p||0===p){var w=me(i,p);w&&r.push(w)}if(f){var k=ve(i,f);k&&r.push(k)}if(s||0===s){var E=ae(i,s);E&&r.push(E)}if(u||0===u){var S=se(i,u);S&&r.push(S)}if("string"===l){var C=void 0;if(!(C="date-time"===c?he(i):"uuid"===c?de(i):fe(i)))return r;r.push(C)}else if("boolean"===l){var A=pe(i);if(!A)return r;r.push(A)}else if("number"===l){var D=ue(i);if(!D)return r;r.push(D)}else if("integer"===l){var O=le(i);if(!O)return r;r.push(O)}else if("array"===l){var M=void 0;if(!v||!i.count())return r;M=a.getIn(["items","type"]),i.forEach(function(e,t){var n=void 0;"number"===M?n=ue(e):"integer"===M?n=le(e):"string"===M&&(n=fe(e)),n&&r.push({index:t,error:n})})}else if("file"===l){var T=ce(i);if(!T)return r;r.push(T)}}return r},t.getSampleSchema=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return(0,Q.memoizedCreateXMLExample)(e,n)}return(0,A.default)((0,Q.memoizedSampleFromSchema)(e,n),null,2)},t.parseSearch=function(){var e={},t=te.default.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)n.hasOwnProperty(r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},t.serializeSearch=function(e){return(0,j.default)(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&")},t.btoa=function(t){var n=void 0;return n=t instanceof e?t:new e(t.toString(),"utf-8"),n.toString("base64")},t.sorters={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},t.buildFormData=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},t.shallowEqualKeys=function(e,t,n){return!!(0,X.default)(n,function(n){return(0,Z.default)(e[n],t[n])})},t.createDeepLinkPath=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"_"):""});t.escapeDeepLinkPath=function(e){return(0,re.default)(ye(e))},t.getExtensions=function(e){return e.filter(function(e,t){return/^x-/.test(t)})}}).call(t,n(42).Buffer)},function(e,t,n){"use strict";var r=n(33),i=r;e.exports=i},function(e,t,n){"use strict";function r(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r6?s-6:0),l=6;l5?l-5:0),p=5;p5?a-5:0),u=5;u key("+c[p]+")"].concat(s));if(h instanceof Error)return h}}return i(t)}function u(e){return a(e,"List",b.List.isList)}function l(e,t,n,r){function o(){for(var i=arguments.length,o=Array(i),u=0;u5?s-5:0),l=5;l5?l-5:0),p=5;p>",w={listOf:u,mapOf:c,orderedMapOf:p,setOf:f,orderedSetOf:h,stackOf:d,iterableOf:m,recordOf:v,shape:y,contains:y,mapContains:_,list:o("List",b.List.isList),map:o("Map",b.Map.isMap),orderedMap:o("OrderedMap",b.OrderedMap.isOrderedMap),set:o("Set",b.Set.isSet),orderedSet:o("OrderedSet",b.OrderedSet.isOrderedSet),stack:o("Stack",b.Stack.isStack),seq:o("Seq",b.Seq.isSeq),record:o("Record",function(e){return e instanceof b.Record}),iterable:o("Iterable",b.Iterable.isIterable)};e.exports=w},function(e,t,n){"use strict";function r(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}/* object-assign (c) Sindre Sorhus @license MIT */ var i=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=r(e),l=1;l=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function l(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function c(e,t){var n=0;return o(y,t)?y[t]:35===t.charCodeAt(0)&&g.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?l(n):e}function p(e){return e.indexOf("&")<0?e:e.replace(v,c)}function f(e){return x[e]}function h(e){return _.test(e)?e.replace(b,f):e}var d=Object.prototype.hasOwnProperty,m=/\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g,v=/&([a-z#][a-z0-9]{1,31});/gi,g=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,y=n(501),_=/[&<>"]/,b=/[&<>"]/g,x={"&":"&","<":"<",">":">",'"':"""};t.assign=a,t.isString=i,t.has=o,t.unescapeMd=s,t.isValidEntityCode=u,t.fromCodePoint=l,t.replaceEntities=p,t.escapeHtml=h},function(e,t,n){e.exports={default:n(602),__esModule:!0}},function(e,t,n){"use strict";t.__esModule=!0;var r=n(337),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(e,t,n){return t in e?(0,i.default)(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(32),i=n(63),o=n(64),a=n(78),s=n(136),u=function(e,t,n){var l,c,p,f,h=e&u.F,d=e&u.G,m=e&u.S,v=e&u.P,g=e&u.B,y=d?r:m?r[t]||(r[t]={}):(r[t]||{}).prototype,_=d?i:i[t]||(i[t]={}),b=_.prototype||(_.prototype={});d&&(n=t);for(l in n)c=!h&&y&&void 0!==y[l],p=(c?y:n)[l],f=g&&c?s(p,r):v&&"function"==typeof p?s(Function.call,p):p,y&&a(y,l,p,e&u.U),_[l]!=p&&o(_,l,f),v&&b[l]!=p&&(b[l]=p)};r.core=i,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t,n){var r=n(30),i=n(107),o=n(58),a=/"/g,s=function(e,t,n,r){var i=String(o(e)),s="<"+t;return""!==n&&(s+=" "+n+'="'+String(r).replace(a,""")+'"'),s+">"+i+""};e.exports=function(e,t){var n={};n[e]=t(s),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";function r(e){return function(){return e}}var i=function(){};i.thatReturns=r,i.thatReturnsFalse=r(!1),i.thatReturnsTrue=r(!0),i.thatReturnsNull=r(null),i.thatReturnsThis=function(){return this},i.thatReturnsArgument=function(e){return e},e.exports=i},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function o(e){if(p===clearTimeout)return clearTimeout(e);if((p===r||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){m&&h&&(m=!1,h.length?d=h.concat(d):v=-1,d.length&&s())}function s(){if(!m){var e=i(a);m=!0;for(var t=d.length;t;){for(h=d,d=[];++v1)for(var n=1;n=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function m(e){return+e!=e&&(e=0),o.alloc(+e)}function v(e,t){if(o.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return V(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return G(e).length;default:if(r)return V(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return D(this,t,n);case"ascii":return M(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return A(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function _(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=o.from(t,r)),o.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,i);if("number"==typeof t)return t&=255,o.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}var l;if(i){var c=-1;for(l=n;ls&&(n=s-u),l=n;l>=0;l--){for(var p=!0,f=0;fi&&(r=i):r=i;var o=t.length;if(o%2!=0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+s<=n){var u,l,c,p;switch(s){case 1:o<128&&(a=o);break;case 2:u=e[i+1],128==(192&u)&&(p=(31&o)<<6|63&u)>127&&(a=p);break;case 3:u=e[i+1],l=e[i+2],128==(192&u)&&128==(192&l)&&(p=(15&o)<<12|(63&u)<<6|63&l)>2047&&(p<55296||p>57343)&&(a=p);break;case 4:u=e[i+1],l=e[i+2],c=e[i+3],128==(192&u)&&128==(192&l)&&128==(192&c)&&(p=(15&o)<<18|(63&u)<<12|(63&l)<<6|63&c)>65535&&p<1114112&&(a=p)}}null===a?(a=65533,s=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=s}return O(r)}function O(e){var t=e.length;if(t<=Q)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function j(e,t,n,r,i,a){if(!o.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function N(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function F(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function B(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,i){return i||B(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),$.write(e,t,n,r,23,4),n+4}function q(e,t,n,r,i){return i||B(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),$.write(e,t,n,r,52,8),n+8}function z(e){if(e=U(e).replace(ee,""),e.length<2)return"";for(;e.length%4!=0;)e+="=";return e}function U(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function W(e){return e<16?"0"+e.toString(16):e.toString(16)}function V(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function H(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function G(e){return K.toByteArray(z(e))}function X(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function Y(e){return e!==e}/*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ var K=n(583),$=n(779),Z=n(396);t.Buffer=o,t.SlowBuffer=m,t.INSPECT_MAX_BYTES=50,o.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()&&"function"==typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(e){return!1}}(),t.kMaxLength=r(),o.poolSize=8192,o._augment=function(e){return e.__proto__=o.prototype,e},o.from=function(e,t,n){return a(null,e,t,n)},o.TYPED_ARRAY_SUPPORT&&(o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0})),o.alloc=function(e,t,n){return u(null,e,t,n)},o.allocUnsafe=function(e){return l(null,e)},o.allocUnsafeSlow=function(e){return l(null,e)},o.isBuffer=function(e){return!(null==e||!e._isBuffer)},o.compare=function(e,t){if(!o.isBuffer(e)||!o.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},o.prototype.compare=function(e,t,n,r,i){if(!o.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,s=n-t,u=Math.min(a,s),l=this.slice(r,i),c=e.slice(t,n),p=0;pi)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return x(this,e,t,n);case"utf8":case"utf-8":return w(this,e,t,n);case"ascii":return k(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Q=4096;o.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},o.prototype.readUInt8=function(e,t){return t||R(e,1,this.length),this[e]},o.prototype.readUInt16LE=function(e,t){return t||R(e,2,this.length),this[e]|this[e+1]<<8},o.prototype.readUInt16BE=function(e,t){return t||R(e,2,this.length),this[e]<<8|this[e+1]},o.prototype.readUInt32LE=function(e,t){return t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},o.prototype.readUInt32BE=function(e,t){return t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},o.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},o.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},o.prototype.readInt8=function(e,t){return t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},o.prototype.readInt16LE=function(e,t){t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(e,t){t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(e,t){return t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},o.prototype.readInt32BE=function(e,t){return t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},o.prototype.readFloatLE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!0,23,4)},o.prototype.readFloatBE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!1,23,4)},o.prototype.readDoubleLE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!0,52,8)},o.prototype.readDoubleBE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!1,52,8)},o.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){j(this,e,t,n,Math.pow(2,8*n)-1,0)}var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},o.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,1,255,0),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},o.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},o.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},o.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):F(this,e,t,!0),t+4},o.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):F(this,e,t,!1),t+4},o.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);j(this,e,t,n,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+n},o.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);j(this,e,t,n,i-1,-i)}var o=n-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+n},o.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,1,127,-128),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},o.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},o.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},o.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,2147483647,-2147483648),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):F(this,e,t,!0),t+4},o.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):F(this,e,t,!1),t+4},o.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},o.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},o.prototype.writeDoubleLE=function(e,t,n){return q(this,e,t,!0,n)},o.prototype.writeDoubleBE=function(e,t,n){return q(this,e,t,!1,n)},o.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(a<1e3||!o.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var a;if("number"==typeof e)for(a=t;a0&&(a=this.buffer[u-1],e.call(r,a)<0);)if(u--,this.pointer-u>n/2-1){o=" ... ",u+=5;break}for(l="",i=this.pointer;in/2-1){l=" ... ",i-=5;break}return""+new Array(t).join(" ")+o+this.buffer.slice(u,i)+l+"\n"+new Array(t+this.pointer-u+o.length).join(" ")+"^"},t.prototype.toString=function(){var e,t;return e=this.get_snippet(),t=" on line "+(this.line+1)+", column "+(this.column+1),e?t:t+":\n"+e},t}(),this.YAMLError=function(e){function n(e){this.message=e,n.__super__.constructor.call(this),this.stack=this.toString()+"\n"+(new Error).stack.split("\n").slice(1).join("\n")}return t(n,e),n.prototype.toString=function(){return this.message},n}(Error),this.MarkedYAMLError=function(e){function n(e,t,r,i,o){this.context=e,this.context_mark=t,this.problem=r,this.problem_mark=i,this.note=o,n.__super__.constructor.call(this)}return t(n,e),n.prototype.toString=function(){var e;return e=[],null!=this.context&&e.push(this.context),null==this.context_mark||null!=this.problem&&null!=this.problem_mark&&this.context_mark.line===this.problem_mark.line&&this.context_mark.column===this.problem_mark.column||e.push(this.context_mark.toString()),null!=this.problem&&e.push(this.problem),null!=this.problem_mark&&e.push(this.problem_mark.toString()),null!=this.note&&e.push(this.note),e.join("\n")},n}(this.YAMLError)}).call(this)},function(e,t,n){e.exports={default:n(606),__esModule:!0}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(581),o=r(i),a=n(580),s=r(a),u="function"==typeof s.default&&"symbol"==typeof o.default?function(e){return typeof e}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":typeof e};t.default="function"==typeof s.default&&"symbol"===u(o.default)?function(e){return void 0===e?"undefined":u(e)}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":void 0===e?"undefined":u(e)}},function(e,t,n){e.exports=!n(55)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";function r(e,t,n){return n?[e,t]:e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,e.exports=t.default},function(e,t){function n(e){return null!=e&&"object"==typeof e}e.exports=n},function(e,t,n){"use strict";function r(e,t,n,r){this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n;var i=this.constructor.Interface;for(var o in i)if(i.hasOwnProperty(o)){var s=i[o];s?this[o]=s(n):"target"===o?this.target=r:this[o]=n[o]}var u=null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue;return this.isDefaultPrevented=u?a.thatReturnsTrue:a.thatReturnsFalse,this.isPropagationStopped=a.thatReturnsFalse,this}var i=n(13),o=n(70),a=n(33),s=(n(10),["dispatchConfig","_targetInst","nativeEvent","isDefaultPrevented","isPropagationStopped","_dispatchListeners","_dispatchInstances"]),u={type:null,target:null,currentTarget:a.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null};i(r.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=a.thatReturnsTrue)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=a.thatReturnsTrue)},persist:function(){this.isPersistent=a.thatReturnsTrue},isPersistent:a.thatReturnsFalse,destructor:function(){var e=this.constructor.Interface;for(var t in e)this[t]=null;for(var n=0;n1?t-1:0),i=1;i2?n-2:0),o=2;o=n?e:e.length+1===n?""+t+e:""+new Array(n-e.length+1).join(t)+e},this.to_hex=function(e){return"string"==typeof e&&(e=e.charCodeAt(0)),e.toString(16)}}).call(this)}).call(t,n(16))},function(e,t,n){var r=n(77);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){var n=e.exports={version:"2.5.3"};"number"==typeof __e&&(__e=n)},function(e,t,n){var r=n(138),i=n(367);e.exports=n(106)?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";var r=n(740),i=Math.max;e.exports=function(e){return i(0,r(e))}},function(e,t,n){function r(e){return null==e?void 0===e?u:s:l&&l in Object(e)?o(e):a(e)}var i=n(82),o=n(907),a=n(936),s="[object Null]",u="[object Undefined]",l=i?i.toStringTag:void 0;e.exports=r},function(e,t,n){function r(e,t){var n=o(e,t);return i(n)?n:void 0}var i=n(868),o=n(908);e.exports=r},function(e,t,n){function r(e){return a(e)?i(e):o(e)}var i=n(403),o=n(871),a=n(86);e.exports=r},function(e,t,n){"use strict"},function(e,t,n){"use strict";var r=n(11),i=(n(8),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),o=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var i=r.instancePool.pop();return r.call(i,e,t,n),i}return new r(e,t,n)},s=function(e,t,n,r){var i=this;if(i.instancePool.length){var o=i.instancePool.pop();return i.call(o,e,t,n,r),o}return new i(e,t,n,r)},u=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t){e.exports={}},function(e,t,n){var r=n(183),i=n(180);e.exports=function(e){return r(i(e))}},function(e,t,n){var r=n(180);e.exports=function(e){return Object(r(e))}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(32),i=n(64),o=n(108),a=n(204)("src"),s=Function.toString,u=(""+s).split("toString");n(63).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var l="function"==typeof n;l&&(o(n,"name")||i(n,"name",t)),e[t]!==n&&(l&&(o(n,a)||i(n,a,e[t]?""+e[t]:u.join(String(t)))),e===r?e[t]=n:s?e[t]?e[t]=n:i(e,t,n):(delete e[t],i(e,t,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(e,t,n){"use strict";var r=n(380)();e.exports=function(e){return e!==r&&null!==e}},function(e,t,n){"use strict";function r(e){return void 0===e||null===e}function i(e){return"object"==typeof e&&null!==e}function o(e){return Array.isArray(e)?e:r(e)?[]:[e]}function a(e,t){var n,r,i,o;if(t)for(o=Object.keys(t),n=0,r=o.length;n`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t,n){"use strict";var r=n(13),i=n(487),o=n(1115),a=n(1116),s=n(93),u=n(1117),l=n(1118),c=n(1119),p=n(1123),f=s.createElement,h=s.createFactory,d=s.cloneElement,m=r,v=function(e){return e},g={Children:{map:o.map,forEach:o.forEach,count:o.count,toArray:o.toArray,only:p},Component:i.Component,PureComponent:i.PureComponent,createElement:f,cloneElement:d,isValidElement:s.isValidElement,PropTypes:u,createClass:c,createFactory:h,createMixin:v,DOM:a,version:l,__spread:m};e.exports=g},function(e,t,n){"use strict";function r(e){return void 0!==e.ref}function i(e){return void 0!==e.key}var o=n(13),a=n(53),s=(n(10),n(491),Object.prototype.hasOwnProperty),u=n(489),l={key:!0,ref:!0,__self:!0,__source:!0},c=function(e,t,n,r,i,o,a){var s={$$typeof:u,type:e,key:t,ref:n,props:a,_owner:o};return s};c.createElement=function(e,t,n){var o,u={},p=null,f=null;if(null!=t){r(t)&&(f=t.ref),i(t)&&(p=""+t.key),void 0===t.__self?null:t.__self,void 0===t.__source?null:t.__source;for(o in t)s.call(t,o)&&!l.hasOwnProperty(o)&&(u[o]=t[o])}var h=arguments.length-2;if(1===h)u.children=n;else if(h>1){for(var d=Array(h),m=0;m1){for(var g=Array(v),y=0;y=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){var r=n(352),i=n(182);e.exports=Object.keys||function(e){return r(e,i)}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(43).f,i=n(56),o=n(21)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,o)&&r(e,o,{configurable:!0,value:t})}},function(e,t,n){"use strict";var r=n(630)(!0);n(346)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){n(635);for(var r=n(24),i=n(57),o=n(74),a=n(21)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),u=0;u0?i(r(e),9007199254740991):0}},function(e,t,n){(function(e){function n(e){return Array.isArray?Array.isArray(e):"[object Array]"===v(e)}function r(e){return"boolean"==typeof e}function i(e){return null===e}function o(e){return null==e}function a(e){return"number"==typeof e}function s(e){return"string"==typeof e}function u(e){return"symbol"==typeof e}function l(e){return void 0===e}function c(e){return"[object RegExp]"===v(e)}function p(e){return"object"==typeof e&&null!==e}function f(e){return"[object Date]"===v(e)}function h(e){return"[object Error]"===v(e)||e instanceof Error}function d(e){return"function"==typeof e}function m(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e}function v(e){return Object.prototype.toString.call(e)}t.isArray=n,t.isBoolean=r,t.isNull=i,t.isNullOrUndefined=o,t.isNumber=a,t.isString=s,t.isSymbol=u,t.isUndefined=l,t.isRegExp=c,t.isObject=p,t.isDate=f,t.isError=h,t.isFunction=d,t.isPrimitive=m,t.isBuffer=e.isBuffer}).call(t,n(42).Buffer)},function(e,t,n){"use strict";function r(e){return"string"==typeof e&&i.test(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=/-webkit-|-moz-|-ms-/;e.exports=t.default},function(e,t){e.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",Doctype:"doctype",isTag:function(e){return"tag"===e.type||"script"===e.type||"style"===e.type}}},function(e,t,n){var r=n(726),i=n(725);t.decode=function(e,t){return(!t||t<=0?i.XML:i.HTML)(e)},t.decodeStrict=function(e,t){return(!t||t<=0?i.XML:i.HTMLStrict)(e)},t.encode=function(e,t){return(!t||t<=0?r.XML:r.HTML)(e)},t.encodeXML=r.XML,t.encodeHTML4=t.encodeHTML5=t.encodeHTML=r.HTML,t.decodeXML=t.decodeXMLStrict=i.XML,t.decodeHTML4=t.decodeHTML5=t.decodeHTML=i.HTML,t.decodeHTML4Strict=t.decodeHTML5Strict=t.decodeHTMLStrict=i.HTMLStrict,t.escape=r.escape},function(e,t,n){"use strict";var r=n(79);e.exports=function(e){if(!r(e))throw new TypeError("Cannot use null or undefined");return e}},function(e,t,n){function r(t,n){return delete e.exports[t],e.exports[t]=n,n}var i=n(389),o=n(715);e.exports={Parser:i,Tokenizer:n(390),ElementType:n(113),DomHandler:o,get FeedHandler(){return r("FeedHandler",n(775))},get Stream(){return r("Stream",n(777))},get WritableStream(){return r("WritableStream",n(391))},get ProxyHandler(){return r("ProxyHandler",n(776))},get DomUtils(){return r("DomUtils",n(717))},get CollectingHandler(){return r("CollectingHandler",n(774))},DefaultHandler:o,get RssHandler(){return r("RssHandler",this.FeedHandler)},parseDOM:function(e,t){var n=new o(t);return new i(n,t).end(e),n.dom},parseFeed:function(t,n){var r=new e.exports.FeedHandler(n);return new i(r,n).end(t),r.dom},createDomStream:function(e,t,n){var r=new o(e,t,n);return new i(r,t)},EVENTS:{attribute:2,cdatastart:0,cdataend:0,text:1,processinginstruction:2,comment:1,commentend:0,closetag:1,opentag:2,opentagname:1,error:1,end:0}}},function(e,t,n){"use strict";function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t},e.exports=r},function(e,t,n){"use strict";var r=n(81);e.exports=new r({include:[n(397)],implicit:[n(829),n(822)],explicit:[n(814),n(824),n(825),n(827)]})},function(e,t){function n(e,t){return e===t||e!==e&&t!==t}e.exports=n},function(e,t){function n(e,t,n){if(t in e)return e[t];if(3===arguments.length)return n;throw new Error('"'+t+'" is a required argument.')}function r(e){var t=e.match(y);return t?{scheme:t[1],auth:t[2],host:t[3],port:t[4],path:t[5]}:null}function i(e){var t="";return e.scheme&&(t+=e.scheme+":"),t+="//",e.auth&&(t+=e.auth+"@"),e.host&&(t+=e.host),e.port&&(t+=":"+e.port),e.path&&(t+=e.path),t}function o(e){var n=e,o=r(e);if(o){if(!o.path)return e;n=o.path}for(var a,s=t.isAbsolute(n),u=n.split(/\/+/),l=0,c=u.length-1;c>=0;c--)a=u[c],"."===a?u.splice(c,1):".."===a?l++:l>0&&(""===a?(u.splice(c+1,l),l=0):(u.splice(c,2),l--));return n=u.join("/"),""===n&&(n=s?"/":"."),o?(o.path=n,i(o)):n}function a(e,t){""===e&&(e="."),""===t&&(t=".");var n=r(t),a=r(e);if(a&&(e=a.path||"/"),n&&!n.scheme)return a&&(n.scheme=a.scheme),i(n);if(n||t.match(_))return t;if(a&&!a.host&&!a.path)return a.host=t,i(a);var s="/"===t.charAt(0)?t:o(e.replace(/\/+$/,"")+"/"+t);return a?(a.path=s,i(a)):s}function s(e,t){""===e&&(e="."),e=e.replace(/\/$/,"");for(var n=0;0!==t.indexOf(e+"/");){var r=e.lastIndexOf("/");if(r<0)return t;if(e=e.slice(0,r),e.match(/^([^\/]+:\/)?\/*$/))return t;++n}return Array(n+1).join("../")+t.substr(e.length+1)}function u(e){return e}function l(e){return p(e)?"$"+e:e}function c(e){return p(e)?e.slice(1):e}function p(e){if(!e)return!1;var t=e.length;if(t<9)return!1;if(95!==e.charCodeAt(t-1)||95!==e.charCodeAt(t-2)||111!==e.charCodeAt(t-3)||116!==e.charCodeAt(t-4)||111!==e.charCodeAt(t-5)||114!==e.charCodeAt(t-6)||112!==e.charCodeAt(t-7)||95!==e.charCodeAt(t-8)||95!==e.charCodeAt(t-9))return!1;for(var n=t-10;n>=0;n--)if(36!==e.charCodeAt(n))return!1;return!0}function f(e,t,n){var r=d(e.source,t.source);return 0!==r?r:0!==(r=e.originalLine-t.originalLine)?r:0!==(r=e.originalColumn-t.originalColumn)||n?r:0!==(r=e.generatedColumn-t.generatedColumn)?r:(r=e.generatedLine-t.generatedLine,0!==r?r:d(e.name,t.name))}function h(e,t,n){var r=e.generatedLine-t.generatedLine;return 0!==r?r:0!==(r=e.generatedColumn-t.generatedColumn)||n?r:0!==(r=d(e.source,t.source))?r:0!==(r=e.originalLine-t.originalLine)?r:(r=e.originalColumn-t.originalColumn,0!==r?r:d(e.name,t.name))}function d(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}function m(e,t){var n=e.generatedLine-t.generatedLine;return 0!==n?n:0!==(n=e.generatedColumn-t.generatedColumn)?n:0!==(n=d(e.source,t.source))?n:0!==(n=e.originalLine-t.originalLine)?n:(n=e.originalColumn-t.originalColumn,0!==n?n:d(e.name,t.name))}function v(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}function g(e,t,n){if(t=t||"",e&&("/"!==e[e.length-1]&&"/"!==t[0]&&(e+="/"),t=e+t),n){var s=r(n);if(!s)throw new Error("sourceMapURL could not be parsed");if(s.path){var u=s.path.lastIndexOf("/");u>=0&&(s.path=s.path.substring(0,u+1))}t=a(i(s),t)}return o(t)}t.getArg=n;var y=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/,_=/^data:.+\,.+$/;t.urlParse=r,t.urlGenerate=i,t.normalize=o,t.join=a,t.isAbsolute=function(e){return"/"===e.charAt(0)||y.test(e)},t.relative=s;var b=function(){return!("__proto__"in Object.create(null))}();t.toSetString=b?u:l,t.fromSetString=b?u:c,t.compareByOriginalPositions=f,t.compareByGeneratedPositionsDeflated=h,t.compareByGeneratedPositionsInflated=m,t.parseSourceMapInput=v,t.computeSourceURL=g},function(e,t,n){"use strict";function r(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}function i(e,t,n){switch(e){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":return!(!n.disabled||!r(t));default:return!1}}var o=n(11),a=n(246),s=n(247),u=n(251),l=n(475),c=n(476),p=(n(8),{}),f=null,h=function(e,t){e&&(s.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e))},d=function(e){return h(e,!0)},m=function(e){return h(e,!1)},v=function(e){return"."+e._rootNodeID},g={injection:{injectEventPluginOrder:a.injectEventPluginOrder,injectEventPluginsByName:a.injectEventPluginsByName},putListener:function(e,t,n){"function"!=typeof n&&o("94",t,typeof n);var r=v(e);(p[t]||(p[t]={}))[r]=n;var i=a.registrationNameModules[t];i&&i.didPutListener&&i.didPutListener(e,t,n)},getListener:function(e,t){var n=p[t];if(i(t,e._currentElement.type,e._currentElement.props))return null;var r=v(e);return n&&n[r]},deleteListener:function(e,t){var n=a.registrationNameModules[t];n&&n.willDeleteListener&&n.willDeleteListener(e,t);var r=p[t];if(r){delete r[v(e)]}},deleteAllListeners:function(e){var t=v(e);for(var n in p)if(p.hasOwnProperty(n)&&p[n][t]){var r=a.registrationNameModules[n];r&&r.willDeleteListener&&r.willDeleteListener(e,n),delete p[n][t]}},extractEvents:function(e,t,n,r){for(var i,o=a.plugins,s=0;s0&&void 0!==arguments[0]?arguments[0]:{};return{type:g,payload:e}}function l(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:y,payload:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.CLEAR_BY=t.CLEAR=t.NEW_AUTH_ERR=t.NEW_SPEC_ERR_BATCH=t.NEW_SPEC_ERR=t.NEW_THROWN_ERR_BATCH=t.NEW_THROWN_ERR=void 0,t.newThrownErr=r,t.newThrownErrBatch=i,t.newSpecErr=o,t.newSpecErrBatch=a,t.newAuthErr=s,t.clear=u,t.clearBy=l;var c=n(268),p=function(e){return e&&e.__esModule?e:{default:e}}(c),f=t.NEW_THROWN_ERR="err_new_thrown_err",h=t.NEW_THROWN_ERR_BATCH="err_new_thrown_err_batch",d=t.NEW_SPEC_ERR="err_new_spec_err",m=t.NEW_SPEC_ERR_BATCH="err_new_spec_err_batch",v=t.NEW_AUTH_ERR="err_new_auth_err",g=t.CLEAR="err_clear",y=t.CLEAR_BY="err_clear_by"},function(e,t,n){e.exports={default:n(608),__esModule:!0}},function(e,t,n){var r=n(54),i=n(345),o=n(343),a=n(38),s=n(133),u=n(195),l={},c={},t=e.exports=function(e,t,n,p,f){var h,d,m,v,g=f?function(){return e}:u(e),y=r(n,p,t?2:1),_=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(o(g)){for(h=s(e.length);h>_;_++)if((v=t?y(a(d=e[_])[0],d[1]):y(e[_]))===l||v===c)return v}else for(m=g.call(e);!(d=m.next()).done;)if((v=i(m,y,d.value,t))===l||v===c)return v};t.BREAK=l,t.RETURN=c},function(e,t){e.exports=!0},function(e,t,n){var r=n(134)("meta"),i=n(29),o=n(56),a=n(43).f,s=0,u=Object.isExtensible||function(){return!0},l=!n(55)(function(){return u(Object.preventExtensions({}))}),c=function(e){a(e,r,{value:{i:"O"+ ++s,w:{}}})},p=function(e,t){if(!i(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!o(e,r)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[r].i},f=function(e,t){if(!o(e,r)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[r].w},h=function(e){return l&&d.NEED&&u(e)&&!o(e,r)&&c(e),e},d=e.exports={KEY:r,NEED:!1,fastKey:p,getWeak:f,onFreeze:h}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var r=n(191),i=Math.min;e.exports=function(e){return e>0?i(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(135);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";var r=n(64),i=n(78),o=n(107),a=n(58),s=n(19);e.exports=function(e,t,n){var u=s(e),l=n(a,u,""[e]),c=l[0],p=l[1];o(function(){var t={};return t[u]=function(){return 7},7!=""[e](t)})&&(i(String.prototype,e,c),r(RegExp.prototype,u,2==t?function(e,t){return p.call(e,this,t)}:function(e){return p.call(e,this)}))}},function(e,t,n){var r=n(62),i=n(655),o=n(674),a=Object.defineProperty;t.f=n(106)?Object.defineProperty:function(e,t,n){if(r(e),t=o(t,!0),r(n),i)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(657),i=n(58);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";var r,i=n(381),o=n(384),a=n(744),s=n(749);r=e.exports=function(e,t){var n,r,a,u,l;return arguments.length<2||"string"!=typeof e?(u=t,t=e,e=null):u=arguments[2],null==e?(n=a=!0,r=!1):(n=s.call(e,"c"),r=s.call(e,"e"),a=s.call(e,"w")),l={value:t,configurable:n,enumerable:r,writable:a},u?i(o(u),l):l},r.gs=function(e,t,n){var r,u,l,c;return"string"!=typeof e?(l=n,n=t,t=e,e=null):l=arguments[3],null==t?t=void 0:a(t)?null==n?n=void 0:a(n)||(l=n,n=void 0):(l=t,t=n=void 0),null==e?(r=!0,u=!1):(r=s.call(e,"c"),u=s.call(e,"e")),c={get:t,set:n,configurable:r,enumerable:u},l?i(o(l),c):c}},function(e,t,n){"use strict";e.exports=n(741)("forEach")},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function i(e){return"number"==typeof e}function o(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,i,s,u,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var c=new Error('Uncaught, unspecified "error" event. ('+t+")");throw c.context=t,c}if(n=this._events[e],a(n))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:s=Array.prototype.slice.call(arguments,1),n.apply(this,s)}else if(o(n))for(s=Array.prototype.slice.call(arguments,1),l=n.slice(),i=l.length,u=0;u0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,i,a,s;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],a=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(s=a;s-- >0;)if(n[s]===t||n[s].listener&&n[s].listener===t){i=s;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){"use strict";var r={};e.exports=r},function(e,t,n){"use strict";var r=n(81);e.exports=r.DEFAULT=new r({include:[n(118)],explicit:[n(820),n(819),n(818)]})},function(e,t,n){function r(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e]/;e.exports=i},function(e,t,n){"use strict";var r,i=n(25),o=n(245),a=/^[ \r\n\t\f]/,s=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,u=n(253),l=u(function(e,t){if(e.namespaceURI!==o.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(i.canUseDOM){var c=document.createElement("div");c.innerHTML=" ",""===c.innerHTML&&(l=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&s.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),c=null}e.exports=l},function(e,t,n){"use strict";function r(e){var t={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]="number"==typeof e[n]?e[n]:e[n].val);return t}t.__esModule=!0,t.default=r,e.exports=t.default},function(e,t,n){"use strict";e.exports=function(e,t){var n,r,i,o=-1,a=e.posMax,s=e.pos,u=e.isInLabel;if(e.isInLabel)return-1;if(e.labelUnmatchedScopes)return e.labelUnmatchedScopes--,-1;for(e.pos=t+1,e.isInLabel=!0,n=1;e.pos1&&void 0!==arguments[1])||arguments[1];return e=(0,s.normalizeArray)(e),{type:p,payload:{thing:e,shown:t}}}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,s.normalizeArray)(e),{type:c,payload:{thing:e,mode:t}}}Object.defineProperty(t,"__esModule",{value:!0}),t.SHOW=t.UPDATE_MODE=t.UPDATE_FILTER=t.UPDATE_LAYOUT=void 0,t.updateLayout=r,t.updateFilter=i,t.show=o,t.changeMode=a;var s=n(9),u=t.UPDATE_LAYOUT="layout_update_layout",l=t.UPDATE_FILTER="layout_update_filter",c=t.UPDATE_MODE="layout_update_mode",p=t.SHOW="layout_show"},function(e,t,n){"use strict";function r(e,t){return{type:u,payload:{selectedServerUrl:e,namespace:t}}}function i(e){var t=e.value,n=e.pathMethod;return{type:l,payload:{value:t,pathMethod:n}}}function o(e){var t=e.value,n=e.pathMethod;return{type:c,payload:{value:t,pathMethod:n}}}function a(e){var t=e.value,n=e.path,r=e.method;return{type:p,payload:{value:t,path:n,method:r}}}function s(e){var t=e.server,n=e.namespace,r=e.key,i=e.val;return{type:f,payload:{server:t,namespace:n,key:r,val:i}}}Object.defineProperty(t,"__esModule",{value:!0}),t.setSelectedServer=r,t.setRequestBodyValue=i,t.setRequestContentType=o,t.setResponseContentType=a,t.setServerVariableValue=s;var u=t.UPDATE_SELECTED_SERVER="oas3_set_servers",l=t.UPDATE_REQUEST_BODY_VALUE="oas3_set_request_body_value",c=t.UPDATE_REQUEST_CONTENT_TYPE="oas3_set_request_content_type",p=t.UPDATE_RESPONSE_CONTENT_TYPE="oas3_set_response_content_type",f=t.UPDATE_SERVER_VARIABLE_VALUE="oas3_set_server_variable_value"},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=h(e,t);if(n)return(0,s.default)(n,{declaration:!0,indent:"\t"})}Object.defineProperty(t,"__esModule",{value:!0}),t.memoizedSampleFromSchema=t.memoizedCreateXMLExample=t.sampleXmlFromSchema=t.inferSchema=t.sampleFromSchema=void 0,t.createXMLExample=i;var o=n(9),a=n(1213),s=r(a),u=n(982),l=r(u),c={string:function(){return"string"},string_email:function(){return"user@example.com"},"string_date-time":function(){return(new Date).toISOString()},number:function(){return 0},number_float:function(){return 0},integer:function(){return 0},boolean:function(e){return"boolean"!=typeof e.default||e.default}},p=function(e){e=(0,o.objectify)(e);var t=e,n=t.type,r=t.format,i=c[n+"_"+r]||c[n];return(0,o.isFunc)(i)?i(e):"Unknown Type: "+e.type},f=t.sampleFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.example,s=r.properties,u=r.additionalProperties,l=r.items,c=n.includeReadOnly,f=n.includeWriteOnly;if(a&&a.$$ref&&delete a.$$ref,void 0!==a)return a;if(!i)if(s)i="object";else{if(!l)return;i="array"}if("object"===i){var h=(0,o.objectify)(s),d={};for(var m in h)h[m].readOnly&&!c||h[m].writeOnly&&!f||(d[m]=e(h[m],n));if(!0===u)d.additionalProp1={};else if(u)for(var v=(0,o.objectify)(u),g=e(v,n),y=1;y<4;y++)d["additionalProp"+y]=g;return d}return"array"===i?Array.isArray(l.anyOf)?l.anyOf.map(function(t){return e(t,n)}):Array.isArray(l.oneOf)?l.oneOf.map(function(t){return e(t,n)}):[e(l,n)]:t.enum?t.default?t.default:(0,o.normalizeArray)(t.enum)[0]:"file"!==i?p(t):void 0},h=(t.inferSchema=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},t.sampleXmlFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.properties,s=r.additionalProperties,u=r.items,l=r.example,c=n.includeReadOnly,f=n.includeWriteOnly,h=r.default,d={},m={},v=t.xml,g=v.name,y=v.prefix,_=v.namespace,b=r.enum,x=void 0,w=void 0;if(!i)if(a||s)i="object";else{if(!u)return;i="array"}if(g=g||"notagname",x=(y?y+":":"")+g,_){m[y?"xmlns:"+y:"xmlns"]=_}if("array"===i&&u){if(u.xml=u.xml||v||{},u.xml.name=u.xml.name||v.name,v.wrapped)return d[x]=[],Array.isArray(l)?l.forEach(function(t){u.example=t,d[x].push(e(u,n))}):Array.isArray(h)?h.forEach(function(t){u.default=t,d[x].push(e(u,n))}):d[x]=[e(u,n)],m&&d[x].push({_attr:m}),d;var k=[];return Array.isArray(l)?(l.forEach(function(t){u.example=t,k.push(e(u,n))}),k):Array.isArray(h)?(h.forEach(function(t){u.default=t,k.push(e(u,n))}),k):e(u,n)}if("object"===i){var E=(0,o.objectify)(a);d[x]=[],l=l||{};for(var S in E)if(E.hasOwnProperty(S)&&(!E[S].readOnly||c)&&(!E[S].writeOnly||f))if(E[S].xml=E[S].xml||{},E[S].xml.attribute){var C=Array.isArray(E[S].enum)&&E[S].enum[0],A=E[S].example,D=E[S].default;m[E[S].xml.name||S]=void 0!==A&&A||void 0!==l[S]&&l[S]||void 0!==D&&D||C||p(E[S])}else{E[S].xml.name=E[S].xml.name||S,E[S].example=void 0!==E[S].example?E[S].example:l[S];var O=e(E[S]);Array.isArray(O)?d[x]=d[x].concat(O):d[x].push(O)}return!0===s?d[x].push({additionalProp:"Anything can be here"}):s&&d[x].push({additionalProp:p(s)}),m&&d[x].push({_attr:m}),d}return w=void 0!==l?l:void 0!==h?h:Array.isArray(b)?b[0]:p(t),d[x]=m?[{_attr:m},w]:w,d});t.memoizedCreateXMLExample=(0,l.default)(i),t.memoizedSampleFromSchema=(0,l.default)(f)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=se(e).replace(/\t/g," ");if("string"==typeof e)return{type:H,payload:t}}function o(e){return{type:ie,payload:e}}function a(e){return{type:J,payload:e}}function s(e){return{type:G,payload:e}}function u(e,t,n,r,i){return{type:X,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:i}}}function l(e){return{type:ne,payload:{pathMethod:e}}}function c(e,t){return{type:re,payload:{path:e,value:t,key:"consumes_value"}}}function p(e,t){return{type:re,payload:{path:e,value:t,key:"produces_value"}}}function f(e,t){return{type:ee,payload:{path:e,method:t}}}function h(e,t){return{type:te,payload:{path:e,method:t}}}function d(e,t,n){return{type:ae,payload:{scheme:e,path:t,method:n}}}Object.defineProperty(t,"__esModule",{value:!0}),t.execute=t.executeRequest=t.logRequest=t.setMutatedRequest=t.setRequest=t.setResponse=t.validateParams=t.invalidateResolvedSubtreeCache=t.updateResolvedSubtree=t.requestResolvedSubtree=t.resolveSpec=t.parseToJson=t.SET_SCHEME=t.UPDATE_RESOLVED_SUBTREE=t.UPDATE_RESOLVED=t.UPDATE_OPERATION_META_VALUE=t.CLEAR_VALIDATE_PARAMS=t.CLEAR_REQUEST=t.CLEAR_RESPONSE=t.LOG_REQUEST=t.SET_MUTATED_REQUEST=t.SET_REQUEST=t.SET_RESPONSE=t.VALIDATE_PARAMS=t.UPDATE_PARAM=t.UPDATE_JSON=t.UPDATE_URL=t.UPDATE_SPEC=void 0;var m=n(20),v=r(m),g=n(97),y=r(g),_=n(27),b=r(_),x=n(47),w=r(x),k=n(128),E=r(k),S=n(339),C=r(S),A=n(338),D=r(A),O=n(48),M=r(O);t.updateSpec=i,t.updateResolved=o,t.updateUrl=a,t.updateJsonSpec=s,t.changeParam=u,t.clearValidateParams=l,t.changeConsumesValue=c,t.changeProducesValue=p,t.clearResponse=f,t.clearRequest=h,t.setScheme=d;var T=n(214),P=r(T),I=n(7),R=n(1201),j=r(R),N=n(268),F=r(N),B=n(433),L=r(B),q=n(956),z=r(q),U=n(969),W=r(U),V=n(9),H=t.UPDATE_SPEC="spec_update_spec",J=t.UPDATE_URL="spec_update_url",G=t.UPDATE_JSON="spec_update_json",X=t.UPDATE_PARAM="spec_update_param",Y=t.VALIDATE_PARAMS="spec_validate_param",K=t.SET_RESPONSE="spec_set_response",$=t.SET_REQUEST="spec_set_request",Z=t.SET_MUTATED_REQUEST="spec_set_mutated_request",Q=t.LOG_REQUEST="spec_log_request",ee=t.CLEAR_RESPONSE="spec_clear_response",te=t.CLEAR_REQUEST="spec_clear_request",ne=t.CLEAR_VALIDATE_PARAMS="spec_clear_validate_param",re=t.UPDATE_OPERATION_META_VALUE="spec_update_operation_meta_value",ie=t.UPDATE_RESOLVED="spec_update_resolved",oe=t.UPDATE_RESOLVED_SUBTREE="spec_update_resolved_subtree",ae=t.SET_SCHEME="set_scheme",se=function(e){return(0,L.default)(e)?e:""},ue=(t.parseToJson=function(e){return function(t){var n=t.specActions,r=t.specSelectors,i=t.errActions,o=r.specStr,a=null;try{e=e||o(),i.clear({source:"parser"}),a=P.default.safeLoad(e)}catch(e){return console.error(e),i.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return a&&"object"===(void 0===a?"undefined":(0,M.default)(a))?n.updateJsonSpec(a):{}}},!1),le=(t.resolveSpec=function(e,t){return function(n){var r=n.specActions,i=n.specSelectors,o=n.errActions,a=n.fn,s=a.fetch,u=a.resolve,l=a.AST,c=n.getConfigs;ue||(console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"),ue=!0);var p=c(),f=p.modelPropertyMacro,h=p.parameterMacro,d=p.requestInterceptor,m=p.responseInterceptor;void 0===e&&(e=i.specJson()),void 0===t&&(t=i.url());var v=l.getLineNumberForPath,g=i.specStr();return u({fetch:s,spec:e,baseDoc:t,modelPropertyMacro:f,parameterMacro:h,requestInterceptor:d,responseInterceptor:m}).then(function(e){var t=e.spec,n=e.errors;if(o.clear({type:"thrown"}),Array.isArray(n)&&n.length>0){var i=n.map(function(e){return console.error(e),e.line=e.fullPath?v(g,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e});o.newThrownErrBatch(i)}return r.updateResolved(t)})}},[]),ce=(0,z.default)((0,D.default)(C.default.mark(function e(){var t,n,r,i,o,a,s,u,l,c,p,f,h,d,m;return C.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=le.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,i=t.fn,o=i.resolveSubtree,a=i.AST.getLineNumberForPath,s=t.specSelectors,u=t.specActions,o){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return l=s.specStr(),c=t.getConfigs(),p=c.modelPropertyMacro,f=c.parameterMacro,h=c.requestInterceptor,d=c.responseInterceptor,e.prev=10,e.next=13,le.reduce(function(){var e=(0,D.default)(C.default.mark(function e(t,i){var u,c,m,v,g,y,_;return C.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return u=e.sent,c=u.resultMap,m=u.specWithCurrentSubtrees,e.next=7,o(m,i,{baseDoc:s.url(),modelPropertyMacro:p,parameterMacro:f,requestInterceptor:h,responseInterceptor:d});case 7:return v=e.sent,g=v.errors,y=v.spec,r.allErrors().size&&n.clear({type:"thrown"}),Array.isArray(g)&&g.length>0&&(_=g.map(function(e){return e.line=e.fullPath?a(l,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e}),n.newThrownErrBatch(_)),(0,W.default)(c,i,y),(0,W.default)(m,i,y),e.abrupt("return",{resultMap:c,specWithCurrentSubtrees:m});case 15:case"end":return e.stop()}},e,void 0)}));return function(t,n){return e.apply(this,arguments)}}(),E.default.resolve({resultMap:(s.specResolvedSubtree([])||(0,I.Map)()).toJS(),specWithCurrentSubtrees:s.specJson().toJS()}));case 13:m=e.sent,delete le.system,le=[],e.next=21;break;case 18:e.prev=18,e.t0=e.catch(10),console.error(e.t0);case 21:u.updateResolvedSubtree([],m.resultMap);case 22:case"end":return e.stop()}},e,void 0,[[10,18]])})),35),pe=(t.requestResolvedSubtree=function(e){return function(t){le.push(e),le.system=t,ce()}},t.updateResolvedSubtree=function(e,t){return{type:oe,payload:{path:e,value:t}}},t.invalidateResolvedSubtreeCache=function(){return{type:oe,payload:{path:[],value:(0,I.Map)()}}},t.validateParams=function(e,t){return{type:Y,payload:{pathMethod:e,isOAS3:t}}},t.setResponse=function(e,t,n){return{payload:{path:e,method:t,res:n},type:K}},t.setRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:$}},t.setMutatedRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:Z}},t.logRequest=function(e){return{payload:e,type:Q}},t.executeRequest=function(e){return function(t){var n=t.fn,r=t.specActions,i=t.specSelectors,o=t.getConfigs,a=t.oas3Selectors,s=e.pathName,u=e.method,l=e.operation,c=o(),p=c.requestInterceptor,f=c.responseInterceptor,h=l.toJS();if(e.contextUrl=(0,j.default)(i.url()).toString(),h&&h.operationId?e.operationId=h.operationId:h&&s&&u&&(e.operationId=n.opId(h,s,u)),i.isOAS3()){var d=s+":"+u;e.server=a.selectedServer(d)||a.selectedServer();var m=a.serverVariables({server:e.server,namespace:d}).toJS(),v=a.serverVariables({server:e.server}).toJS();e.serverVariables=(0,w.default)(m).length?m:v,e.requestContentType=a.requestContentType(s,u),e.responseContentType=a.responseContentType(s,u)||"*/*";var g=a.requestBodyValue(s,u);(0,V.isJSONObject)(g)?e.requestBody=JSON.parse(g):e.requestBody=g}var y=(0,b.default)({},e);y=n.buildRequest(y),r.setRequest(e.pathName,e.method,y);var _=function(t){var n=p.apply(this,[t]),i=(0,b.default)({},n);return r.setMutatedRequest(e.pathName,e.method,i),n};e.requestInterceptor=_,e.responseInterceptor=f;var x=Date.now();return n.execute(e).then(function(t){t.duration=Date.now()-x,r.setResponse(e.pathName,e.method,t)}).catch(function(t){return r.setResponse(e.pathName,e.method,{error:!0,err:(0,F.default)(t)})})}},function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=(0,y.default)(e,["path","method"]);return function(e){var i=e.fn.fetch,o=e.specSelectors,a=e.specActions,s=o.specJsonWithResolvedSubtrees().toJS(),u=o.operationScheme(t,n),l=o.contentTypeValues([t,n]).toJS(),c=l.requestContentType,p=l.responseContentType,f=/xml/i.test(c),h=o.parameterValues([t,n],f).toJS();return a.executeRequest((0,v.default)({},r,{fetch:i,spec:s,pathName:t,method:n,parameters:h,requestContentType:c,scheme:u,responseContentType:p}))}});t.execute=pe},function(e,t,n){"use strict";function r(e,t,n,r){return t=t||[],e.getIn(["meta","paths"].concat((0,f.default)(t),["parameters"]),(0,m.fromJS)([])).find(function(e){return m.Map.isMap(e)&&e.get("name")===n&&e.get("in")===r})||(0,m.Map)()}function i(e,t,n){return t=t||[],j.apply(void 0,[e].concat((0,f.default)(t))).get("parameters",(0,m.List)()).reduce(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(t.get("in")+"."+t.get("name"),r)},(0,m.fromJS)({}))}function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(m.List.isList(e))return e.some(function(e){return m.Map.isMap(e)&&e.get("in")===t})}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(m.List.isList(e))return e.some(function(e){return m.Map.isMap(e)&&e.get("type")===t})}function s(e,t){t=t||[];var n=b(e).getIn(["paths"].concat((0,f.default)(t)),(0,m.fromJS)({})),r=e.getIn(["meta","paths"].concat((0,f.default)(t)),(0,m.fromJS)({})),i=l(e,t),o=n.get("parameters")||new m.List,s=r.get("consumes_value")?r.get("consumes_value"):a(o,"file")?"multipart/form-data":a(o,"formData")?"application/x-www-form-urlencoded":void 0;return(0,m.fromJS)({requestContentType:s,responseContentType:i})}function u(e,t){return t=t||[],b(e).getIn(["paths"].concat((0,f.default)(t),["consumes"]),(0,m.fromJS)({}))}function l(e,t){t=t||[];var n=b(e).getIn(["paths"].concat((0,f.default)(t)),null);if(null!==n){var r=e.getIn(["meta","paths"].concat((0,f.default)(t),["produces_value"]),null),i=n.getIn(["produces",0],null);return r||i||"application/json"}}function c(e){return m.Map.isMap(e)?e:new m.Map}Object.defineProperty(t,"__esModule",{value:!0}),t.validateBeforeExecute=t.canExecuteScheme=t.operationScheme=t.hasHost=t.parameterWithMeta=t.operationWithMeta=t.allowTryItOutFor=t.mutatedRequestFor=t.requestFor=t.responseFor=t.mutatedRequests=t.requests=t.responses=t.taggedOperations=t.operationsWithTags=t.tagDetails=t.tags=t.operationsWithRootInherited=t.schemes=t.host=t.basePath=t.definitions=t.findDefinition=t.securityDefinitions=t.security=t.produces=t.consumes=t.operations=t.paths=t.semver=t.version=t.externalDocs=t.info=t.isOAS3=t.spec=t.specJsonWithResolvedSubtrees=t.specResolvedSubtree=t.specResolved=t.specJson=t.specSource=t.specStr=t.url=t.lastError=void 0;var p=n(72),f=function(e){return e&&e.__esModule?e:{default:e}}(p);t.getParameter=r,t.parameterValues=i,t.parametersIncludeIn=o,t.parametersIncludeType=a,t.contentTypeValues=s,t.operationConsumes=u,t.currentProducesFor=l;var h=n(60),d=n(9),m=n(7),v=["get","put","post","delete","options","head","patch","trace"],g=function(e){return e||(0,m.Map)()},y=(t.lastError=(0,h.createSelector)(g,function(e){return e.get("lastError")}),t.url=(0,h.createSelector)(g,function(e){return e.get("url")}),t.specStr=(0,h.createSelector)(g,function(e){return e.get("spec")||""}),t.specSource=(0,h.createSelector)(g,function(e){return e.get("specSource")||"not-editor"}),t.specJson=(0,h.createSelector)(g,function(e){return e.get("json",(0,m.Map)())})),_=(t.specResolved=(0,h.createSelector)(g,function(e){return e.get("resolved",(0,m.Map)())}),t.specResolvedSubtree=function(e,t){return e.getIn(["resolvedSubtrees"].concat((0,f.default)(t)),void 0)},function e(t,n){return m.Map.isMap(t)&&m.Map.isMap(n)?n.get("$$ref")?n:(0,m.Map)().mergeWith(e,t,n):n}),b=t.specJsonWithResolvedSubtrees=(0,h.createSelector)(g,function(e){return(0,m.Map)().mergeWith(_,e.get("json"),e.get("resolvedSubtrees"))}),x=t.spec=function(e){return y(e)},w=(t.isOAS3=(0,h.createSelector)(x,function(){return!1}),t.info=(0,h.createSelector)(x,function(e){return c(e&&e.get("info"))})),k=(t.externalDocs=(0,h.createSelector)(x,function(e){return c(e&&e.get("externalDocs"))}),t.version=(0,h.createSelector)(w,function(e){return e&&e.get("version")})),E=(t.semver=(0,h.createSelector)(k,function(e){return/v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e).slice(1)}),t.paths=(0,h.createSelector)(x,function(e){return e.get("paths")})),S=t.operations=(0,h.createSelector)(E,function(e){if(!e||e.size<1)return(0,m.List)();var t=(0,m.List)();return e&&e.forEach?(e.forEach(function(e,n){if(!e||!e.forEach)return{};e.forEach(function(e,r){v.indexOf(r)<0||(t=t.push((0,m.fromJS)({path:n,method:r,operation:e,id:r+"-"+n})))})}),t):(0,m.List)()}),C=t.consumes=(0,h.createSelector)(x,function(e){return(0,m.Set)(e.get("consumes"))}),A=t.produces=(0,h.createSelector)(x,function(e){return(0,m.Set)(e.get("produces"))}),D=(t.security=(0,h.createSelector)(x,function(e){return e.get("security",(0,m.List)())}),t.securityDefinitions=(0,h.createSelector)(x,function(e){return e.get("securityDefinitions")}),t.findDefinition=function(e,t){var n=e.getIn(["resolvedSubtrees","definitions",t],null),r=e.getIn(["json","definitions",t],null);return n||r||null},t.definitions=(0,h.createSelector)(x,function(e){return e.get("definitions")||(0,m.Map)()}),t.basePath=(0,h.createSelector)(x,function(e){return e.get("basePath")}),t.host=(0,h.createSelector)(x,function(e){return e.get("host")}),t.schemes=(0,h.createSelector)(x,function(e){return e.get("schemes",(0,m.Map)())}),t.operationsWithRootInherited=(0,h.createSelector)(S,C,A,function(e,t,n){return e.map(function(e){return e.update("operation",function(e){if(e){if(!m.Map.isMap(e))return;return e.withMutations(function(e){return e.get("consumes")||e.update("consumes",function(e){return(0,m.Set)(e).merge(t)}),e.get("produces")||e.update("produces",function(e){return(0,m.Set)(e).merge(n)}),e})}return(0,m.Map)()})})})),O=t.tags=(0,h.createSelector)(x,function(e){return e.get("tags",(0,m.List)())}),M=t.tagDetails=function(e,t){return(O(e)||(0,m.List)()).filter(m.Map.isMap).find(function(e){return e.get("name")===t},(0,m.Map)())},T=t.operationsWithTags=(0,h.createSelector)(D,O,function(e,t){return e.reduce(function(e,t){var n=(0,m.Set)(t.getIn(["operation","tags"]));return n.count()<1?e.update("default",(0,m.List)(),function(e){return e.push(t)}):n.reduce(function(e,n){return e.update(n,(0,m.List)(),function(e){return e.push(t)})},e)},t.reduce(function(e,t){return e.set(t.get("name"),(0,m.List)())},(0,m.OrderedMap)()))}),P=(t.taggedOperations=function(e){return function(t){var n=t.getConfigs,r=n(),i=r.tagsSorter,o=r.operationsSorter;return T(e).sortBy(function(e,t){return t},function(e,t){var n="function"==typeof i?i:d.sorters.tagsSorter[i];return n?n(e,t):null}).map(function(t,n){var r="function"==typeof o?o:d.sorters.operationsSorter[o],i=r?t.sort(r):t;return(0,m.Map)({tagDetails:M(e,n),operations:i})})}},t.responses=(0,h.createSelector)(g,function(e){return e.get("responses",(0,m.Map)())})),I=t.requests=(0,h.createSelector)(g,function(e){return e.get("requests",(0,m.Map)())}),R=t.mutatedRequests=(0,h.createSelector)(g,function(e){return e.get("mutatedRequests",(0,m.Map)())}),j=(t.responseFor=function(e,t,n){return P(e).getIn([t,n],null)},t.requestFor=function(e,t,n){return I(e).getIn([t,n],null)},t.mutatedRequestFor=function(e,t,n){return R(e).getIn([t,n],null)},t.allowTryItOutFor=function(){return!0},t.operationWithMeta=function(e,t,n){var r=b(e).getIn(["paths",t,n],(0,m.Map)()),i=e.getIn(["meta","paths",t,n],(0,m.Map)()),o=r.get("parameters",(0,m.List)()).map(function(e){return(0,m.Map)().merge(e,i.getIn(["parameters",e.get("name")+"."+e.get("in")]))});return(0,m.Map)().merge(r,i).set("parameters",o)}),N=(t.parameterWithMeta=function(e,t,n,r){var i=b(e).getIn(["paths"].concat((0,f.default)(t),["parameters"]),(0,m.Map)()),o=e.getIn(["meta","paths"].concat((0,f.default)(t),["parameters"]),(0,m.Map)());return i.map(function(e){return(0,m.Map)().merge(e,o.get(e.get("name")+"."+e.get("in")))}).find(function(e){return e.get("in")===r&&e.get("name")===n},(0,m.Map)())},t.hasHost=(0,h.createSelector)(x,function(e){var t=e.get("host");return"string"==typeof t&&t.length>0&&"/"!==t[0]}),t.operationScheme=function(e,t,n){var r=e.get("url"),i=r.match(/^([a-z][a-z0-9+\-.]*):/),o=Array.isArray(i)?i[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""});t.canExecuteScheme=function(e,t,n){return["http","https"].indexOf(N(e,t,n))>-1},t.validateBeforeExecute=function(e,t){t=t||[];var n=e.getIn(["meta","paths"].concat((0,f.default)(t),["parameters"]),(0,m.fromJS)([])),r=!0;return n.forEach(function(e){var t=e.get("errors");t&&t.count()&&(r=!1)}),r}},function(e,t,n){"use strict";function r(e){switch(e._type){case"document":case"block_quote":case"list":case"item":case"paragraph":case"heading":case"emph":case"strong":case"link":case"image":case"custom_inline":case"custom_block":return!0;default:return!1}}var i=function(e,t){this.current=e,this.entering=!0===t},o=function(){var e=this.current,t=this.entering;if(null===e)return null;var n=r(e);return t&&n?e._firstChild?(this.current=e._firstChild,this.entering=!0):this.entering=!1:e===this.root?this.current=null:null===e._next?(this.current=e._parent,this.entering=!1):(this.current=e._next,this.entering=!0),{entering:t,node:e}},a=function(e){return{current:e,root:e,entering:!0,next:o,resumeAt:i}},s=function(e,t){this._type=e,this._parent=null,this._firstChild=null,this._lastChild=null,this._prev=null,this._next=null,this._sourcepos=t,this._lastLineBlank=!1,this._open=!0,this._string_content=null,this._literal=null,this._listData={},this._info=null,this._destination=null,this._title=null,this._isFenced=!1,this._fenceChar=null,this._fenceLength=0,this._fenceOffset=null,this._level=null,this._onEnter=null,this._onExit=null},u=s.prototype;Object.defineProperty(u,"isContainer",{get:function(){return r(this)}}),Object.defineProperty(u,"type",{get:function(){return this._type}}),Object.defineProperty(u,"firstChild",{get:function(){return this._firstChild}}),Object.defineProperty(u,"lastChild",{get:function(){return this._lastChild}}),Object.defineProperty(u,"next",{get:function(){return this._next}}),Object.defineProperty(u,"prev",{get:function(){return this._prev}}),Object.defineProperty(u,"parent",{get:function(){return this._parent}}),Object.defineProperty(u,"sourcepos",{get:function(){return this._sourcepos}}),Object.defineProperty(u,"literal",{get:function(){return this._literal},set:function(e){this._literal=e}}),Object.defineProperty(u,"destination",{get:function(){return this._destination},set:function(e){this._destination=e}}),Object.defineProperty(u,"title",{get:function(){return this._title},set:function(e){this._title=e}}),Object.defineProperty(u,"info",{get:function(){return this._info},set:function(e){this._info=e}}),Object.defineProperty(u,"level",{get:function(){return this._level},set:function(e){this._level=e}}),Object.defineProperty(u,"listType",{get:function(){return this._listData.type},set:function(e){this._listData.type=e}}),Object.defineProperty(u,"listTight",{get:function(){return this._listData.tight},set:function(e){this._listData.tight=e}}),Object.defineProperty(u,"listStart",{get:function(){return this._listData.start},set:function(e){this._listData.start=e}}),Object.defineProperty(u,"listDelimiter",{get:function(){return this._listData.delimiter},set:function(e){this._listData.delimiter=e}}),Object.defineProperty(u,"onEnter",{get:function(){return this._onEnter},set:function(e){this._onEnter=e}}),Object.defineProperty(u,"onExit",{get:function(){return this._onExit},set:function(e){this._onExit=e}}),s.prototype.appendChild=function(e){e.unlink(),e._parent=this,this._lastChild?(this._lastChild._next=e,e._prev=this._lastChild,this._lastChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.prependChild=function(e){e.unlink(),e._parent=this,this._firstChild?(this._firstChild._prev=e,e._next=this._firstChild,this._firstChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.unlink=function(){this._prev?this._prev._next=this._next:this._parent&&(this._parent._firstChild=this._next),this._next?this._next._prev=this._prev:this._parent&&(this._parent._lastChild=this._prev),this._parent=null,this._next=null,this._prev=null},s.prototype.insertAfter=function(e){e.unlink(),e._next=this._next,e._next&&(e._next._prev=e),e._prev=this,this._next=e,e._parent=this._parent,e._next||(e._parent._lastChild=e)},s.prototype.insertBefore=function(e){e.unlink(),e._prev=this._prev,e._prev&&(e._prev._next=e),e._next=this,this._prev=e,e._parent=this._parent,e._prev||(e._parent._firstChild=e)},s.prototype.walker=function(){return new a(this)},e.exports=s},function(e,t){e.exports=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){var r=n(54),i=n(183),o=n(76),a=n(133),s=n(615);e.exports=function(e,t){var n=1==e,u=2==e,l=3==e,c=4==e,p=6==e,f=5==e||p,h=t||s;return function(t,s,d){for(var m,v,g=o(t),y=i(g),_=r(s,d,3),b=a(y.length),x=0,w=n?h(t,b):u?h(t,0):void 0;b>x;x++)if((f||x in y)&&(m=y[x],v=_(m,x,g),e))if(n)w[x]=v;else if(v)switch(e){case 3:return!0;case 5:return m;case 6:return x;case 2:w.push(m)}else if(c)return!1;return p?-1:l||c?c:w}}},function(e,t,n){var r=n(99),i=n(21)("toStringTag"),o="Arguments"==r(function(){return arguments}()),a=function(e,t){try{return e[t]}catch(e){}};e.exports=function(e){var t,n,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=a(t=Object(e),i))?n:o?r(t):"Object"==(s=r(t))&&"function"==typeof t.callee?"Arguments":s}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(29),i=n(24).document,o=r(i)&&r(i.createElement);e.exports=function(e){return o?i.createElement(e):{}}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(99);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==r(e)?e.split(""):Object(e)}},function(e,t,n){"use strict";function r(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=i(t),this.reject=i(n)}var i=n(98);e.exports.f=function(e){return new r(e)}},function(e,t,n){var r=n(38),i=n(624),o=n(182),a=n(189)("IE_PROTO"),s=function(){},u=function(){var e,t=n(181)("iframe"),r=o.length;for(t.style.display="none",n(341).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write("