From c088492cfabada198ad563e43278ab7e869029bc Mon Sep 17 00:00:00 2001 From: nsnail Date: Thu, 29 Aug 2024 17:21:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20=E6=A1=86=E6=9E=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=90=8C=E6=AD=A5=20(#173)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: tk --- .github/workflows/nightly-build.yml | 2 +- .github/workflows/release.yml | 2 +- Directory.Build.props | 2 +- Dockerfile | 2 +- NetAdmin.sln | 2 + assets/res/Statements.ln | 2 + build/code.quality.props | 4 +- scripts/git.del.obsolete.tags.ps1 | 2 + scripts/switcher.freesql.json | 4 +- scripts/wait.server.stop.sh | 28 + .../NetAdmin.AdmServer.Host/Startup.cs | 16 +- .../NetAdmin.AdmServer.Tests/AllTests.cs | 2015 ----------------- .../NetAdmin.AdmServer.Tests.csproj | 2 +- .../Services/RepositoryService.cs | 4 +- .../DbMaps/Dependency/MutableEntity.cs | 14 +- .../Dto/Sys/Cache/DelEntryReq.cs | 13 + .../Dto/Sys/Tool/ExecuteSqlReq.cs | 17 + .../Controllers/ProbeController.cs | 57 + .../Extensions/MethodInfoExtensions.cs | 19 + .../Extensions/ServiceCollectionExtensions.cs | 10 +- .../Filters/DefaultApiResultHandler.cs | 3 +- .../Middlewares/SafetyShopHostMiddleware.cs | 40 +- .../NetAdmin.Infrastructure/Constant/Chars.cs | 15 +- .../NetAdmin.Infrastructure/GlobalStatic.cs | 24 +- .../NetAdmin.Infrastructure.csproj | 6 +- .../Utils/FreeSqlBuilder.cs | 1 - .../Modules/Sys/ICacheModule.cs | 11 + .../Modules/Sys/IToolsModule.cs | 5 + .../Services/Sys/CacheService.cs | 25 + .../Services/Sys/ConfigService.cs | 4 +- .../Services/Sys/DeptService.cs | 4 +- .../Services/Sys/DicCatalogService.cs | 2 +- .../Services/Sys/DicContentService.cs | 5 +- .../Services/Sys/JobRecordService.cs | 2 +- .../Services/Sys/JobService.cs | 60 +- .../Services/Sys/LoginLogService.cs | 2 +- .../Services/Sys/MenuService.cs | 4 +- .../Services/Sys/RequestLogDetailService.cs | 2 +- .../Services/Sys/RequestLogService.cs | 3 +- .../Services/Sys/RoleService.cs | 4 +- .../Services/Sys/SiteMsgDeptService.cs | 2 +- .../Services/Sys/SiteMsgFlagService.cs | 2 +- .../Services/Sys/SiteMsgRoleService.cs | 2 +- .../Services/Sys/SiteMsgService.cs | 2 +- .../Services/Sys/SiteMsgUserService.cs | 2 +- .../Services/Sys/ToolsService.cs | 9 + .../Services/Sys/UserProfileService.cs | 2 +- .../Services/Sys/UserService.cs | 55 +- .../Services/Sys/VerifyCodeService.cs | 9 +- .../Services/Tpl/ExampleService.cs | 2 +- .../Sys/CacheCache.cs | 13 + .../Sys/ToolsCache.cs | 6 + .../Controllers/Sys/CacheController.cs | 17 + .../Controllers/Sys/ToolsController.cs | 8 + .../Jobs/FreeScheduledJob.cs | 6 + .../Jobs/ScheduledJob.cs | 6 + .../Subscribers/OperationLogger.cs | 54 +- .../NetAdmin.SysComponent.Tests.csproj | 8 + .../Sys/ApiTests.cs | 118 + .../Sys/CacheTests.cs | 69 + .../Sys/CaptchaTests.cs | 38 + .../Sys/ConfigTests.cs | 139 ++ .../Sys/ConstantTests.cs | 55 + .../Sys/DeptTests.cs | 130 ++ .../Sys/DevTests.cs | 45 + .../Sys/DicTests.cs | 181 ++ .../Sys/FileTests.cs | 28 + .../Sys/JobTests.cs | 212 ++ .../Sys/LoginLogTests.cs | 110 + .../Sys/MenuTests.cs | 128 ++ .../Sys/RequestLogTests.cs | 141 ++ .../Sys/RoleTests.cs | 150 ++ .../Sys/SiteMsgTests.cs | 159 ++ .../Sys/ToolsTests.cs | 65 + .../Sys/UserTests.cs | 309 +++ .../Sys/VerifyCodeTests.cs | 130 ++ .../Attributes/TestPriorityAttribute.cs | 13 + .../NetAdmin.Tests/NetAdmin.Tests.csproj | 2 +- src/backend/NetAdmin.Tests/PriorityOrderer.cs | 52 + src/backend/NetAdmin.Tests/WebApiTestBase.cs | 67 +- .../WebTestApplicationFactory.cs | 21 + src/frontend/admin/package.json | 18 +- .../admin/src/api/controllers/probe.js | 11 + src/frontend/admin/src/api/sys/cache.js | 22 + src/frontend/admin/src/api/sys/tools.js | 22 + .../components/scEcharts/echarts-theme-T.js | 23 + .../admin/src/components/scFilterBar/my.vue | 2 +- .../src/components/scPageHeader/index.vue | 2 +- .../src/components/scStatistic/index.vue | 2 +- .../admin/src/components/scTable/index.vue | 2 +- src/frontend/admin/src/style/app.scss | 16 + src/frontend/admin/src/style/dark.scss | 4 + src/frontend/admin/src/style/fix.scss | 4 + .../admin/src/views/sys/cache/index.vue | 59 +- .../src/views/sys/log/operation/index.vue | 2 +- 95 files changed, 3055 insertions(+), 2140 deletions(-) create mode 100644 scripts/git.del.obsolete.tags.ps1 create mode 100644 scripts/wait.server.stop.sh delete mode 100644 src/backend/NetAdmin.AdmServer.Tests/AllTests.cs create mode 100644 src/backend/NetAdmin.Domain/Dto/Sys/Cache/DelEntryReq.cs create mode 100644 src/backend/NetAdmin.Domain/Dto/Sys/Tool/ExecuteSqlReq.cs create mode 100644 src/backend/NetAdmin.Host/Extensions/MethodInfoExtensions.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/NetAdmin.SysComponent.Tests.csproj create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/ApiTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/CacheTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/CaptchaTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/ConfigTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/ConstantTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/DeptTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/DevTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/DicTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/FileTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/JobTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/LoginLogTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/MenuTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/RequestLogTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/RoleTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/SiteMsgTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/ToolsTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/UserTests.cs create mode 100644 src/backend/NetAdmin.SysComponent.Tests/Sys/VerifyCodeTests.cs create mode 100644 src/backend/NetAdmin.Tests/Attributes/TestPriorityAttribute.cs create mode 100644 src/backend/NetAdmin.Tests/PriorityOrderer.cs create mode 100644 src/backend/NetAdmin.Tests/WebTestApplicationFactory.cs diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index db69a298..82ec3b5f 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [ 20.x ] + node-version: [ 22.x ] steps: - uses: actions/checkout@v3 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d59090f6..ee088e1b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [ 20.x ] + node-version: [ 22.x ] steps: - uses: actions/checkout@v3 with: diff --git a/Directory.Build.props b/Directory.Build.props index 19a99788..f83ca8a4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,7 +25,7 @@ $(AssemblyName) - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Dockerfile b/Dockerfile index 3ed09ead..2a5d9c79 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.6 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.7 AS base WORKDIR /app EXPOSE 8080 RUN apt update diff --git a/NetAdmin.sln b/NetAdmin.sln index b8218fd4..da3755ac 100644 --- a/NetAdmin.sln +++ b/NetAdmin.sln @@ -39,6 +39,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B gen.id.linq = scripts/gen.id.linq gen.ln.cmd = scripts/gen.ln.cmd gen.resx.tt = scripts/gen.resx.tt + git.del.obsolete.tags.ps1 = scripts/git.del.obsolete.tags.ps1 image.optimize.csx = scripts/image.optimize.csx install.as.tpl.ps1 = scripts/install.as.tpl.ps1 rename.csx = scripts/rename.csx @@ -48,6 +49,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B switcher.nsext.json = scripts/switcher.nsext.json switcher.ps1 = scripts/switcher.ps1 sync.sln.files.csx = scripts/sync.sln.files.csx + wait.server.stop.sh = scripts/wait.server.stop.sh EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1129FE25-466B-4F4F-85FC-3752664245E1}" diff --git a/assets/res/Statements.ln b/assets/res/Statements.ln index 18edb906..02bc1d2f 100644 --- a/assets/res/Statements.ln +++ b/assets/res/Statements.ln @@ -49,6 +49,7 @@ XML注释文件不存在 未获取到待执行任务 模块名称不能为空 模块说明不能为空 +此节点已下线 民族不正确 消息主题不能为空 消息内容不能为空 @@ -65,6 +66,7 @@ XML注释文件不存在 站内信不存在 站内信状态不正确 站内信类型不正确 +缓存键不能为空 网络地址不正确 菜单名称不能为空 菜单标题不能为空 diff --git a/build/code.quality.props b/build/code.quality.props index 9c1ce338..99360677 100644 --- a/build/code.quality.props +++ b/build/code.quality.props @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -23,7 +23,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/scripts/git.del.obsolete.tags.ps1 b/scripts/git.del.obsolete.tags.ps1 new file mode 100644 index 00000000..db65409e --- /dev/null +++ b/scripts/git.del.obsolete.tags.ps1 @@ -0,0 +1,2 @@ +git push origin :refs/tags/$(git tag -l "*-*") +git tag -d $(git tag -l "*-*") \ No newline at end of file diff --git a/scripts/switcher.freesql.json b/scripts/switcher.freesql.json index eabab32a..3390871b 100644 --- a/scripts/switcher.freesql.json +++ b/scripts/switcher.freesql.json @@ -10,11 +10,11 @@ "packages": [ { "packageName": "FreeSql.NS", - "version": "3.2.833-preview20260627-ns1" + "version": "3.2.833-ns4" }, { "packageName": "FreeSql.DbContext.NS", - "version": "3.2.833-preview20260627-ns1" + "version": "3.2.833-ns4" } ] } diff --git a/scripts/wait.server.stop.sh b/scripts/wait.server.stop.sh new file mode 100644 index 00000000..edb73190 --- /dev/null +++ b/scripts/wait.server.stop.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# 检查是否提供了 URL 参数 +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +# 获取外部传入的 URL 参数 +URL="$1" + +# 初始化返回值 +response="" + +# 循环检查 API 返回值 +while [ "$response" != "1" ]; do + # 等待一段时间再进行下一次检查,避免频繁请求 + sleep 1 + + # 使用 curl 请求 URL,并捕获返回值,忽略 SSL 证书错误 + response=$(curl -sk "$URL") + + # 打印返回值 (可选) + echo "$1: $response" +done + +# 当返回值为 "1" 时,继续执行后续脚本 +echo "API returned 1. Continuing with the script..." \ No newline at end of file diff --git a/src/backend/NetAdmin.AdmServer.Host/Startup.cs b/src/backend/NetAdmin.AdmServer.Host/Startup.cs index 8de3924b..f9e1a19c 100644 --- a/src/backend/NetAdmin.AdmServer.Host/Startup.cs +++ b/src/backend/NetAdmin.AdmServer.Host/Startup.cs @@ -24,7 +24,9 @@ namespace NetAdmin.AdmServer.Host /// /// 配置应用程序中间件 /// + #pragma warning disable S2325 public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifeTime) + #pragma warning restore S2325 { _ = app // .UseMiddleware() // 安全停机中间件 @@ -52,7 +54,9 @@ namespace NetAdmin.AdmServer.Host /// /// 配置服务容器 /// + #pragma warning disable S2325 public void ConfigureServices(IServiceCollection services) + #pragma warning restore S2325 { _ = services.AddConsoleFormatter() // 添加控制台日志模板 .AddAllOptions() // 添加配置项 @@ -75,12 +79,18 @@ namespace NetAdmin.AdmServer.Host /// #pragma warning disable ASA001 - public Task Execute(CommandContext context, CommandLineArgs settings) + public async Task Execute(CommandContext context, CommandLineArgs settings) #pragma warning restore ASA001 { Args = settings; - _ = Serve.Run(RunOptions.Default.WithArgs(context.Remaining.Raw.ToArray())); - return Task.FromResult(0); + var webOpt = new WebApplicationOptions // + { + EnvironmentName = Environment.GetEnvironmentVariable("TEST_ENVIRONMENT").NullOrEmpty(null) + , Args = context.Remaining.Raw.ToArray() + }; + Serve.BuildApplication(RunOptions.Default.ConfigureOptions(webOpt), null, out var startUrl, out var app); + await app.RunAsync(startUrl).ConfigureAwait(false); + return 0; } /// diff --git a/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs b/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs deleted file mode 100644 index 0506d843..00000000 --- a/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs +++ /dev/null @@ -1,2015 +0,0 @@ -#pragma warning disable xUnit1024,xUnit1026 - -using System.Diagnostics.CodeAnalysis; -using System.Net.Http.Json; -using Microsoft.AspNetCore.Mvc.Testing; -using NetAdmin.AdmServer.Host; -using NetAdmin.Application.Modules; -using NetAdmin.Domain.Dto.Dependency; -using NetAdmin.Domain.Dto.Sys; -using NetAdmin.Domain.Dto.Sys.Api; -using NetAdmin.Domain.Dto.Sys.Cache; -using NetAdmin.Domain.Dto.Sys.Captcha; -using NetAdmin.Domain.Dto.Sys.Config; -using NetAdmin.Domain.Dto.Sys.Dept; -using NetAdmin.Domain.Dto.Sys.Dev; -using NetAdmin.Domain.Dto.Sys.Dic.Catalog; -using NetAdmin.Domain.Dto.Sys.Dic.Content; -using NetAdmin.Domain.Dto.Sys.Job; -using NetAdmin.Domain.Dto.Sys.JobRecord; -using NetAdmin.Domain.Dto.Sys.Menu; -using NetAdmin.Domain.Dto.Sys.RequestLog; -using NetAdmin.Domain.Dto.Sys.Role; -using NetAdmin.Domain.Dto.Sys.SiteMsg; -using NetAdmin.Domain.Dto.Sys.SiteMsgDept; -using NetAdmin.Domain.Dto.Sys.SiteMsgFlag; -using NetAdmin.Domain.Dto.Sys.SiteMsgRole; -using NetAdmin.Domain.Dto.Sys.SiteMsgUser; -using NetAdmin.Domain.Dto.Sys.Tool; -using NetAdmin.Domain.Dto.Sys.User; -using NetAdmin.Domain.Dto.Sys.UserProfile; -using NetAdmin.Domain.Dto.Sys.VerifyCode; -using NetAdmin.SysComponent.Application.Modules.Sys; -using NetAdmin.Tests; -using Xunit; -using Xunit.Abstractions; - -namespace NetAdmin.AdmServer.Tests; - -/// -/// 所有测试 -/// -[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] -public class AllTests(WebApplicationFactory factory, ITestOutputHelper testOutputHelper) - : WebApiTestBase(factory, testOutputHelper), IApiModule, ICacheModule, ICaptchaModule, IConfigModule - , IConstantModule, IDeptModule, IDevModule, IDicCatalogModule, IDicContentModule, IDicModule, IFileModule - , IJobModule, IJobRecordModule, IMenuModule, IRequestLogModule, IRoleModule, ISiteMsgDeptModule, ISiteMsgFlagModule - , ISiteMsgModule, ISiteMsgRoleModule, ISiteMsgUserModule, IToolsModule, IUserModule, IUserProfileModule - , IVerifyCodeModule - -{ - /// - public Task BulkDeleteCatalogAsync(BulkReq req) - { - return default; - } - - /// - public Task BulkDeleteContentAsync(BulkReq req) - { - return default; - } - - /// - [Fact] - public async Task CacheStatisticsAsync() - { - var rsp = await PostAsync("/api/sys/cache/cache.statistics", null).ConfigureAwait(true); - Assert.Equal(HttpStatusCode.OK, rsp.StatusCode); - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CheckMobileAvailableAsync(CheckMobileAvailableReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CountRecordAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateJobReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateVerifyCodeReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateUserProfileReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateSiteMsgUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateSiteMsgRoleReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateSiteMsgReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateSiteMsgFlagReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateSiteMsgDeptReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateRoleReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateRequestLogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateMenuReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateJobRecordReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateDicContentReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateDicCatalogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateDeptReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateConfigReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateAsync(CreateApiReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateCatalogAsync(CreateDicCatalogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task CreateContentAsync(CreateDicContentReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task DeleteCatalogAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task DeleteContentAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditRoleReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditDeptReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditConfigReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditJobReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditMenuReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditSiteMsgReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditAsync(EditUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditCatalogAsync(EditDicCatalogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task EditContentAsync(EditDicContentReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExecuteAsync(QueryJobReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExistAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportContentAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ExportRecordAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GenerateCsCodeAsync(GenerateCsCodeReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GenerateIconCodeAsync(GenerateIconCodeReq req) - { - return default; - } - - /// - [Fact] - public Task GenerateJsCodeAsync() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetAllEntriesAsync(GetAllEntriesReq req) - { - var rsp = PostAsync("/api/sys/cache/get.all.entries", JsonContent.Create(new GetAllEntriesReq())) - .ConfigureAwait(true) - .GetAwaiter() - #pragma warning disable xUnit1031 - .GetResult(); - #pragma warning restore xUnit1031 - Assert.Equal(HttpStatusCode.OK, rsp.StatusCode); - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryJobReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryVerifyCodeReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryUserProfileReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QuerySiteMsgUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QuerySiteMsgRoleReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QuerySiteMsgReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QuerySiteMsgFlagReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QuerySiteMsgDeptReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryRoleReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryRequestLogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryMenuReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryJobRecordReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryDicContentReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryDicCatalogReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryDeptReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryConfigReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetAsync(QueryApiReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetBarChartAsync(QueryReq req) - { - return default; - } - - /// - [Fact] - public Task GetCaptchaImageAsync() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetCatalogAsync(QueryDicCatalogReq req) - { - return default; - } - - /// - [Fact] - public Task GetChangeLogAsync() - { - return default; - } - - /// - [Fact] - public IDictionary GetCharsDic() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetContentAsync(QueryDicContentReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetDicValueAsync(GetDicValueReq req) - { - return default; - } - - /// - public Task GetEntryAsync(GetEntriesReq req) - { - return default; - } - - /// - [Fact] - public IDictionary> GetEnums() - { - return default; - } - - /// - [Fact] - public Task GetLatestConfigAsync() - { - return default; - } - - /// - [Fact] - public IDictionary GetLocalizedStrings() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetMineAsync(QuerySiteMsgReq req) - { - return default; - } - - /// - [Fact] - public Task> GetModulesAsync() - { - return default; - } - - /// - [Fact] - public IDictionary GetNumbersDic() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetPieChartByApiSummaryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetPieChartByHttpStatusCodeAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task GetRecordAsync(QueryJobRecordReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetRecordBarChartAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> GetRecordPieChartByNameAsync(QueryReq req) - { - return default; - } - - /// - [Fact] - public async Task GetServerUtcTimeAsync() - { - var response = await PostAsync("/api/sys/tools/get.server.utc.time", null).ConfigureAwait(true); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - return default; - } - - /// - [Fact] - public Task GetSessionUserAppConfigAsync() - { - return default; - } - - /// - [Fact] - public async Task GetVersionAsync() - { - var response = await PostAsync("/api/sys/tools/version", null).ConfigureAwait(true); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task LoginByPwdAsync(LoginByPwdReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task LoginBySmsAsync(LoginBySmsReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryCatalogAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryContentAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryMineAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> PagedQueryRecordAsync(PagedQueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryCatalogAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryContentAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task> QueryProfileAsync(QueryReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task RegisterAsync(RegisterUserReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task ResetPasswordAsync(ResetPasswordReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SendVerifyCodeAsync(SendVerifyCodeReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetAvatarAsync(SetAvatarReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetDisplayDashboardAsync(SetDisplayDashboardReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEmailAsync(SetEmailReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEnabledAsync(SetDeptEnabledReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEnabledAsync(SetConfigEnabledReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEnabledAsync(SetRoleEnabledReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEnabledAsync(SetJobEnabledReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetEnabledAsync(SetUserEnabledReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetIgnorePermissionControlAsync(SetIgnorePermissionControlReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetMobileAsync(SetMobileReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetPasswordAsync(SetPasswordReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetSessionUserAppConfigAsync(SetSessionUserAppConfigReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task SetSiteMsgStatusAsync(SetUserSiteMsgStatusReq req) - { - return default; - } - - /// - [Fact] - public async Task SyncAsync() - { - var response = await PostAsync("/api/sys/api/sync", null).ConfigureAwait(true); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - /// - [Fact] - public Task UnreadCountAsync() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task UploadAsync(IFormFile file) - { - return default; - } - - /// - [Fact] - public Task UserInfoAsync() - { - return default; - } - - /// - [Fact] - public Task> UserMenusAsync() - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task VerifyAsync(VerifyCodeReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - public Task VerifyCaptchaAsync(VerifyCaptchaReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - BulkDeleteAsync(BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.BulkDeleteAsync( - BulkReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule. - DeleteAsync(DelReq req) - { - return default; - } - - /// - [InlineData(default)] - [Theory] - Task ICrudModule.DeleteAsync(DelReq req) - { - return default; - } -} \ No newline at end of file diff --git a/src/backend/NetAdmin.AdmServer.Tests/NetAdmin.AdmServer.Tests.csproj b/src/backend/NetAdmin.AdmServer.Tests/NetAdmin.AdmServer.Tests.csproj index 0bba584e..9b35407a 100644 --- a/src/backend/NetAdmin.AdmServer.Tests/NetAdmin.AdmServer.Tests.csproj +++ b/src/backend/NetAdmin.AdmServer.Tests/NetAdmin.AdmServer.Tests.csproj @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Services/RepositoryService.cs b/src/backend/NetAdmin.Application/Services/RepositoryService.cs index 006fb3f9..a4660371 100644 --- a/src/backend/NetAdmin.Application/Services/RepositoryService.cs +++ b/src/backend/NetAdmin.Application/Services/RepositoryService.cs @@ -33,7 +33,7 @@ public abstract class RepositoryService(BasicReposit /// /// 导出实体 /// - protected async Task ExportAsync( // + protected static async Task ExportAsync( // Func, ISelectGrouping> selector, QueryReq query, string fileName , Expression, object>> listExp = null) where TQuery : DataAbstraction, new() @@ -45,7 +45,7 @@ public abstract class RepositoryService(BasicReposit /// /// 导出实体 /// - protected async Task ExportAsync( // + protected static async Task ExportAsync( // Func, ISelect> selector, QueryReq query, string fileName , Expression> listExp = null) where TQuery : DataAbstraction, new() diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs index d357cc1c..82f862bc 100644 --- a/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs @@ -13,9 +13,21 @@ public abstract record MutableEntity : MutableEntity /// /// 可变实体 /// -public abstract record MutableEntity : LiteMutableEntity, IFieldModifiedUser +public abstract record MutableEntity : LiteMutableEntity, IFieldCreatedUser, IFieldModifiedUser where T : IEquatable { + /// + [Column(CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual long? CreatedUserId { get; init; } + + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual string CreatedUserName { get; init; } + /// [Column(IsIdentity = false, IsPrimary = true, Position = 1)] [CsvIgnore] diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Cache/DelEntryReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/DelEntryReq.cs new file mode 100644 index 00000000..106b86a8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/DelEntryReq.cs @@ -0,0 +1,13 @@ +namespace NetAdmin.Domain.Dto.Sys.Cache; + +/// +/// 请求:删除缓存项 +/// +public sealed record DelEntryReq : DataAbstraction +{ + /// + /// 缓存键 + /// + [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.缓存键不能为空))] + public string Key { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Tool/ExecuteSqlReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Tool/ExecuteSqlReq.cs new file mode 100644 index 00000000..a56c86b5 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Tool/ExecuteSqlReq.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.Dto.Sys.Tool; + +/// +/// 请求:执行SQL +/// +public record ExecuteSqlReq : DataAbstraction +{ + /// + /// SQL 语句 + /// + public string Sql { get; init; } + + /// + /// 超时时间(秒) + /// + public int TimeoutSecs { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Controllers/ProbeController.cs b/src/backend/NetAdmin.Host/Controllers/ProbeController.cs index bec7ae29..7495de12 100644 --- a/src/backend/NetAdmin.Host/Controllers/ProbeController.cs +++ b/src/backend/NetAdmin.Host/Controllers/ProbeController.cs @@ -10,6 +10,23 @@ namespace NetAdmin.Host.Controllers; [ApiDescriptionSettings("Probe")] public sealed class ProbeController : ControllerBase, IService> { + /// + /// 退出程序 + /// + [AllowAnonymous] + [HttpGet] + #pragma warning disable CA1822 + public ActionResult Exit(string token) + #pragma warning restore CA1822 + { + if (token != GlobalStatic.SecretKey) { + return new UnauthorizedResult(); + } + + Environment.Exit(0); + return new OkResult(); + } + /// /// 健康检查 /// @@ -23,6 +40,46 @@ public sealed class ProbeController : ControllerBase + /// 系统是否已经安全停止 + /// + [AllowAnonymous] + [HttpGet] + [NonUnify] + #pragma warning disable CA1822, S3400 + public IActionResult IsSystemSafetyStopped(int logTimeoutSeconds = 15) + #pragma warning restore S3400, CA1822 + { + return new ContentResult { + Content = (DateTime.Now - GlobalStatic.LatestLogTime).TotalSeconds > + logTimeoutSeconds + ? "1" + : "0" + }; + } + + /// + /// 实例下线 + /// + /// + /// 流量只出不进 + /// + [AllowAnonymous] + [HttpGet] + #pragma warning disable CA1822 + public ActionResult Offline(string token) + #pragma warning restore CA1822 + { + if (token != GlobalStatic.SecretKey) { + return new UnauthorizedResult(); + } + + SafetyShopHostMiddleware.Stop(); + return new OkResult(); + } } \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/MethodInfoExtensions.cs b/src/backend/NetAdmin.Host/Extensions/MethodInfoExtensions.cs new file mode 100644 index 00000000..c1ae6ad0 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/MethodInfoExtensions.cs @@ -0,0 +1,19 @@ +namespace NetAdmin.Host.Extensions; + +/// +/// Type 扩展方法 +/// +public static class MethodInfoExtensions +{ + /// + /// 获取路由路径 + /// + public static string GetRoutePath(this MethodInfo me, IServiceProvider serviceProvider) + { + return serviceProvider.GetService() + .ActionDescriptors.Items.FirstOrDefault(x => x.DisplayName!.StartsWith( // + $"{me.DeclaringType}.{me.Name}" + , StringComparison.Ordinal)) + ?.AttributeRouteInfo?.Template; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs b/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs index a1983a3b..367944fc 100644 --- a/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs @@ -108,22 +108,20 @@ public static class ServiceCollectionExtensions return me.AddConsoleFormatter(options => { var logLevels = Enum.GetValues().ToDictionary(x => x, x => x.GetDisplay()); - #if DEBUG options.WriteHandler = (message, _, _, _, _) => { + #if DEBUG MarkupLine(message.Message.EscapeMarkup(), message, logLevels); if (message.Exception != null) { MarkupLine(message.Exception.ToString().EscapeMarkup(), message, logLevels); } - }; - - #else - options.WriteHandler = (message, _, _, _, _) => { + #else var msg = message.Message.ReplaceLineEndings(string.Empty); var (date, logName, logFormat) = ParseMessage(message, false); Console.WriteLine( // logFormat, date, logLevels[(LogLevels)message.LogLevel].ShortName, logName, message.ThreadId, msg); + #endif + GlobalStatic.IncrementLogCounter(); }; - #endif }); } diff --git a/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs b/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs index b6dda4b4..8224ac10 100644 --- a/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs +++ b/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs @@ -11,6 +11,7 @@ public sealed class DefaultApiResultHandler : ApiResultHandler public IActionResult OnAuthorizeException(DefaultHttpContext context, ExceptionMetadata metadata) { - throw new NotImplementedException(); + LogHelper.Get().Error(metadata.Exception); + throw metadata.Exception; } } \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Middlewares/SafetyShopHostMiddleware.cs b/src/backend/NetAdmin.Host/Middlewares/SafetyShopHostMiddleware.cs index f9b6a1b5..b3ebca23 100644 --- a/src/backend/NetAdmin.Host/Middlewares/SafetyShopHostMiddleware.cs +++ b/src/backend/NetAdmin.Host/Middlewares/SafetyShopHostMiddleware.cs @@ -9,36 +9,64 @@ namespace NetAdmin.Host.Middlewares; public sealed class SafetyShopHostMiddleware(RequestDelegate next) { private static long _connections; - private static bool _hostStopping; + private static bool _trafficOff; /// /// 当前连接数 /// public static long Connections => Interlocked.Read(ref _connections); + /// + /// 是否已停机 + /// + public static bool IsShutdown => Volatile.Read(ref _trafficOff); + /// /// 停机处理 /// public static void OnStopping() { - Volatile.Write(ref _hostStopping, true); + Stop(); while (Interlocked.Read(ref _connections) > 0) { Thread.Sleep(10); } } + /// + /// 系统启机 + /// + public static void Start() + { + Volatile.Write(ref _trafficOff, false); + } + + /// + /// 系统停机 + /// + public static void Stop() + { + Volatile.Write(ref _trafficOff, true); + } + /// /// 主函数 /// public async Task InvokeAsync(HttpContext context) { - if (Volatile.Read(ref _hostStopping)) { + if (Volatile.Read(ref _trafficOff) && + !context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_RPOBE}")) { context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable; return; } - _ = Interlocked.Increment(ref _connections); - await next(context).ConfigureAwait(false); - _ = Interlocked.Decrement(ref _connections); + // webSocket链接不参与计算 + if (context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_WEBSOCKET_PREFIX}")) { + await next(context).ConfigureAwait(false); + } + else { + _ = Interlocked.Increment(ref _connections); + await next(context).ConfigureAwait(false); + _ = Interlocked.Decrement(ref _connections); + } } } \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs index 4fde6e5e..d7550d0b 100644 --- a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs +++ b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs @@ -73,12 +73,15 @@ public static class Chars public const string FLG_HTTP_METHOD_POST = "POST"; public const string FLG_HTTP_METHOD_PUT = "PUT"; public const string FLG_HTTP_METHOD_TRACE = "TRACE"; - public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd"; - public const string FLG_PATH_PREFIX_HEALTH_CHECK = "probe/health.check"; - public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY"; - public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache"; - public const string FLG_SNOWFLAKE_WORK_ID = "SNOWFLAKE_WORK_ID"; - public const string FLG_SYSTEM_PREFIX = "sc_"; + + public const string FLG_PATH_API_RPOBE = "api/probe"; + public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd"; + public const string FLG_PATH_PREFIX_HEALTH_CHECK = "probe/health.check"; + public const string FLG_PATH_WEBSOCKET_PREFIX = "ws"; + public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY"; + public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache"; + public const string FLG_SNOWFLAKE_WORK_ID = "SNOWFLAKE_WORK_ID"; + public const string FLG_SYSTEM_PREFIX = "sc_"; public const string FLGL_HTTP_HEADER_VALUE_UA_MOBILE = "Mozilla/5.0 (Linux; Android 9; Redmi Note 8 Pro Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.96 Mobile Safari/537.36"; diff --git a/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs b/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs index 23e435f9..683cc660 100644 --- a/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs +++ b/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs @@ -7,12 +7,19 @@ namespace NetAdmin.Infrastructure; /// public static class GlobalStatic { + /// + /// 当前进程 + /// + public static readonly Process CurrentProcess = Process.GetCurrentProcess(); + /// /// 产品版本 /// public static readonly string ProductVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion; + private static long _latestLogTime; + /// /// 调试模式 /// @@ -24,10 +31,17 @@ public static class GlobalStatic #endif ; + /// + /// 最后一次日志时间 + /// + public static DateTime LatestLogTime => Volatile.Read(ref _latestLogTime).Time(); + /// /// 日志记录器忽略的API编号 /// - public static string[] LoggerIgnoreApiIds => []; + public static string[] LoggerIgnoreApiIds => [ + "api/adm/tools/query.es.log", "api/probe/health.check", "api/probe/is.system.safety.stopped" + ]; /// /// 系统内部密钥 @@ -73,4 +87,12 @@ public static class GlobalStatic /// Json序列化选项 /// public static JsonSerializerOptions JsonSerializerOptions { get; set; } + + /// + /// 增加日志计数器 + /// + public static void IncrementLogCounter() + { + Volatile.Write(ref _latestLogTime, DateTime.Now.TimeUnixUtcMs()); + } } \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj index 7f1a5486..34d5cec4 100644 --- a/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj +++ b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj @@ -6,13 +6,13 @@ - - + + - + diff --git a/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs index edc4f65c..285d2d2e 100644 --- a/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs +++ b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs @@ -18,7 +18,6 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions) .UseAutoSyncStructure( initMethods.HasFlag(FreeSqlInitMethods.SyncStructure)) .Build(); - _ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步 return freeSql; } diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs index 642d072d..a481003d 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs @@ -1,3 +1,4 @@ +using NetAdmin.Domain.Dto.Dependency; using NetAdmin.Domain.Dto.Sys.Cache; namespace NetAdmin.SysComponent.Application.Modules.Sys; @@ -7,11 +8,21 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys; /// public interface ICacheModule { + /// + /// 批量删除缓存项 + /// + Task BulkDeleteEntryAsync(BulkReq req); + /// /// 缓存统计 /// Task CacheStatisticsAsync(); + /// + /// 删除缓存项 + /// + Task DeleteEntryAsync(DelEntryReq req); + /// /// 获取所有缓存项 /// diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs index 38628e34..5e098d34 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs @@ -7,6 +7,11 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys; /// public interface IToolsModule { + /// + /// 执行SQL语句 + /// + Task ExecuteSqlAsync(ExecuteSqlReq req); + /// /// 获取更新日志 /// diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs index 7783f24b..f8352a1c 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Dependency; using NetAdmin.Domain.Dto.Sys.Cache; using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using StackExchange.Redis; @@ -21,6 +22,20 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) / _redisInstance = redisOptions.Value.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE); } + /// + public async Task BulkDeleteEntryAsync(BulkReq req) + { + req.ThrowIfInvalid(); + var ret = 0; + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var item in req.Items) { + ret += await DeleteEntryAsync(item).ConfigureAwait(false); + } + + return ret; + } + /// public async Task CacheStatisticsAsync() { @@ -30,6 +45,16 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) / }; } + /// + public async Task DeleteEntryAsync(DelEntryReq req) + { + req.ThrowIfInvalid(); + #pragma warning disable VSTHRD103 + var database = connectionMultiplexer.GetDatabase(_redisInstance.Database); + var delSuccess = await database.KeyDeleteAsync(req.Key).ConfigureAwait(false); + return delSuccess ? 1 : 0; + } + /// public async Task> GetAllEntriesAsync(GetAllEntriesReq req) { diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs index bbd2afc3..3e102f58 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs @@ -84,7 +84,9 @@ public sealed class ConfigService(BasicRepository rpo) // public async Task GetAsync(QueryConfigReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync().ConfigureAwait(false); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs index d34b80f6..f9d4012a 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs @@ -102,7 +102,9 @@ public sealed class DeptService(BasicRepository rpo) // public async Task GetAsync(QueryDeptReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync().ConfigureAwait(false); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs index 19a35e4e..1893e223 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs @@ -89,7 +89,7 @@ public sealed class DicCatalogService(BasicRepository rpo) public async Task GetAsync(QueryDicCatalogReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs index 9b811636..bc982014 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs @@ -104,7 +104,7 @@ public sealed class DicContentService(BasicRepository rpo) public async Task GetAsync(QueryDicContentReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); @@ -145,6 +145,9 @@ public sealed class DicContentService(BasicRepository rpo) public async Task> QueryByCatalogCodeAsync(string catalogCode) { var ret = await Rpo.Orm.Select() + #if DBTYPE_SQLSERVER + .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #endif .Include(a => a.Catalog) .Where(a => a.Catalog.Code == catalogCode) .ToListAsync() diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs index f374a91c..38aba223 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs @@ -73,7 +73,7 @@ public sealed class JobRecordService(BasicRepository rpo) / public async Task GetAsync(QueryJobRecordReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs index bc0b716f..3ba9bd81 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs @@ -112,9 +112,11 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer } ] }; - var job = await QueryInternal(new QueryReq { Count = 1, Filter = req, DynamicFilter = df }) - .ToOneAsync() - .ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.未获取到待执行任务); + var job + = await QueryInternal( + new QueryReq { Count = 1, Filter = req, DynamicFilter = df, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.未获取到待执行任务); var nextExecTime = GetNextExecTime(Chars.FLG_CRON_PER_SECS); try { @@ -175,7 +177,9 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer public async Task GetAsync(QueryJobReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync().ConfigureAwait(false); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } @@ -201,13 +205,26 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer } ] }; - var job = await QueryInternal(new QueryReq { DynamicFilter = df, Order = Orders.Random }) - .Take(1) + var job = await QueryInternal(new QueryReq { DynamicFilter = df, Order = Orders.Random }, false) + #if DBTYPE_SQLSERVER + .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #endif .Where(a => !Rpo.Orm.Select() .As("b") .Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId) .Any()) - .ToOneAsync() + .ToOneAsync(a => new { + a.RequestUrl + , a.HttpMethod + , a.RequestHeader + , a.RequestBody + , a.RandomDelayBegin + , a.RandomDelayEnd + , a.UserId + , a.Id + , a.NextTimeId + , a.Version + }) .ConfigureAwait(false); if (job == null) { return null; @@ -215,15 +232,15 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer #if DBTYPE_SQLSERVER var ret = await UpdateReturnListAsync( // - job with { Status = JobStatues.Running, LastExecTime = DateTime.Now } - , [nameof(job.Status), nameof(job.LastExecTime)]) + job.Adapt() with { Status = JobStatues.Running, LastExecTime = DateTime.Now } + , [nameof(Sys_Job.Status), nameof(Sys_Job.LastExecTime)]) .ConfigureAwait(false); return ret.FirstOrDefault()?.Adapt(); #else return await UpdateAsync( // - job with { Status = JobStatues.Running, LastExecTime = DateTime.Now } - , [nameof(job.Status), nameof(job.LastExecTime)]) + job.Adapt() with { Status = JobStatues.Running, LastExecTime = DateTime.Now } + , [nameof(Sys_Job.Status), nameof(Sys_Job.LastExecTime)]) .ConfigureAwait(false) > 0 ? await GetAsync(new QueryJobReq { Id = job.Id }).ConfigureAwait(false) : null; @@ -330,12 +347,21 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer private ISelect QueryInternal(QueryReq req) { - var ret = Rpo.Select.Include(a => a.User) - .WhereDynamicFilter(req.DynamicFilter) - .WhereDynamic(req.Filter) - .WhereIf( // - req.Keywords?.Length > 0 - , a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords)); + return QueryInternal(req, true); + } + + private ISelect QueryInternal(QueryReq req, bool includeUser) + { + var ret = Rpo.Select; + if (includeUser) { + ret = ret.Include(a => a.User); + } + + ret = ret.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .WhereIf( // + req.Keywords?.Length > 0 + , a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords)); // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault switch (req.Order) { diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/LoginLogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/LoginLogService.cs index ad9d13c7..d09230d7 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/LoginLogService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/LoginLogService.cs @@ -72,7 +72,7 @@ public sealed class LoginLogService(BasicRepository rpo) // public async Task GetAsync(QueryLoginLogReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs index 6756791a..e1e3aaf8 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs @@ -88,7 +88,9 @@ public sealed class MenuService(BasicRepository rpo, IUserServic public async Task GetAsync(QueryMenuReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync().ConfigureAwait(false); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs index 30382365..53d15166 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs @@ -71,7 +71,7 @@ public sealed class RequestLogDetailService(BasicRepository GetAsync(QueryRequestLogDetailReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs index 416a5b0c..16e9e1fd 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs @@ -99,7 +99,8 @@ public sealed class RequestLogService(BasicRepository rpo, }.Json() .Object() }; - var ret = await QueryInternal(new QueryReq { Filter = req, DynamicFilter = df }) + var ret = await QueryInternal( + new QueryReq { Filter = req, DynamicFilter = df, Order = Orders.None }) .Include(a => a.Detail) .ToOneAsync() .ConfigureAwait(false); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs index 9e62cc66..f0eb4299 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs @@ -96,7 +96,9 @@ public sealed class RoleService(BasicRepository rpo) // public async Task GetAsync(QueryRoleReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync().ConfigureAwait(false); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) + .ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs index 608fb4c6..1ef66e7e 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs @@ -71,7 +71,7 @@ public sealed class SiteMsgDeptService(BasicRepository rp public async Task GetAsync(QuerySiteMsgDeptReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs index 8ec8c46a..d5f19b91 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs @@ -71,7 +71,7 @@ public sealed class SiteMsgFlagService(BasicRepository rp public async Task GetAsync(QuerySiteMsgFlagReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs index 7b3fc382..37c99240 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs @@ -71,7 +71,7 @@ public sealed class SiteMsgRoleService(BasicRepository rp public async Task GetAsync(QuerySiteMsgRoleReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs index ab75dac6..c2049ed5 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs @@ -120,7 +120,7 @@ public sealed class SiteMsgService( public async Task GetAsync(QuerySiteMsgReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .IncludeMany(a => a.Roles) .IncludeMany(a => a.Users) .IncludeMany(a => a.Depts) diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs index 52344dfa..c5876893 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs @@ -71,7 +71,7 @@ public sealed class SiteMsgUserService(BasicRepository rp public async Task GetAsync(QuerySiteMsgUserReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs index 413a45f4..97a6b75e 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs @@ -7,6 +7,15 @@ namespace NetAdmin.SysComponent.Application.Services.Sys; /// public sealed class ToolsService : ServiceBase, IToolsService { + /// + public Task ExecuteSqlAsync(ExecuteSqlReq req) + { + return App.GetService() + .Ado.CommandFluent(req.Sql) + .CommandTimeout(req.TimeoutSecs) + .ExecuteArrayAsync(); + } + /// public async Task GetChangeLogAsync() { diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs index fa33da8e..ac3dfd82 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs @@ -100,7 +100,7 @@ public sealed class UserProfileService(BasicRepository rp public async Task GetAsync(QueryUserProfileReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs index 96e1e6c6..cb9e2761 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs @@ -172,9 +172,9 @@ public sealed class UserService( public async Task GetAsync(QueryUserReq req) { req.ThrowIfInvalid(); - var ret = await (await QueryInternalAsync(new QueryReq { Filter = req }).ConfigureAwait(false)) - .ToOneAsync() - .ConfigureAwait(false); + var ret = await (await QueryInternalAsync(new QueryReq { Filter = req, Order = Orders.None }) + .ConfigureAwait(false)).ToOneAsync() + .ConfigureAwait(false); return ret.Adapt(); } @@ -433,14 +433,51 @@ public sealed class UserService( /// public async Task UserInfoAsync() { + static void OtherIncludes(ISelect select) + { + select.Where(a => a.Enabled) + #if DBTYPE_SQLSERVER + .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #endif + .IncludeMany( // + a => a.Menus + #if DBTYPE_SQLSERVER + #pragma warning disable SA1115 + , then => then.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #pragma warning restore SA1115 + #endif + #pragma warning disable SA1009, SA1111 + ) + #pragma warning restore SA1111, SA1009 + .IncludeMany( // + a => a.Depts + #if DBTYPE_SQLSERVER + #pragma warning disable SA1115 + , then => then.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #pragma warning restore SA1115 + #endif + #pragma warning disable SA1009, SA1111 + ) + #pragma warning restore SA1111, SA1009 + .IncludeMany( // + a => a.Apis + #if DBTYPE_SQLSERVER + #pragma warning disable SA1115 + , then => then.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #pragma warning restore SA1115 + #endif + #pragma warning disable SA1009, SA1111 + ) + #pragma warning restore SA1111, SA1009 + ; + } + var dbUser = await Rpo.Where(a => a.Token == UserToken.Token && a.Enabled) + #if DBTYPE_SQLSERVER + .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) + #endif .Include(a => a.Dept) - .IncludeMany( // - a => a.Roles - , then => then.Where(a => a.Enabled) - .IncludeMany(a => a.Menus) - .IncludeMany(a => a.Depts) - .IncludeMany(a => a.Apis)) + .IncludeMany(a => a.Roles, OtherIncludes) .ToOneAsync() .ConfigureAwait(false); return dbUser.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs index 44c41fb4..d3126aac 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs @@ -81,7 +81,7 @@ public sealed class VerifyCodeService(BasicRepository rpo, public async Task GetAsync(QueryVerifyCodeReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); @@ -188,11 +188,10 @@ public sealed class VerifyCodeService(BasicRepository rpo, , Value = destDevice } }) - #if DBTYPE_SQLSERVER + #if DBTYPE_SQLSERVER .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) - #endif - .Take(1) - .ToOneAsync(); + #endif + .ToOneAsync(); } private ISelect QueryInternal(QueryReq req) diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs index 6621c27a..d3ee011e 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs @@ -73,7 +73,7 @@ public sealed class ExampleService(BasicRepository rpo) // public async Task GetAsync(QueryExampleReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req }) + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }) .ToOneAsync() .ConfigureAwait(false); return ret.Adapt(); diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs index 5047cfce..b8781d05 100644 --- a/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs @@ -1,4 +1,5 @@ using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; using NetAdmin.Domain.Dto.Sys.Cache; using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Cache.Sys.Dependency; @@ -9,6 +10,12 @@ namespace NetAdmin.SysComponent.Cache.Sys; public sealed class CacheCache(IDistributedCache cache, ICacheService service) // : DistributedCache(cache, service), IScoped, ICacheCache { + /// + public Task BulkDeleteEntryAsync(BulkReq req) + { + return Service.BulkDeleteEntryAsync(req); + } + /// public Task CacheStatisticsAsync() { @@ -20,6 +27,12 @@ public sealed class CacheCache(IDistributedCache cache, ICacheService service) / #endif } + /// + public Task DeleteEntryAsync(DelEntryReq req) + { + return Service.DeleteEntryAsync(req); + } + /// public Task> GetAllEntriesAsync(GetAllEntriesReq req) { diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs index bb329056..5c725096 100644 --- a/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs @@ -9,6 +9,12 @@ namespace NetAdmin.SysComponent.Cache.Sys; public sealed class ToolsCache(IDistributedCache cache, IToolsService service) // : DistributedCache(cache, service), IScoped, IToolsCache { + /// + public Task ExecuteSqlAsync(ExecuteSqlReq req) + { + return Service.ExecuteSqlAsync(req); + } + /// public Task GetChangeLogAsync() { diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs index dc65a052..d6860522 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs @@ -1,3 +1,4 @@ +using NetAdmin.Domain.Dto.Dependency; using NetAdmin.Domain.Dto.Sys.Cache; using NetAdmin.Host.Controllers; using NetAdmin.SysComponent.Application.Modules.Sys; @@ -12,6 +13,14 @@ namespace NetAdmin.SysComponent.Host.Controllers.Sys; [ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] public sealed class CacheController(ICacheCache cache) : ControllerBase(cache), ICacheModule { + /// + /// 批量删除缓存项 + /// + public Task BulkDeleteEntryAsync(BulkReq req) + { + return Cache.BulkDeleteEntryAsync(req); + } + /// /// 缓存统计 /// @@ -20,6 +29,14 @@ public sealed class CacheController(ICacheCache cache) : ControllerBase + /// 删除缓存项 + /// + public Task DeleteEntryAsync(DelEntryReq req) + { + return Cache.DeleteEntryAsync(req); + } + /// /// 获取所有缓存项 /// diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs index 9a6e83ab..41a68ce2 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs @@ -12,6 +12,14 @@ namespace NetAdmin.SysComponent.Host.Controllers.Sys; [ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] public sealed class ToolsController(IToolsCache cache) : ControllerBase(cache), IToolsModule { + /// + /// 执行SQL语句 + /// + public Task ExecuteSqlAsync(ExecuteSqlReq req) + { + return Cache.ExecuteSqlAsync(req); + } + /// /// 获取更新日志 /// diff --git a/src/backend/NetAdmin.SysComponent.Host/Jobs/FreeScheduledJob.cs b/src/backend/NetAdmin.SysComponent.Host/Jobs/FreeScheduledJob.cs index 851a8db3..fce347b5 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Jobs/FreeScheduledJob.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Jobs/FreeScheduledJob.cs @@ -1,5 +1,6 @@ using Furion.Schedule; using NetAdmin.Host.BackgroundRunning; +using NetAdmin.Host.Middlewares; using NetAdmin.SysComponent.Application.Services.Sys.Dependency; namespace NetAdmin.SysComponent.Host.Jobs; @@ -27,6 +28,11 @@ public sealed class FreeScheduledJob : WorkBase, IJob /// 加锁失败异常 public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) { + if (SafetyShopHostMiddleware.IsShutdown) { + Console.WriteLine(Ln.此节点已下线); + return; + } + await WorkflowAsync(true, stoppingToken).ConfigureAwait(false); } diff --git a/src/backend/NetAdmin.SysComponent.Host/Jobs/ScheduledJob.cs b/src/backend/NetAdmin.SysComponent.Host/Jobs/ScheduledJob.cs index af65abc5..30a436a6 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Jobs/ScheduledJob.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Jobs/ScheduledJob.cs @@ -6,6 +6,7 @@ using NetAdmin.Domain.Dto.Sys.Job; using NetAdmin.Domain.Dto.Sys.JobRecord; using NetAdmin.Host.BackgroundRunning; using NetAdmin.Host.Extensions; +using NetAdmin.Host.Middlewares; using NetAdmin.SysComponent.Application.Services.Sys.Dependency; namespace NetAdmin.SysComponent.Host.Jobs; @@ -42,6 +43,11 @@ public sealed class ScheduledJob : WorkBase, IJob /// 加锁失败异常 public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) { + if (SafetyShopHostMiddleware.IsShutdown) { + Console.WriteLine(Ln.此节点已下线); + return; + } + await WorkflowAsync(stoppingToken).ConfigureAwait(false); } diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs index f17ec166..b14cfa25 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs @@ -1,5 +1,11 @@ -using NetAdmin.Domain.Events.Sys; +#if !DEBUG +using System.Collections.Concurrent; +using NetAdmin.Domain.Dto.Sys.RequestLog; + +#else using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +#endif +using NetAdmin.Domain.Events.Sys; namespace NetAdmin.SysComponent.Host.Subscribers; @@ -8,6 +14,10 @@ namespace NetAdmin.SysComponent.Host.Subscribers; /// public sealed class OperationLogger : IEventSubscriber { + #if !DEBUG + private static readonly ConcurrentQueue _requestLogs = new(); + #endif + /// /// 保存请求日志到数据库 /// @@ -18,7 +28,47 @@ public sealed class OperationLogger : IEventSubscriber return; } - operationEvent.Data.TruncateStrings(); + #if DEBUG _ = await App.GetService().CreateAsync(operationEvent.Data).ConfigureAwait(false); + #else + if (_requestLogs.Count > Numbers.REQUEST_LOG_BUFF_SIZE) { + await WriteToDbAsync().ConfigureAwait(false); + } + else { + _requestLogs.Enqueue(operationEvent.Data); + } + #endif } + + #if !DEBUG + private static async Task WriteToDbAsync() + { + var inserts = new List(Numbers.REQUEST_LOG_BUFF_SIZE); + + // 批量入库 + for (var i = 0; i != Numbers.REQUEST_LOG_BUFF_SIZE; ++i) { + if (!_requestLogs.TryDequeue(out var log)) { + continue; + } + + inserts.Add(log); + } + + // 如果首尾日期不一致,要分别插入不同的日期分表 + if (inserts[0].CreatedTime.Date != inserts[^1].CreatedTime.Date) { + foreach (var dayInserts in inserts.GroupBy(x => x.CreatedTime.Date)) { + await App.GetService() + .Insert(dayInserts.Select(x => x)) + .ExecuteSqlBulkCopyAsync(tableName: $"{nameof(Sys_RequestLog)}_{dayInserts.Key:yyyyMMdd}") + .ConfigureAwait(false); + } + } + else { + await App.GetService() + .Insert(inserts) + .ExecuteSqlBulkCopyAsync(tableName: $"{nameof(Sys_RequestLog)}_{inserts[0].CreatedTime:yyyyMMdd}") + .ConfigureAwait(false); + } + } + #endif } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/NetAdmin.SysComponent.Tests.csproj b/src/backend/NetAdmin.SysComponent.Tests/NetAdmin.SysComponent.Tests.csproj new file mode 100644 index 00000000..57479c69 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/NetAdmin.SysComponent.Tests.csproj @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/ApiTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/ApiTests.cs new file mode 100644 index 00000000..04eb4f4c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/ApiTests.cs @@ -0,0 +1,118 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 接口测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class ApiTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IApiModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateApiReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryApiReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task SyncAsync() + { + var rsp = await PostJsonAsync(typeof(DeptController)); + Assert.True(rsp.IsSuccessStatusCode); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/CacheTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/CacheTests.cs new file mode 100644 index 00000000..33353809 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/CacheTests.cs @@ -0,0 +1,69 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 缓存测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class CacheTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), ICacheModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteEntryAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(CacheController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task CacheStatisticsAsync() + { + var rsp = await PostJsonAsync(typeof(CacheController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteEntryAsync(DelEntryReq req) + { + var rsp = await PostJsonAsync(typeof(CacheController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetAllEntriesAsync(GetAllEntriesReq req) + { + var rsp = await PostJsonAsync(typeof(CacheController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetEntryAsync(GetEntriesReq req) + { + var rsp = await PostJsonAsync(typeof(CacheController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/CaptchaTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/CaptchaTests.cs new file mode 100644 index 00000000..20887fc1 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/CaptchaTests.cs @@ -0,0 +1,38 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 人机验证测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class CaptchaTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), ICaptchaModule +{ + /// + [Fact] + public async Task GetCaptchaImageAsync() + { + var rsp = await PostJsonAsync(typeof(CaptchaController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task VerifyCaptchaAsync(VerifyCaptchaReq req) + { + var rsp = await PostJsonAsync(typeof(CaptchaController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/ConfigTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/ConfigTests.cs new file mode 100644 index 00000000..36bb3a2e --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/ConfigTests.cs @@ -0,0 +1,139 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Config; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 配置测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class ConfigTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IConfigModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateConfigReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditConfigReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryConfigReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task GetLatestConfigAsync() + { + var rsp = await PostJsonAsync(typeof(ConfigController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetEnabledAsync(SetConfigEnabledReq req) + { + var rsp = await PostJsonAsync(typeof(ConfigController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/ConstantTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/ConstantTests.cs new file mode 100644 index 00000000..62cb259e --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/ConstantTests.cs @@ -0,0 +1,55 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 常量测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +[SuppressMessage("Usage", "xUnit1031:Do not use blocking task operations in test method")] +public class ConstantTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IConstantModule +{ + /// + [Fact] + public IDictionary GetCharsDic() + { + var rsp = PostJsonAsync(typeof(ConstantController)).GetAwaiter().GetResult(); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public IDictionary> GetEnums() + { + var rsp = PostJsonAsync(typeof(ConstantController)).GetAwaiter().GetResult(); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public IDictionary GetLocalizedStrings() + { + var rsp = PostJsonAsync(typeof(ConstantController)).GetAwaiter().GetResult(); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public IDictionary GetNumbersDic() + { + var rsp = PostJsonAsync(typeof(ConstantController)).GetAwaiter().GetResult(); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/DeptTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/DeptTests.cs new file mode 100644 index 00000000..30b87cdb --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/DeptTests.cs @@ -0,0 +1,130 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 部门测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class DeptTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IDeptModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateDeptReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditDeptReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryDeptReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetEnabledAsync(SetDeptEnabledReq req) + { + var rsp = await PostJsonAsync(typeof(DeptController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/DevTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/DevTests.cs new file mode 100644 index 00000000..db4749aa --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/DevTests.cs @@ -0,0 +1,45 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Sys.Dev; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 开发测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class DevTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IDevModule +{ + /// + [InlineData(default)] + [Theory] + public async Task GenerateCsCodeAsync(GenerateCsCodeReq req) + { + var rsp = await PostJsonAsync(typeof(DevController), req); + Assert.True(rsp.IsSuccessStatusCode); + } + + /// + [InlineData(default)] + [Theory] + public async Task GenerateIconCodeAsync(GenerateIconCodeReq req) + { + var rsp = await PostJsonAsync(typeof(DevController), req); + Assert.True(rsp.IsSuccessStatusCode); + } + + /// + [Fact] + public async Task GenerateJsCodeAsync() + { + var rsp = await PostJsonAsync(typeof(DevController)); + Assert.True(rsp.IsSuccessStatusCode); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/DicTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/DicTests.cs new file mode 100644 index 00000000..e00e844f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/DicTests.cs @@ -0,0 +1,181 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 字典测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class DicTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IDicModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteCatalogAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteContentAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateCatalogAsync(CreateDicCatalogReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateContentAsync(CreateDicContentReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteCatalogAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteContentAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditCatalogAsync(EditDicCatalogReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditContentAsync(EditDicContentReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportContentAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetCatalogAsync(QueryDicCatalogReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetContentAsync(QueryDicContentReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetDicValueAsync(GetDicValueReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryCatalogAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryContentAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryCatalogAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryContentAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(DicController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/FileTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/FileTests.cs new file mode 100644 index 00000000..58cab6ba --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/FileTests.cs @@ -0,0 +1,28 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 文件测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class FileTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IFileModule +{ + /// + [InlineData(default)] + [Theory] + public async Task UploadAsync(IFormFile file) + { + var rsp = await PostJsonAsync(typeof(FileController), file); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/JobTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/JobTests.cs new file mode 100644 index 00000000..0d2e55fe --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/JobTests.cs @@ -0,0 +1,212 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys; +using NetAdmin.Domain.Dto.Sys.Job; +using NetAdmin.Domain.Dto.Sys.JobRecord; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 计划作业测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class JobTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IJobModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountRecordAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateJobReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditJobReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExecuteAsync(QueryJobReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportRecordAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryJobReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetRecordAsync(QueryJobRecordReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetRecordBarChartAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetRecordPieChartByHttpStatusCodeAsync( + QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetRecordPieChartByNameAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryRecordAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetEnabledAsync(SetJobEnabledReq req) + { + var rsp = await PostJsonAsync(typeof(JobController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/LoginLogTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/LoginLogTests.cs new file mode 100644 index 00000000..4f04d9ec --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/LoginLogTests.cs @@ -0,0 +1,110 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.LoginLog; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 登录日志测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class LoginLogTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), ILoginLogModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateLoginLogReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryLoginLogReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(LoginLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/MenuTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/MenuTests.cs new file mode 100644 index 00000000..4565a10a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/MenuTests.cs @@ -0,0 +1,128 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Menu; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 菜单测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class MenuTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IMenuModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateMenuReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditMenuReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryMenuReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(MenuTests), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task> UserMenusAsync() + { + var rsp = await PostJsonAsync(typeof(MenuTests)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/RequestLogTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/RequestLogTests.cs new file mode 100644 index 00000000..9d594281 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/RequestLogTests.cs @@ -0,0 +1,141 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys; +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 请求日志测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class RequestLogTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IRequestLogModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateRequestLogReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryRequestLogReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetBarChartAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetPieChartByApiSummaryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> GetPieChartByHttpStatusCodeAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RequestLogController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/RoleTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/RoleTests.cs new file mode 100644 index 00000000..fe90de9d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/RoleTests.cs @@ -0,0 +1,150 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 角色测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class RoleTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IRoleModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateRoleReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditRoleReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryRoleReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetDisplayDashboardAsync(SetDisplayDashboardReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetEnabledAsync(SetRoleEnabledReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetIgnorePermissionControlAsync(SetIgnorePermissionControlReq req) + { + var rsp = await PostJsonAsync(typeof(RoleController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/SiteMsgTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/SiteMsgTests.cs new file mode 100644 index 00000000..d50ff331 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/SiteMsgTests.cs @@ -0,0 +1,159 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.SiteMsg; +using NetAdmin.Domain.Dto.Sys.SiteMsgFlag; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 站内信测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class SiteMsgTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), ISiteMsgModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateSiteMsgReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task EditAsync(EditSiteMsgReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QuerySiteMsgReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetMineAsync(QuerySiteMsgReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryMineAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SetSiteMsgStatusAsync(SetUserSiteMsgStatusReq req) + { + var rsp = await PostJsonAsync(typeof(SiteMsgController), req); + Assert.True(rsp.IsSuccessStatusCode); + } + + /// + [Fact] + public async Task UnreadCountAsync() + { + var rsp = await PostJsonAsync(typeof(SiteMsgController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/ToolsTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/ToolsTests.cs new file mode 100644 index 00000000..12b03c9d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/ToolsTests.cs @@ -0,0 +1,65 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Sys.Tool; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 工具测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class ToolsTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IToolsModule +{ + /// + [InlineData(default)] + [Theory] + public async Task ExecuteSqlAsync(ExecuteSqlReq req) + { + var rsp = await PostJsonAsync(typeof(ToolsController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task GetChangeLogAsync() + { + var rsp = await PostJsonAsync(typeof(ToolsController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task> GetModulesAsync() + { + var rsp = await PostJsonAsync(typeof(ToolsController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task GetServerUtcTimeAsync() + { + var rsp = await PostJsonAsync(typeof(ToolsController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + public async Task GetVersionAsync() + { + var rsp = await PostJsonAsync(typeof(ToolsController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/UserTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/UserTests.cs new file mode 100644 index 00000000..8e33e788 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/UserTests.cs @@ -0,0 +1,309 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using NetAdmin.Tests.Attributes; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 用户测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +[TestCaseOrderer("NetAdmin.Tests.PriorityOrderer", "NetAdmin.Tests")] +public class UserTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IUserModule +{ + /// + [InlineData(default)] + [Theory] + [TestPriority(100100)] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.Equal(HttpStatusCode.NotFound, rsp.StatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100200)] + public async Task CheckMobileAvailableAsync(CheckMobileAvailableReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), new CheckMobileAvailableReq { Mobile = "13838381438" }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100300)] + public async Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), new CheckUserNameAvailableReq { UserName = "test" }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100400)] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100000)] + public async Task CreateAsync(CreateUserReq req) + { + var rsp = await PostJsonAsync(typeof(UserController) + , new CreateUserReq { + UserName = "test" + , PasswordText = "1234qwer" + , RoleIds = [371729946431493] + , DeptId = 372119301627909 + }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100600)] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100700)] + public async Task EditAsync(EditUserReq req) + { + var rsp = await PostJsonAsync(typeof(UserController) + , new EditUserReq { + UserName = "test" + , RoleIds = [371729946431493] + , DeptId = 372119301627909 + }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100800)] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), new QueryReq()); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(100900)] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101000)] + public async Task GetAsync(QueryUserReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + [TestPriority(101100)] + public async Task GetSessionUserAppConfigAsync() + { + var rsp = await PostJsonAsync(typeof(UserController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101200)] + public async Task LoginByPwdAsync(LoginByPwdReq req) + { + var rsp = await PostJsonAsync(typeof(UserController) + , new LoginByPwdReq { Account = "root", Password = "1234qwer" }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101300)] + public async Task LoginBySmsAsync(LoginBySmsReq req) + { + var rsp = await PostJsonAsync(typeof(UserController) + , new LoginBySmsReq { Code = "1234", DestDevice = "13838381438" }); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101400)] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101500)] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101600)] + public async Task> QueryProfileAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101700)] + public async Task RegisterAsync(RegisterUserReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101800)] + public async Task ResetPasswordAsync(ResetPasswordReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(101900)] + public async Task SetAvatarAsync(SetAvatarReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(102000)] + public async Task SetEmailAsync(SetEmailReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(102100)] + public async Task SetEnabledAsync(SetUserEnabledReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(102200)] + public async Task SetMobileAsync(SetMobileReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(102300)] + public async Task SetPasswordAsync(SetPasswordReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + [TestPriority(102400)] + public async Task SetSessionUserAppConfigAsync(SetSessionUserAppConfigReq req) + { + var rsp = await PostJsonAsync(typeof(UserController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [Fact] + [TestPriority(102500)] + public async Task UserInfoAsync() + { + var rsp = await PostJsonAsync(typeof(UserController)); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Tests/Sys/VerifyCodeTests.cs b/src/backend/NetAdmin.SysComponent.Tests/Sys/VerifyCodeTests.cs new file mode 100644 index 00000000..d98a0369 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Tests/Sys/VerifyCodeTests.cs @@ -0,0 +1,130 @@ +using System.Diagnostics.CodeAnalysis; +using NetAdmin.AdmServer.Host; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Host.Controllers.Sys; +using NetAdmin.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace NetAdmin.SysComponent.Tests.Sys; + +/// +/// 验证码测试 +/// +[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] +[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] +public class VerifyCodeTests(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : WebApiTestBase(factory, testOutputHelper), IVerifyCodeModule +{ + /// + [InlineData(default)] + [Theory] + public async Task BulkDeleteAsync(BulkReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CountAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task CreateAsync(CreateVerifyCodeReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task DeleteAsync(DelReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExistAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task ExportAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task GetAsync(QueryVerifyCodeReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task> QueryAsync(QueryReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task SendVerifyCodeAsync(SendVerifyCodeReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } + + /// + [InlineData(default)] + [Theory] + public async Task VerifyAsync(VerifyCodeReq req) + { + var rsp = await PostJsonAsync(typeof(VerifyCodeController), req); + Assert.True(rsp.IsSuccessStatusCode); + return default; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Tests/Attributes/TestPriorityAttribute.cs b/src/backend/NetAdmin.Tests/Attributes/TestPriorityAttribute.cs new file mode 100644 index 00000000..cd28231d --- /dev/null +++ b/src/backend/NetAdmin.Tests/Attributes/TestPriorityAttribute.cs @@ -0,0 +1,13 @@ +namespace NetAdmin.Tests.Attributes; + +/// +/// 测试用例优先级 +/// +[AttributeUsage(AttributeTargets.Method)] +public class TestPriorityAttribute(int priority) : Attribute +{ + /// + /// 优先级 + /// + public int Priority { get; private set; } = priority; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Tests/NetAdmin.Tests.csproj b/src/backend/NetAdmin.Tests/NetAdmin.Tests.csproj index cadded48..61125458 100644 --- a/src/backend/NetAdmin.Tests/NetAdmin.Tests.csproj +++ b/src/backend/NetAdmin.Tests/NetAdmin.Tests.csproj @@ -3,8 +3,8 @@ + - runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/backend/NetAdmin.Tests/PriorityOrderer.cs b/src/backend/NetAdmin.Tests/PriorityOrderer.cs new file mode 100644 index 00000000..940e988c --- /dev/null +++ b/src/backend/NetAdmin.Tests/PriorityOrderer.cs @@ -0,0 +1,52 @@ +using NetAdmin.Tests.Attributes; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace NetAdmin.Tests; + +/// +/// 优先级排序 +/// +public class PriorityOrderer : ITestCaseOrderer +{ + /// + /// 排序测试用例 + /// + public IEnumerable OrderTestCases(IEnumerable testCases) + where TTestCase : ITestCase + { + var sortedMethods = new SortedDictionary>(); + + foreach (var testCase in testCases) { + var priority = 0; + + foreach (var attr in testCase.TestMethod.Method.GetCustomAttributes( + typeof(TestPriorityAttribute).AssemblyQualifiedName)) { + priority = attr.GetNamedArgument("Priority"); + } + + GetOrCreate(sortedMethods, priority).Add(testCase); + } + + foreach (var list in sortedMethods.Keys.Select(priority => sortedMethods[priority])) { + list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare( + x.TestMethod.Method.Name, y.TestMethod.Method.Name)); + foreach (var testCase in list) { + yield return testCase; + } + } + } + + private static TValue GetOrCreate(SortedDictionary dictionary, TKey key) + where TValue : new() + { + if (dictionary.TryGetValue(key, out var result)) { + return result; + } + + result = new TValue(); + dictionary[key] = result; + + return result; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Tests/WebApiTestBase.cs b/src/backend/NetAdmin.Tests/WebApiTestBase.cs index 09e6edc0..6aa1f00d 100644 --- a/src/backend/NetAdmin.Tests/WebApiTestBase.cs +++ b/src/backend/NetAdmin.Tests/WebApiTestBase.cs @@ -1,8 +1,9 @@ using System.Net.Http.Headers; using System.Net.Http.Json; -using Microsoft.AspNetCore.Mvc.Testing; +using System.Runtime.CompilerServices; using NetAdmin.Domain.Dto; using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Host.Extensions; using Xunit; using Xunit.Abstractions; @@ -11,34 +12,68 @@ namespace NetAdmin.Tests; /// /// WebApi 测试用例基类 /// -public abstract class WebApiTestBase(WebApplicationFactory factory, ITestOutputHelper testOutputHelper) - : IClassFixture> +public abstract class WebApiTestBase(WebTestApplicationFactory factory, ITestOutputHelper testOutputHelper) + : IClassFixture> where T : AppStartup { - private const string _ACCOUNT = "root"; - private const string _PASSWORD = "1234qwer"; - private string _accessToken; + // ReSharper disable once StaticMemberInGenericType + private static string _accessToken; /// /// Post请求 /// - protected async Task PostAsync(string url, HttpContent content) + protected async Task PostAsync(Type type, HttpContent content + , [CallerMemberName] string memberName = null) { var client = factory.CreateClient(); + await Authorization(client); + + var ret = await client.PostAsync(type.GetMethod(memberName!).GetRoutePath(factory.Services), content) + .ConfigureAwait(false); + testOutputHelper.WriteLine(await ret.Content.ReadAsStringAsync().ConfigureAwait(false)); + return ret; + } + + /// + /// Post请求 + /// + protected async Task PostJsonAsync(Type type, TRequest req = default + , [CallerMemberName] string memberName = null) + { + return await PostAsync(type, req == null ? JsonContent.Create(new { }) : JsonContent.Create(req), memberName); + } + + /// + /// Post请求 + /// + protected async Task PostJsonAsync(Type type, [CallerMemberName] string memberName = null) + { + return await PostJsonAsync(type, null, memberName); + } + + private static async Task Authorization(HttpClient client) + { if (_accessToken == null) { - var loginRsp = await client.PostAsync(Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD - , JsonContent.Create( - new LoginByPwdReq { Password = _PASSWORD, Account = _ACCOUNT })) - .ConfigureAwait(false); - var loginRspObj = (await loginRsp.Content.ReadAsStringAsync().ConfigureAwait(false)) + var req = new LoginByPwdReq // + { + Password + = Environment.GetEnvironmentVariable( + nameof(WebTestApplicationFactory.TEST_PASSWORD)) ?? + WebTestApplicationFactory.TEST_PASSWORD + , Account + = Environment.GetEnvironmentVariable(nameof(WebTestApplicationFactory.TEST_ACCOUNT)) ?? + WebTestApplicationFactory.TEST_ACCOUNT + }; + var loginAccount = JsonContent.Create(req); + var rspMsg = await client.PostAsync( // + Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD, loginAccount) + .ConfigureAwait(false); + var rspObj = (await rspMsg.Content.ReadAsStringAsync().ConfigureAwait(false)) .ToObject>(); - _accessToken = loginRspObj.Data.AccessToken; + _accessToken = rspObj.Data.AccessToken; } client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA, _accessToken); - var ret = await client.PostAsync(url, content).ConfigureAwait(false); - testOutputHelper.WriteLine(await ret.Content.ReadAsStringAsync().ConfigureAwait(false)); - return ret; } } \ No newline at end of file diff --git a/src/backend/NetAdmin.Tests/WebTestApplicationFactory.cs b/src/backend/NetAdmin.Tests/WebTestApplicationFactory.cs new file mode 100644 index 00000000..3f1cc335 --- /dev/null +++ b/src/backend/NetAdmin.Tests/WebTestApplicationFactory.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Mvc.Testing; + +namespace NetAdmin.Tests; + +/// +/// Web 测试应用程序工厂 +/// +/// +public class WebTestApplicationFactory : WebApplicationFactory + where T : class +{ + /// + /// 测试用户 + /// + public const string TEST_ACCOUNT = "root"; + + /// + /// 测试密码 + /// + public const string TEST_PASSWORD = "1234qwer"; +} \ No newline at end of file diff --git a/src/frontend/admin/package.json b/src/frontend/admin/package.json index eee79303..4e7df5c0 100644 --- a/src/frontend/admin/package.json +++ b/src/frontend/admin/package.json @@ -10,15 +10,15 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.3.1", - "ace-builds": "^1.35.4", - "aieditor": "^1.0.13", - "axios": "^1.7.3", + "ace-builds": "^1.36.0", + "aieditor": "^1.0.14", + "axios": "^1.7.5", "clipboard": "^2.0.11", - "core-js": "^3.38.0", + "core-js": "^3.38.1", "cropperjs": "^1.6.2", "crypto-js": "^4.2.0", "echarts": "^5.5.1", - "element-plus": "^2.8.0", + "element-plus": "^2.8.1", "json-bigint": "^1.0.0", "json5-to-table": "^0.1.8", "markdown-it": "^14.1.0", @@ -28,8 +28,8 @@ "qrcodejs2": "^0.0.2", "sortablejs": "^1.15.2", "vkbeautify": "^0.99.3", - "vue": "^3.4.37", - "vue-i18n": "^9.13.1", + "vue": "^3.4.38", + "vue-i18n": "^9.14.0", "vue-router": "^4.4.3", "vue3-ace-editor": "^2.2.4", "vue3-json-viewer": "^2.2.2", @@ -41,8 +41,8 @@ "prettier": "^3.3.3", "prettier-plugin-organize-attributes": "^1.0.0", "sass": "^1.77.8", - "terser": "^5.31.5", - "vite": "^5.4.0" + "terser": "^5.31.6", + "vite": "^5.4.2" }, "browserslist": [ "> 1%", diff --git a/src/frontend/admin/src/api/controllers/probe.js b/src/frontend/admin/src/api/controllers/probe.js index 6fbe3ff1..71341ee5 100644 --- a/src/frontend/admin/src/api/controllers/probe.js +++ b/src/frontend/admin/src/api/controllers/probe.js @@ -15,4 +15,15 @@ export default { return await http.get(this.url, data, config) }, }, + + /** + * 系统是否已经安全停止 + */ + isSystemSafetyStopped: { + url: `${config.API_URL}/api/probe/is.system.safety.stopped`, + name: `系统是否已经安全停止`, + get: async function (data = {}, config = {}) { + return await http.get(this.url, data, config) + }, + }, } \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/cache.js b/src/frontend/admin/src/api/sys/cache.js index ee433c0f..8d12473f 100644 --- a/src/frontend/admin/src/api/sys/cache.js +++ b/src/frontend/admin/src/api/sys/cache.js @@ -5,6 +5,17 @@ import config from '@/config' import http from '@/utils/request' export default { + /** + * 批量删除缓存项 + */ + bulkDeleteEntry: { + url: `${config.API_URL}/api/sys/cache/bulk.delete.entry`, + name: `批量删除缓存项`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + /** * 缓存统计 */ @@ -16,6 +27,17 @@ export default { }, }, + /** + * 删除缓存项 + */ + deleteEntry: { + url: `${config.API_URL}/api/sys/cache/delete.entry`, + name: `删除缓存项`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + /** * 获取所有缓存项 */ diff --git a/src/frontend/admin/src/api/sys/tools.js b/src/frontend/admin/src/api/sys/tools.js index 2ba8adc0..1895deef 100644 --- a/src/frontend/admin/src/api/sys/tools.js +++ b/src/frontend/admin/src/api/sys/tools.js @@ -5,6 +5,17 @@ import config from '@/config' import http from '@/utils/request' export default { + /** + * 执行SQL语句 + */ + executeSql: { + url: `${config.API_URL}/api/sys/tools/execute.sql`, + name: `执行SQL语句`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + /** * 获取更新日志 */ @@ -48,4 +59,15 @@ export default { return await http.post(this.url, data, config) }, }, + + /** + * 系统停机 + */ + shutdown: { + url: `${config.API_URL}/api/sys/tools/shutdown`, + name: `系统停机`, + get: async function (data = {}, config = {}) { + return await http.get(this.url, data, config) + }, + }, } \ No newline at end of file diff --git a/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js b/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js index 1cf4996c..b6c17058 100644 --- a/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js +++ b/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js @@ -7,6 +7,29 @@ const T = { top: '40', containLabel: true, }, + pie: { + label: { + color: '#999', + }, + }, + gauge: { + axisTick: { + lineStyle: { + color: '#999', + }, + }, + splitLine: { + lineStyle: { + color: '#999', + }, + }, + axisLabel: { + color: '#999', + }, + title: { + color: '#999', + }, + }, legend: { textStyle: { color: '#999', diff --git a/src/frontend/admin/src/components/scFilterBar/my.vue b/src/frontend/admin/src/components/scFilterBar/my.vue index a3348b6d..4ed870c1 100644 --- a/src/frontend/admin/src/components/scFilterBar/my.vue +++ b/src/frontend/admin/src/components/scFilterBar/my.vue @@ -167,7 +167,7 @@ export default { } [data-theme='dark'] .sc-filter-my-list li { - color: #d0d0d0; + color: #c0c0c0; } [data-theme='dark'] .sc-filter-my-list li:hover { diff --git a/src/frontend/admin/src/components/scPageHeader/index.vue b/src/frontend/admin/src/components/scPageHeader/index.vue index 964e0a16..103ec7c7 100644 --- a/src/frontend/admin/src/components/scPageHeader/index.vue +++ b/src/frontend/admin/src/components/scPageHeader/index.vue @@ -88,6 +88,6 @@ export default { } [data-theme='dark'] .sc-page-header__title h2 { - color: #d0d0d0; + color: #c0c0c0; } \ No newline at end of file diff --git a/src/frontend/admin/src/components/scStatistic/index.vue b/src/frontend/admin/src/components/scStatistic/index.vue index 6ee69d89..1fdce0a7 100644 --- a/src/frontend/admin/src/components/scStatistic/index.vue +++ b/src/frontend/admin/src/components/scStatistic/index.vue @@ -100,6 +100,6 @@ export default { } .dark .sc-statistic-content { - color: #d0d0d0; + color: #c0c0c0; } \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTable/index.vue b/src/frontend/admin/src/components/scTable/index.vue index 83d9e684..85de8880 100644 --- a/src/frontend/admin/src/components/scTable/index.vue +++ b/src/frontend/admin/src/components/scTable/index.vue @@ -490,7 +490,7 @@ export default { this.loading = true try { await this.exportApi.post(this.getQueryParams()) - this.$message.success(`数据已导出(上限1万条)`) + this.$message.success(`数据已导出(上限2万条)`) } catch {} this.loading = false }, diff --git a/src/frontend/admin/src/style/app.scss b/src/frontend/admin/src/style/app.scss index 978282cc..a3378c6d 100644 --- a/src/frontend/admin/src/style/app.scss +++ b/src/frontend/admin/src/style/app.scss @@ -571,4 +571,20 @@ textarea { color: var(--el-color-info-light-3); } } +} + +.sc-statistic-error a { + font-size: inherit; + font-weight: inherit; + color: var(--el-color-danger) !important; + + &:after { + border-bottom: 1px solid var(--el-color-danger) !important; + bottom: 0; + content: ''; + height: 0; + left: 0; + position: absolute; + right: 0; + } } \ No newline at end of file diff --git a/src/frontend/admin/src/style/dark.scss b/src/frontend/admin/src/style/dark.scss index a2165a4d..278d3531 100644 --- a/src/frontend/admin/src/style/dark.scss +++ b/src/frontend/admin/src/style/dark.scss @@ -108,4 +108,8 @@ html.dark { .ace_gutter { background: var(--el-bg-color-overlay); } + + .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell { + --el-table-row-hover-bg-color: unset; + } } \ No newline at end of file diff --git a/src/frontend/admin/src/style/fix.scss b/src/frontend/admin/src/style/fix.scss index 44672cf4..282cdb64 100644 --- a/src/frontend/admin/src/style/fix.scss +++ b/src/frontend/admin/src/style/fix.scss @@ -302,4 +302,8 @@ .el-descriptions__body .el-descriptions__table .el-descriptions__cell { font-size: inherit; +} + +.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell { + --el-table-row-hover-bg-color: #fffaf0; } \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/cache/index.vue b/src/frontend/admin/src/views/sys/cache/index.vue index 3424f572..24aec529 100644 --- a/src/frontend/admin/src/views/sys/cache/index.vue +++ b/src/frontend/admin/src/views/sys/cache/index.vue @@ -62,10 +62,24 @@ -
+
+ +
- + + @@ -73,7 +87,14 @@ :buttons="[ { icon: 'el-icon-view', - click: rowClick, + click: viewClick, + }, + { + icon: 'el-icon-delete', + type: 'danger', + confirm: true, + title: '删除缓存', + click: delClick, }, ]" :vue="this" @@ -94,6 +115,7 @@ export default { }, data() { return { + selection: [], loading: true, dialog: { info: false, @@ -113,6 +135,24 @@ export default { } }, methods: { + //批量删除 + async batchDel() { + let loading + try { + await this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?`, '提示', { + type: 'warning', + }) + loading = this.$loading() + const res = await this.$API.sys_cache.bulkDeleteEntry.post({ + items: this.selection, + }) + this.$message.success(`删除 ${res.data} 项`) + } catch { + // + } + await this.getData() + loading?.close() + }, reset() { this.query.keywords = '' this.search() @@ -120,10 +160,19 @@ export default { search() { this.getData() }, - async rowClick(row) { + async delClick(row) { + try { + const res = await this.$API.sys_cache.deleteEntry.post({ key: row.key }) + this.$message.success(`删除 ${res.data} 项`) + } catch { + // + } + await this.getData() + }, + async viewClick(row) { this.dialog.info = true await this.$nextTick() - this.$refs.info.open( + await this.$refs.info.open( () => this.$t('缓存详情'), () => this.$API.sys_cache.getEntry.post({ key: row.key }), ) diff --git a/src/frontend/admin/src/views/sys/log/operation/index.vue b/src/frontend/admin/src/views/sys/log/operation/index.vue index b63bc93e..c4752afd 100644 --- a/src/frontend/admin/src/views/sys/log/operation/index.vue +++ b/src/frontend/admin/src/views/sys/log/operation/index.vue @@ -227,7 +227,7 @@ export default { const apiCrcs = data.data.rows?.map((x) => x.apiPathCrc32) const ips = data.data.rows?.map((x) => x.createdClientIp) ?? [] const res = await Promise.all([ - ownerIds && ownerIds.length > 0 + ownerIds && ownerIds.length > 0 && this.$GLOBAL.permissions.some((x) => x === '*/*/*' || x === 'sys/log/operation/user') ? this.$API.sys_user.query.post({ dynamicFilter: { field: 'id',