mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-23 14:42:51 +08:00
parent
dfe6b03b21
commit
58e4572723
@ -10,6 +10,7 @@ ij_xml_text_wrap = off # IntelliJ IDEA 中 XML 文本不换行
|
|||||||
indent_size = 4 # 缩进大小为 4 个空格
|
indent_size = 4 # 缩进大小为 4 个空格
|
||||||
indent_style = space # 使用空格进行缩进
|
indent_style = space # 使用空格进行缩进
|
||||||
insert_final_newline = false # 不在文件末尾插入空行
|
insert_final_newline = false # 不在文件末尾插入空行
|
||||||
|
max_line_length = 150 # 行长度限制为 150 个字符
|
||||||
trim_trailing_whitespace = true # 删除行尾的空格
|
trim_trailing_whitespace = true # 删除行尾的空格
|
||||||
|
|
||||||
[{*.json,*.yml}]
|
[{*.json,*.yml}]
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<Title>$(AssemblyName)</Title>
|
<Title>$(AssemblyName)</Title>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MinVer" Version="6.0.0-rc.1">
|
<PackageReference Include="MinVer" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.7 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
RUN apt update
|
RUN apt update
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Roslynator.Analyzers" Version="4.12.4">
|
<PackageReference Include="Roslynator.Analyzers" Version="4.12.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cz-git": "^1.9.4",
|
"cz-git": "^1.10.1",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"standard-version": "^9.5.0"
|
"standard-version": "^9.5.0"
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"packageName": "Furion.Pure.NS",
|
"packageName": "Furion.Pure.NS",
|
||||||
"version": "4.9.5.2-ns1"
|
"version": "4.9.5.8-ns1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,7 @@ public static class ServiceCollectionExtensions
|
|||||||
(Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => {
|
(Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => {
|
||||||
// 数据权限过滤器
|
// 数据权限过滤器
|
||||||
_ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( //
|
_ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( //
|
||||||
Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA
|
Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA, () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false
|
||||||
, () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false
|
|
||||||
, a => a.OwnerId == ContextUserInfo.Create().Id);
|
, a => a.OwnerId == ContextUserInfo.Create().Id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*
|
||||||
|
_ooOoo_
|
||||||
|
o8888888o
|
||||||
|
88" . "88
|
||||||
|
(| -_- |)
|
||||||
|
O\ = /O
|
||||||
|
____/`---'\____
|
||||||
|
.' \\| |// `.
|
||||||
|
/ \\||| : |||// \
|
||||||
|
/ _||||| -:- |||||- \
|
||||||
|
| | \\\ - /// | |
|
||||||
|
| \_| ''\---/'' | |
|
||||||
|
\ .-\__ `-` ___/-. /
|
||||||
|
___`. .' /--.--\ `. . __
|
||||||
|
."" '< `.___\_<|>_/___.' >'"".
|
||||||
|
| | : `- \`.;`\ _ /`;.`/ - ` : | |
|
||||||
|
\ \ `-. \_ __\ /__ _/ .-` / /
|
||||||
|
======`-.____`-.___\_____/___.-`____.-'======
|
||||||
|
`=---='
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
佛祖保佑 永无BUG
|
||||||
|
*/
|
||||||
|
|
||||||
using NetAdmin.AdmServer.Host;
|
using NetAdmin.AdmServer.Host;
|
||||||
using NetAdmin.AdmServer.Host.Extensions;
|
using NetAdmin.AdmServer.Host.Extensions;
|
||||||
using NetAdmin.Host.Extensions;
|
using NetAdmin.Host.Extensions;
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
<ProjectReference Include="../NetAdmin.AdmServer.Host/NetAdmin.AdmServer.Host.csproj"/>
|
<ProjectReference Include="../NetAdmin.AdmServer.Host/NetAdmin.AdmServer.Host.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -5,10 +5,8 @@ namespace NetAdmin.Application.Repositories;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础仓储
|
/// 基础仓储
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class BasicRepository<TEntity, TPrimary>(
|
public sealed class BasicRepository<TEntity, TPrimary>(IFreeSql fSql, UnitOfWorkManager uowManger, ContextUserToken userToken)
|
||||||
IFreeSql fSql
|
: DefaultRepository<TEntity, TPrimary>(fSql, uowManger)
|
||||||
, UnitOfWorkManager uowManger
|
|
||||||
, ContextUserToken userToken) : DefaultRepository<TEntity, TPrimary>(fSql, uowManger)
|
|
||||||
where TEntity : EntityBase<TPrimary> //
|
where TEntity : EntityBase<TPrimary> //
|
||||||
where TPrimary : IEquatable<TPrimary>
|
where TPrimary : IEquatable<TPrimary>
|
||||||
{
|
{
|
||||||
|
@ -20,19 +20,15 @@ public abstract class RedisService<TEntity, TPrimary, TLogger>(BasicRepository<T
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected IDatabase RedisDatabase { get; } //
|
protected IDatabase RedisDatabase { get; } //
|
||||||
= App.GetService<IConnectionMultiplexer>()
|
= App.GetService<IConnectionMultiplexer>()
|
||||||
.GetDatabase(App.GetOptions<RedisOptions>()
|
.GetDatabase(App.GetOptions<RedisOptions>().Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE).Database);
|
||||||
.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
|
|
||||||
.Database);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取锁
|
/// 获取锁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Task<RedisLocker> GetLockerAsync(string lockerName)
|
protected Task<RedisLocker> GetLockerAsync(string lockerName)
|
||||||
{
|
{
|
||||||
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName
|
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY)
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY)
|
, Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
||||||
, Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
|
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,8 +36,7 @@ public abstract class RedisService<TEntity, TPrimary, TLogger>(BasicRepository<T
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Task<RedisLocker> GetLockerOnceAsync(string lockerName)
|
protected Task<RedisLocker> GetLockerOnceAsync(string lockerName)
|
||||||
{
|
{
|
||||||
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName
|
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), 1
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), 1
|
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,8 +12,7 @@ namespace NetAdmin.Application.Services;
|
|||||||
/// <typeparam name="TEntity">实体类型</typeparam>
|
/// <typeparam name="TEntity">实体类型</typeparam>
|
||||||
/// <typeparam name="TPrimary">主键类型</typeparam>
|
/// <typeparam name="TPrimary">主键类型</typeparam>
|
||||||
/// <typeparam name="TLogger">日志类型</typeparam>
|
/// <typeparam name="TLogger">日志类型</typeparam>
|
||||||
public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo)
|
public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo) : ServiceBase<TLogger>
|
||||||
: ServiceBase<TLogger>
|
|
||||||
where TEntity : EntityBase<TPrimary> //
|
where TEntity : EntityBase<TPrimary> //
|
||||||
where TPrimary : IEquatable<TPrimary>
|
where TPrimary : IEquatable<TPrimary>
|
||||||
{
|
{
|
||||||
@ -46,8 +45,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
|||||||
/// 导出实体
|
/// 导出实体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
||||||
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName
|
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName, Expression<Func<TEntity, object>> listExp = null)
|
||||||
, Expression<Func<TEntity, object>> listExp = null)
|
|
||||||
where TQuery : DataAbstraction, new()
|
where TQuery : DataAbstraction, new()
|
||||||
{
|
{
|
||||||
var select = selector(query)
|
var select = selector(query)
|
||||||
@ -56,9 +54,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
|||||||
#endif
|
#endif
|
||||||
.Take(Numbers.MAX_LIMIT_EXPORT);
|
.Take(Numbers.MAX_LIMIT_EXPORT);
|
||||||
|
|
||||||
object list = listExp == null
|
object list = listExp == null ? await select.ToListAsync().ConfigureAwait(false) : await select.ToListAsync(listExp).ConfigureAwait(false);
|
||||||
? await select.ToListAsync().ConfigureAwait(false)
|
|
||||||
: await select.ToListAsync(listExp).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false);
|
return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -108,10 +104,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
|||||||
{
|
{
|
||||||
// 默认匹配主键
|
// 默认匹配主键
|
||||||
whereExp ??= a => a.Id.Equals(newValue.Id);
|
whereExp ??= a => a.Id.Equals(newValue.Id);
|
||||||
return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion)
|
return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql).ExecuteUpdatedAsync();
|
||||||
.Where(whereExp)
|
|
||||||
.Where(whereSql)
|
|
||||||
.ExecuteUpdatedAsync();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -134,7 +127,8 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
|||||||
|
|
||||||
App.HttpContext.Response.Headers.ContentDisposition
|
App.HttpContext.Response.Headers.ContentDisposition
|
||||||
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
|
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
|
||||||
FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
|
FileNameStar
|
||||||
|
= $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
|
||||||
}.ToString();
|
}.ToString();
|
||||||
|
|
||||||
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
|
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
|
||||||
@ -149,9 +143,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
|||||||
var updateExp = includeFields == null
|
var updateExp = includeFields == null
|
||||||
? Rpo.UpdateDiy.SetSource(entity)
|
? Rpo.UpdateDiy.SetSource(entity)
|
||||||
: Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary(
|
: Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary(
|
||||||
x => x
|
x => x, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!.GetValue(entity)));
|
||||||
, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!
|
|
||||||
.GetValue(entity)));
|
|
||||||
if (excludeFields != null) {
|
if (excludeFields != null) {
|
||||||
updateExp = updateExp.IgnoreColumns(excludeFields);
|
updateExp = updateExp.IgnoreColumns(excludeFields);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ namespace NetAdmin.Cache;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存基类
|
/// 缓存基类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class CacheBase<TCacheContainer, TService>(TCacheContainer cache, TService service)
|
public abstract class CacheBase<TCacheContainer, TService>(TCacheContainer cache, TService service) : ICache<TCacheContainer, TService>
|
||||||
: ICache<TCacheContainer, TService>
|
|
||||||
where TService : IService
|
where TService : IService
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -6,8 +6,7 @@ namespace NetAdmin.Cache;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分布式缓存
|
/// 分布式缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class DistributedCache<TService>(IDistributedCache cache, TService service)
|
public abstract class DistributedCache<TService>(IDistributedCache cache, TService service) : CacheBase<IDistributedCache, TService>(cache, service)
|
||||||
: CacheBase<IDistributedCache, TService>(cache, service)
|
|
||||||
where TService : IService
|
where TService : IService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,12 +65,10 @@ public abstract class DistributedCache<TService>(IDistributedCache cache, TServi
|
|||||||
/// <param name="slideLifeTime">滑动过期时间</param>
|
/// <param name="slideLifeTime">滑动过期时间</param>
|
||||||
/// <typeparam name="T">缓存对象类型</typeparam>
|
/// <typeparam name="T">缓存对象类型</typeparam>
|
||||||
/// <returns>缓存对象</returns>
|
/// <returns>缓存对象</returns>
|
||||||
protected async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> createProc, TimeSpan? absLifeTime = null
|
protected async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> createProc, TimeSpan? absLifeTime = null, TimeSpan? slideLifeTime = null)
|
||||||
, TimeSpan? slideLifeTime = null)
|
|
||||||
{
|
{
|
||||||
var cacheRead = await GetAsync<T>(key).ConfigureAwait(false);
|
var cacheRead = await GetAsync<T>(key).ConfigureAwait(false);
|
||||||
if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() !=
|
if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() != Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
|
||||||
Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
|
|
||||||
return cacheRead;
|
return cacheRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,5 @@ namespace NetAdmin.Cache;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内存缓存
|
/// 内存缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MemoryCache<TService>(IMemoryCache cache, TService service)
|
public abstract class MemoryCache<TService>(IMemoryCache cache, TService service) : CacheBase<IMemoryCache, TService>(cache, service)
|
||||||
: CacheBase<IMemoryCache, TService>(cache, service)
|
|
||||||
where TService : IService;
|
where TService : IService;
|
@ -12,8 +12,7 @@ public sealed class ApiIdAttribute : ValidationAttribute
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
var service = App.GetService(App.EffectiveTypes.Single(
|
var service = App.GetService(App.EffectiveTypes.Single(x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IApiCache"));
|
||||||
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IApiCache"));
|
|
||||||
|
|
||||||
var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } };
|
var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } };
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ public sealed class JsonStringAttribute : ValidationAttribute
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
return (value as string).IsJsonString()
|
return (value as string).IsJsonString() ? ValidationResult.Success : new ValidationResult(Ln.非JSON字符串, [validationContext.MemberName]);
|
||||||
? ValidationResult.Success
|
|
||||||
: new ValidationResult(Ln.非JSON字符串, new[] { validationContext.MemberName });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,8 +12,7 @@ public sealed class UserIdAttribute : ValidationAttribute
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
var service = App.GetService(App.EffectiveTypes.Single(
|
var service = App.GetService(App.EffectiveTypes.Single(x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IUserCache"));
|
||||||
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IUserCache"));
|
|
||||||
|
|
||||||
var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } };
|
var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } };
|
||||||
|
|
||||||
|
@ -45,9 +45,7 @@ public sealed record ContextUserToken : DataAbstraction
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static ContextUserToken Create(QueryUserRsp user)
|
public static ContextUserToken Create(QueryUserRsp user)
|
||||||
{
|
{
|
||||||
return new ContextUserToken {
|
return new ContextUserToken { Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId };
|
||||||
Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -30,9 +30,7 @@ public abstract record DataAbstraction
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void TruncateStrings()
|
public void TruncateStrings()
|
||||||
{
|
{
|
||||||
foreach (var property in GetType()
|
foreach (var property in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType == typeof(string))) {
|
||||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(x => x.PropertyType == typeof(string))) {
|
|
||||||
var maxLen = property.GetCustomAttribute<MaxLengthAttribute>(true)?.Length;
|
var maxLen = property.GetCustomAttribute<MaxLengthAttribute>(true)?.Length;
|
||||||
if (maxLen is null or 0) {
|
if (maxLen is null or 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
|
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
|
||||||
public record Sys_DicContent : VersionEntity
|
public record Sys_DicContent : VersionEntity, IFieldEnabled, IFieldSummary
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 字典目录
|
/// 字典目录
|
||||||
@ -23,6 +23,12 @@ public record Sys_DicContent : VersionEntity
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual long CatalogId { get; init; }
|
public virtual long CatalogId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldEnabled.Enabled" />
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 键名称
|
/// 键名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -31,6 +37,14 @@ public record Sys_DicContent : VersionEntity
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual string Key { get; init; }
|
public virtual string Key { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述
|
||||||
|
/// </summary>
|
||||||
|
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string Summary { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 键值
|
/// 键值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -7,8 +7,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_LoginLog))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_LoginLog))]
|
||||||
public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp, IFieldCreatedClientUserAgent
|
||||||
, IFieldCreatedClientUserAgent
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[Column]
|
[Column]
|
||||||
|
@ -10,8 +10,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||||
[Table( //
|
[Table( //
|
||||||
Name = $"{Chars.FLG_DB_TABLE_NAME_PREFIX}{nameof(Sys_RequestLog)}_{{yyyyMMdd}}"
|
Name = $"{Chars.FLG_DB_TABLE_NAME_PREFIX}{nameof(Sys_RequestLog)}_{{yyyyMMdd}}", AsTable = $"{nameof(CreatedTime)}=2024-5-1(1 day)")]
|
||||||
, AsTable = $"{nameof(CreatedTime)}=2024-1-1(1 day)")]
|
|
||||||
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -123,20 +123,11 @@ public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary
|
|||||||
{
|
{
|
||||||
_ = config.ForType<CreateRoleReq, Sys_Role>()
|
_ = config.ForType<CreateRoleReq, Sys_Role>()
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Depts
|
d => d.Depts, s => s.DeptIds.NullOrEmpty() ? Array.Empty<Sys_Dept>() : s.DeptIds.Select(x => new Sys_Dept { Id = x }))
|
||||||
, s => s.DeptIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Dept>()
|
|
||||||
: s.DeptIds.Select(x => new Sys_Dept { Id = x }))
|
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Menus
|
d => d.Menus, s => s.MenuIds.NullOrEmpty() ? Array.Empty<Sys_Menu>() : s.MenuIds.Select(x => new Sys_Menu { Id = x }))
|
||||||
, s => s.MenuIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Menu>()
|
|
||||||
: s.MenuIds.Select(x => new Sys_Menu { Id = x }))
|
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Apis
|
d => d.Apis, s => s.ApiIds.NullOrEmpty() ? Array.Empty<Sys_Api>() : s.ApiIds.Select(x => new Sys_Api { Id = x }))
|
||||||
, s => s.ApiIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Api>()
|
|
||||||
: s.ApiIds.Select(x => new Sys_Api { Id = x }))
|
|
||||||
|
|
||||||
//
|
//
|
||||||
;
|
;
|
||||||
|
@ -91,20 +91,11 @@ public record Sys_SiteMsg : VersionEntity, IRegister, IFieldSummary
|
|||||||
.Map( //
|
.Map( //
|
||||||
d => d.Summary, s => s.Content.RemoveHtmlTag().HtmlDe().Sub(0, 100))
|
d => d.Summary, s => s.Content.RemoveHtmlTag().HtmlDe().Sub(0, 100))
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Roles
|
d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }))
|
||||||
, s => s.RoleIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Role>()
|
|
||||||
: s.RoleIds.Select(x => new Sys_Role { Id = x }))
|
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Users
|
d => d.Users, s => s.UserIds.NullOrEmpty() ? Array.Empty<Sys_User>() : s.UserIds.Select(x => new Sys_User { Id = x }))
|
||||||
, s => s.UserIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_User>()
|
|
||||||
: s.UserIds.Select(x => new Sys_User { Id = x }))
|
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Depts
|
d => d.Depts, s => s.DeptIds.NullOrEmpty() ? Array.Empty<Sys_Dept>() : s.DeptIds.Select(x => new Sys_Dept { Id = x }))
|
||||||
, s => s.DeptIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Dept>()
|
|
||||||
: s.DeptIds.Select(x => new Sys_Dept { Id = x }))
|
|
||||||
|
|
||||||
//
|
//
|
||||||
;
|
;
|
||||||
|
@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 站内信-部门映射表
|
/// 站内信-部门映射表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}"
|
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}", true)]
|
||||||
, true)]
|
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))]
|
||||||
public record Sys_SiteMsgDept : ImmutableEntity
|
public record Sys_SiteMsgDept : ImmutableEntity
|
||||||
{
|
{
|
||||||
|
@ -5,8 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 站内信标记表
|
/// 站内信标记表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}"
|
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}", true)]
|
||||||
, true)]
|
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))]
|
||||||
public record Sys_SiteMsgFlag : MutableEntity
|
public record Sys_SiteMsgFlag : MutableEntity
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 站内信-角色映射表
|
/// 站内信-角色映射表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}"
|
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}", true)]
|
||||||
, true)]
|
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))]
|
||||||
public record Sys_SiteMsgRole : ImmutableEntity
|
public record Sys_SiteMsgRole : ImmutableEntity
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 站内信-用户映射表
|
/// 站内信-用户映射表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}"
|
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}", true)]
|
||||||
, true)]
|
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))]
|
||||||
public record Sys_SiteMsgUser : ImmutableEntity
|
public record Sys_SiteMsgUser : ImmutableEntity
|
||||||
{
|
{
|
||||||
|
@ -130,18 +130,12 @@ public record Sys_User : VersionEntity, IFieldSummary, IFieldEnabled, IRegister
|
|||||||
.Map(d => d.Password, s => s.PasswordText.Pwd().Guid())
|
.Map(d => d.Password, s => s.PasswordText.Pwd().Guid())
|
||||||
.Map(d => d.Token, _ => Guid.NewGuid())
|
.Map(d => d.Token, _ => Guid.NewGuid())
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Roles
|
d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }));
|
||||||
, s => s.RoleIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Role>()
|
|
||||||
: s.RoleIds.Select(x => new Sys_Role { Id = x }));
|
|
||||||
|
|
||||||
_ = config.ForType<EditUserReq, Sys_User>()
|
_ = config.ForType<EditUserReq, Sys_User>()
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Password, s => s.PasswordText.NullOrEmpty() ? Guid.Empty : s.PasswordText.Pwd().Guid())
|
d => d.Password, s => s.PasswordText.NullOrEmpty() ? Guid.Empty : s.PasswordText.Pwd().Guid())
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.Roles
|
d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }));
|
||||||
, s => s.RoleIds.NullOrEmpty()
|
|
||||||
? Array.Empty<Sys_Role>()
|
|
||||||
: s.RoleIds.Select(x => new Sys_Role { Id = x }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -228,7 +228,6 @@ public record Sys_UserProfile : VersionEntity, IRegister
|
|||||||
.Map(d => d.CompanyArea, s => s.CompanyArea == null ? null : s.CompanyArea.Value)
|
.Map(d => d.CompanyArea, s => s.CompanyArea == null ? null : s.CompanyArea.Value)
|
||||||
.Map(d => d.HomeArea, s => s.HomeArea == null ? null : s.HomeArea.Value)
|
.Map(d => d.HomeArea, s => s.HomeArea == null ? null : s.HomeArea.Value)
|
||||||
.Map( //
|
.Map( //
|
||||||
d => d.EmergencyContactArea
|
d => d.EmergencyContactArea, s => s.EmergencyContactArea == null ? null : s.EmergencyContactArea.Value);
|
||||||
, s => s.EmergencyContactArea == null ? null : s.EmergencyContactArea.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,8 +74,8 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) }
|
if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) }.Contains(
|
||||||
.Contains(d?.Field, StringComparer.OrdinalIgnoreCase)) {
|
d?.Field, StringComparer.OrdinalIgnoreCase)) {
|
||||||
var val = d!.Value?.ToString();
|
var val = d!.Value?.ToString();
|
||||||
if (val?.IsIpV4() == true) {
|
if (val?.IsIpV4() == true) {
|
||||||
d.Value = val.IpV4ToInt32();
|
d.Value = val.IpV4ToInt32();
|
||||||
|
@ -6,13 +6,13 @@ namespace NetAdmin.Domain.Dto.Sys.Cache;
|
|||||||
public sealed record CacheStatisticsRsp : DataAbstraction
|
public sealed record CacheStatisticsRsp : DataAbstraction
|
||||||
{
|
{
|
||||||
private static readonly Regex[] _regexes = [
|
private static readonly Regex[] _regexes = [
|
||||||
new Regex(@"keyspace_hits:(\d+)", RegexOptions.Compiled) //
|
new(@"keyspace_hits:(\d+)", RegexOptions.Compiled) //
|
||||||
, new Regex(@"keyspace_misses:(\d+)", RegexOptions.Compiled) //
|
, new(@"keyspace_misses:(\d+)", RegexOptions.Compiled) //
|
||||||
, new Regex(@"uptime_in_seconds:(\d+)", RegexOptions.Compiled) //
|
, new(@"uptime_in_seconds:(\d+)", RegexOptions.Compiled) //
|
||||||
, new Regex(@"used_cpu_sys:([\d\\.]+)", RegexOptions.Compiled) //
|
, new(@"used_cpu_sys:([\d\\.]+)", RegexOptions.Compiled) //
|
||||||
, new Regex(@"used_cpu_user:([\d\\.]+)", RegexOptions.Compiled) //
|
, new(@"used_cpu_user:([\d\\.]+)", RegexOptions.Compiled) //
|
||||||
, new Regex(@"used_memory:(\d+)", RegexOptions.Compiled) //
|
, new(@"used_memory:(\d+)", RegexOptions.Compiled) //
|
||||||
, new Regex("redis_version:(.+)", RegexOptions.Compiled) //
|
, new("redis_version:(.+)", RegexOptions.Compiled) //
|
||||||
];
|
];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,8 +28,7 @@ public sealed record CacheStatisticsRsp : DataAbstraction
|
|||||||
KeyspaceHits = _regexes[0].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
KeyspaceHits = _regexes[0].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
||||||
KeyspaceMisses = _regexes[1].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
KeyspaceMisses = _regexes[1].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
||||||
UpTime = _regexes[2].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
UpTime = _regexes[2].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
||||||
UsedCpu = _regexes[3].Match(redisResult).Groups[1].Value.Trim().DecTry(0) +
|
UsedCpu = _regexes[3].Match(redisResult).Groups[1].Value.Trim().DecTry(0) + _regexes[4].Match(redisResult).Groups[1].Value.Trim().DecTry(0);
|
||||||
_regexes[4].Match(redisResult).Groups[1].Value.Trim().DecTry(0);
|
|
||||||
UsedMemory = _regexes[5].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
UsedMemory = _regexes[5].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
|
||||||
Version = _regexes[6].Match(redisResult).Groups[1].Value.Trim();
|
Version = _regexes[6].Match(redisResult).Groups[1].Value.Trim();
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,21 @@ public record CreateDicContentReq : Sys_DicContent
|
|||||||
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典目录编号不能为空))]
|
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典目录编号不能为空))]
|
||||||
public override long CatalogId { get; init; }
|
public override long CatalogId { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_DicContent.Key" />
|
/// <inheritdoc cref="IFieldEnabled.Enabled" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override bool Enabled { get; init; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_DicContent.Key" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键名称不能为空))]
|
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键名称不能为空))]
|
||||||
public override string Key { get; init; }
|
public override string Key { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_DicContent.Summary" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string Summary { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_DicContent.Value" />
|
/// <inheritdoc cref="Sys_DicContent.Value" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键值不能为空))]
|
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键值不能为空))]
|
||||||
public override string Value { get; init; }
|
public override string Value { get; init; }
|
||||||
}
|
}
|
@ -11,12 +11,24 @@ public sealed record ExportDicContentRsp : QueryDicContentRsp
|
|||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
[CsvIgnore(false)]
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.项名))]
|
[CsvName(nameof(Ln.项名))]
|
||||||
public override string Key { get; init; }
|
public override string Key { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.备注))]
|
||||||
|
public override string Summary { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
[CsvIgnore(false)]
|
[CsvIgnore(false)]
|
||||||
|
@ -13,10 +13,18 @@ public record QueryDicContentRsp : Sys_DicContent
|
|||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldEnabled.Enabled" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_DicContent.Key" />
|
/// <inheritdoc cref="Sys_DicContent.Key" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override string Key { get; init; }
|
public override string Key { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_DicContent.Summary" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string Summary { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_DicContent.Value" />
|
/// <inheritdoc cref="Sys_DicContent.Value" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override string Value { get; init; }
|
public override string Value { get; init; }
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
namespace NetAdmin.Domain.Dto.Sys.Dic.Content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求:设置字典内容启用状态
|
||||||
|
/// </summary>
|
||||||
|
public sealed record SetDicContentEnabledReq : Sys_DicContent
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IFieldEnabled.Enabled" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldVersion.Version" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override long Version { get; init; }
|
||||||
|
}
|
@ -19,8 +19,7 @@ public record CreateJobReq : Sys_Job
|
|||||||
public override string ExecutionCron { get; init; }
|
public override string ExecutionCron { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_Job.HttpMethod" />
|
/// <inheritdoc cref="Sys_Job.HttpMethod" />
|
||||||
[EnumDataType(typeof(HttpMethods), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(HttpMethods), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求方法不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.请求方法不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override HttpMethods HttpMethod { get; init; }
|
public override HttpMethods HttpMethod { get; init; }
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ public record QueryJobRsp : Sys_Job
|
|||||||
/// Cron 表达式描述
|
/// Cron 表达式描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public string CronDescription =>
|
public string CronDescription => ExpressionDescriptor.GetDescription(ExecutionCron, new Options { Locale = "zh-CN" });
|
||||||
ExpressionDescriptor.GetDescription(ExecutionCron, new Options { Locale = "zh-CN" });
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_Job.LastStatusCode" />
|
/// <inheritdoc cref="Sys_Job.LastStatusCode" />
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
|
@ -15,8 +15,7 @@ public sealed record MetaInfo : DataAbstraction
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MetaInfo" /> class.
|
/// Initializes a new instance of the <see cref="MetaInfo" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MetaInfo(string color, bool fullPage, bool hidden, bool hiddenBreadCrumb, string icon, string tag
|
public MetaInfo(string color, bool fullPage, bool hidden, bool hiddenBreadCrumb, string icon, string tag, string title, MenuTypes type)
|
||||||
, string title, MenuTypes type)
|
|
||||||
{
|
{
|
||||||
Color = color;
|
Color = color;
|
||||||
FullPage = fullPage;
|
FullPage = fullPage;
|
||||||
@ -73,8 +72,7 @@ public sealed record MetaInfo : DataAbstraction
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类型
|
/// 类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumDataType(typeof(MenuTypes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(MenuTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.菜单类型不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.菜单类型不正确))]
|
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public MenuTypes Type { get; init; }
|
public MenuTypes Type { get; init; }
|
||||||
}
|
}
|
@ -18,8 +18,7 @@ public record CreateRoleReq : Sys_Role, IValidatableObject
|
|||||||
public override string DashboardLayout { get; set; }
|
public override string DashboardLayout { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_Role.DataScope" />
|
/// <inheritdoc cref="Sys_Role.DataScope" />
|
||||||
[EnumDataType(typeof(DataScopes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(DataScopes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色数据范围不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.角色数据范围不正确))]
|
|
||||||
public override DataScopes DataScope { get; init; } = DataScopes.All;
|
public override DataScopes DataScope { get; init; } = DataScopes.All;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -20,8 +20,7 @@ public record CreateSiteMsgReq : Sys_SiteMsg
|
|||||||
public IReadOnlyCollection<long> DeptIds { get; init; }
|
public IReadOnlyCollection<long> DeptIds { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_SiteMsg.MsgType" />
|
/// <inheritdoc cref="Sys_SiteMsg.MsgType" />
|
||||||
[EnumDataType(typeof(SiteMsgTypes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(SiteMsgTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.站内信类型不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.站内信类型不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override SiteMsgTypes MsgType { get; init; }
|
public override SiteMsgTypes MsgType { get; init; }
|
||||||
|
|
||||||
|
@ -12,8 +12,7 @@ public record CreateSiteMsgFlagReq : Sys_SiteMsgFlag
|
|||||||
public override long SiteMsgId { get; init; }
|
public override long SiteMsgId { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_SiteMsgFlag.UserSiteMsgStatus" />
|
/// <inheritdoc cref="Sys_SiteMsgFlag.UserSiteMsgStatus" />
|
||||||
[EnumDataType(typeof(UserSiteMsgStatues), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(UserSiteMsgStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.站内信状态不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.站内信状态不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override UserSiteMsgStatues UserSiteMsgStatus { get; init; }
|
public override UserSiteMsgStatues UserSiteMsgStatus { get; init; }
|
||||||
}
|
}
|
12
src/backend/NetAdmin.Domain/Dto/Sys/Tool/AesDecodeReq.cs
Normal file
12
src/backend/NetAdmin.Domain/Dto/Sys/Tool/AesDecodeReq.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace NetAdmin.Domain.Dto.Sys.Tool;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求:Aes解密
|
||||||
|
/// </summary>
|
||||||
|
public record AesDecodeReq : DataAbstraction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 密文
|
||||||
|
/// </summary>
|
||||||
|
public string CipherText { get; init; }
|
||||||
|
}
|
@ -16,6 +16,14 @@ public record QueryUserRsp : Sys_User
|
|||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserId" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override long? CreatedUserId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserName" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string CreatedUserName { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_User.Dept" />
|
/// <inheritdoc cref="Sys_User.Dept" />
|
||||||
public new virtual QueryDeptRsp Dept { get; init; }
|
public new virtual QueryDeptRsp Dept { get; init; }
|
||||||
|
|
||||||
|
@ -17,8 +17,7 @@ public record CreateUserProfileReq : Sys_UserProfile
|
|||||||
public override string CertificateNumber { get; init; }
|
public override string CertificateNumber { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_UserProfile.CertificateType" />
|
/// <inheritdoc cref="Sys_UserProfile.CertificateType" />
|
||||||
[EnumDataType(typeof(CertificateTypes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(CertificateTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.证件类型不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.证件类型不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override CertificateTypes? CertificateType { get; init; }
|
public override CertificateTypes? CertificateType { get; init; }
|
||||||
|
|
||||||
@ -39,8 +38,7 @@ public record CreateUserProfileReq : Sys_UserProfile
|
|||||||
public override string CompanyTelephone { get; init; }
|
public override string CompanyTelephone { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_UserProfile.Education" />
|
/// <inheritdoc cref="Sys_UserProfile.Education" />
|
||||||
[EnumDataType(typeof(Educations), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(Educations), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.学历不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.学历不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override Educations? Education { get; init; }
|
public override Educations? Education { get; init; }
|
||||||
|
|
||||||
@ -82,8 +80,7 @@ public record CreateUserProfileReq : Sys_UserProfile
|
|||||||
public override string HomeTelephone { get; init; }
|
public override string HomeTelephone { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_UserProfile.MarriageStatus" />
|
/// <inheritdoc cref="Sys_UserProfile.MarriageStatus" />
|
||||||
[EnumDataType(typeof(MarriageStatues), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(MarriageStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.婚姻状况不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.婚姻状况不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override MarriageStatues? MarriageStatus { get; init; }
|
public override MarriageStatues? MarriageStatus { get; init; }
|
||||||
|
|
||||||
@ -96,8 +93,7 @@ public record CreateUserProfileReq : Sys_UserProfile
|
|||||||
public new CreateDicContentReq NationArea { get; init; }
|
public new CreateDicContentReq NationArea { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_UserProfile.PoliticalStatus" />
|
/// <inheritdoc cref="Sys_UserProfile.PoliticalStatus" />
|
||||||
[EnumDataType(typeof(PoliticalStatues), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(PoliticalStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.政治面貌不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.政治面貌不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public override PoliticalStatues? PoliticalStatus { get; init; }
|
public override PoliticalStatues? PoliticalStatus { get; init; }
|
||||||
|
|
||||||
|
@ -14,8 +14,7 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
|
|||||||
public override string DestDevice { get; init; }
|
public override string DestDevice { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_VerifyCode.DeviceType" />
|
/// <inheritdoc cref="Sys_VerifyCode.DeviceType" />
|
||||||
[EnumDataType(typeof(VerifyCodeDeviceTypes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(VerifyCodeDeviceTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码目标设备类型不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.验证码目标设备类型不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.设备类型不能为空))]
|
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.设备类型不能为空))]
|
||||||
public override VerifyCodeDeviceTypes DeviceType { get; init; }
|
public override VerifyCodeDeviceTypes DeviceType { get; init; }
|
||||||
@ -24,8 +23,7 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
|
|||||||
public override VerifyCodeStatues Status => VerifyCodeStatues.Waiting;
|
public override VerifyCodeStatues Status => VerifyCodeStatues.Waiting;
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_VerifyCode.Type" />
|
/// <inheritdoc cref="Sys_VerifyCode.Type" />
|
||||||
[EnumDataType(typeof(VerifyCodeTypes), ErrorMessageResourceType = typeof(Ln)
|
[EnumDataType(typeof(VerifyCodeTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不正确))]
|
||||||
, ErrorMessageResourceName = nameof(Ln.验证码类型不正确))]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不能为空))]
|
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不能为空))]
|
||||||
public override VerifyCodeTypes Type { get; init; }
|
public override VerifyCodeTypes Type { get; init; }
|
||||||
@ -43,22 +41,20 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
|
|||||||
switch (DeviceType) {
|
switch (DeviceType) {
|
||||||
case VerifyCodeDeviceTypes.Email:
|
case VerifyCodeDeviceTypes.Email:
|
||||||
validationResult = new EmailAttribute().GetValidationResult(DestDevice, validationContext);
|
validationResult = new EmailAttribute().GetValidationResult(DestDevice, validationContext);
|
||||||
if (validationResult == null) {
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) });
|
|
||||||
break;
|
break;
|
||||||
case VerifyCodeDeviceTypes.Mobile:
|
case VerifyCodeDeviceTypes.Mobile:
|
||||||
validationResult = new MobileAttribute().GetValidationResult(DestDevice, validationContext);
|
validationResult = new MobileAttribute().GetValidationResult(DestDevice, validationContext);
|
||||||
if (validationResult == null) {
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) });
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validationResult == null) {
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new ValidationResult(validationResult.ErrorMessage, [nameof(DestDevice)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,6 @@ public sealed record SyncStructureAfterEvent : SyncStructureBeforeEvent
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln.数据库结构同步完成
|
return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln.数据库结构同步完成, string.Join(',', EntityTypes.Select(x => x.Name)));
|
||||||
, string.Join(',', EntityTypes.Select(x => x.Name)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,8 +10,8 @@ public sealed record RequestLogEvent : DataAbstraction, IEventSourceGeneric<Crea
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestLogEvent" /> class.
|
/// Initializes a new instance of the <see cref="RequestLogEvent" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RequestLogEvent(CreateRequestLogReq data, bool isConsumOnce = false, object payload = default
|
public RequestLogEvent(CreateRequestLogReq data, bool isConsumOnce = false, object payload = default, DateTime createdTime = default
|
||||||
, DateTime createdTime = default, CancellationToken cancellationToken = default)
|
, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
IsConsumOnce = isConsumOnce;
|
IsConsumOnce = isConsumOnce;
|
||||||
|
@ -10,8 +10,8 @@ public sealed record UserUpdatedEvent : DataAbstraction, IEventSourceGeneric<Use
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UserUpdatedEvent" /> class.
|
/// Initializes a new instance of the <see cref="UserUpdatedEvent" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UserUpdatedEvent(UserInfoRsp data, DateTime createdTime = default, bool isConsumOnce = false
|
public UserUpdatedEvent(UserInfoRsp data, DateTime createdTime = default, bool isConsumOnce = false, object payload = default
|
||||||
, object payload = default, CancellationToken cancellationToken = default)
|
, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
CancellationToken = cancellationToken;
|
CancellationToken = cancellationToken;
|
||||||
|
@ -10,8 +10,8 @@ public sealed record VerifyCodeCreatedEvent : DataAbstraction, IEventSourceGener
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="VerifyCodeCreatedEvent" /> class.
|
/// Initializes a new instance of the <see cref="VerifyCodeCreatedEvent" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public VerifyCodeCreatedEvent(QueryVerifyCodeRsp data, DateTime createdTime = default, bool isConsumOnce = false
|
public VerifyCodeCreatedEvent(QueryVerifyCodeRsp data, DateTime createdTime = default, bool isConsumOnce = false, object payload = default
|
||||||
, object payload = default, CancellationToken cancellationToken = default)
|
, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
CancellationToken = cancellationToken;
|
CancellationToken = cancellationToken;
|
||||||
|
@ -67,11 +67,9 @@ public abstract class WorkBase<TLogger>
|
|||||||
{
|
{
|
||||||
var db = ServiceProvider.GetService<IConnectionMultiplexer>()
|
var db = ServiceProvider.GetService<IConnectionMultiplexer>()
|
||||||
.GetDatabase(ServiceProvider.GetService<IOptions<RedisOptions>>()
|
.GetDatabase(ServiceProvider.GetService<IOptions<RedisOptions>>()
|
||||||
.Value.Instances
|
.Value.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
|
||||||
.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
|
|
||||||
.Database);
|
.Database);
|
||||||
return RedisLocker.GetLockerAsync(db, lockId, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY)
|
return RedisLocker.GetLockerAsync(db, lockId, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
|
||||||
, Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
|
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@ namespace NetAdmin.Host.Controllers;
|
|||||||
/// 探针组件
|
/// 探针组件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiDescriptionSettings("Probe")]
|
[ApiDescriptionSettings("Probe")]
|
||||||
|
[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)]
|
||||||
public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, IService>, IService>
|
public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, IService>, IService>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -55,12 +56,7 @@ public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, I
|
|||||||
public IActionResult IsSystemSafetyStopped(int logTimeoutSeconds = 15)
|
public IActionResult IsSystemSafetyStopped(int logTimeoutSeconds = 15)
|
||||||
#pragma warning restore S3400, CA1822
|
#pragma warning restore S3400, CA1822
|
||||||
{
|
{
|
||||||
return new ContentResult {
|
return new ContentResult { Content = (DateTime.Now - GlobalStatic.LatestLogTime).TotalSeconds > logTimeoutSeconds ? "1" : "0" };
|
||||||
Content = (DateTime.Now - GlobalStatic.LatestLogTime).TotalSeconds >
|
|
||||||
logTimeoutSeconds
|
|
||||||
? "1"
|
|
||||||
: "0"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -82,4 +78,21 @@ public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, I
|
|||||||
SafetyShopHostMiddleware.Stop();
|
SafetyShopHostMiddleware.Stop();
|
||||||
return new OkResult();
|
return new OkResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止日志计数器
|
||||||
|
/// </summary>
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpGet]
|
||||||
|
#pragma warning disable CA1822
|
||||||
|
public ActionResult StopLogCounter(string token)
|
||||||
|
#pragma warning restore CA1822
|
||||||
|
{
|
||||||
|
if (token != GlobalStatic.SecretKey) {
|
||||||
|
return new UnauthorizedResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalStatic.LogCounterOff = true;
|
||||||
|
return new OkResult();
|
||||||
|
}
|
||||||
}
|
}
|
@ -17,23 +17,17 @@ public static class IMvcBuilderExtensions
|
|||||||
public static IMvcBuilder AddDefaultApiResultHandler(this IMvcBuilder me)
|
public static IMvcBuilder AddDefaultApiResultHandler(this IMvcBuilder me)
|
||||||
{
|
{
|
||||||
return me.AddInjectWithUnifyResult<DefaultApiResultHandler>(injectOptions => {
|
return me.AddInjectWithUnifyResult<DefaultApiResultHandler>(injectOptions => {
|
||||||
injectOptions.ConfigureSwaggerGen(
|
injectOptions.ConfigureSwaggerGen(genOptions => {
|
||||||
genOptions => {
|
|
||||||
// 替换自定义的EnumSchemaFilter,支持多语言Resx资源 (需将SpecificationDocumentSettings.EnableEnumSchemaFilter配置为false)
|
// 替换自定义的EnumSchemaFilter,支持多语言Resx资源 (需将SpecificationDocumentSettings.EnableEnumSchemaFilter配置为false)
|
||||||
genOptions
|
genOptions.SchemaFilter<SwaggerEnumSchemaFixer>();
|
||||||
.SchemaFilter<
|
|
||||||
SwaggerEnumSchemaFixer>();
|
// 枚举显示自身xml comment 而不是$ref原型引用
|
||||||
|
genOptions.UseInlineDefinitionsForEnums();
|
||||||
|
|
||||||
// 将程序集版本号与OpenApi版本号同步
|
// 将程序集版本号与OpenApi版本号同步
|
||||||
foreach (var doc in genOptions
|
foreach (var doc in genOptions.SwaggerGeneratorOptions.SwaggerDocs) {
|
||||||
.SwaggerGeneratorOptions
|
doc.Value.Version = FileVersionInfo
|
||||||
.SwaggerDocs) {
|
.GetVersionInfo(Assembly.GetEntryAssembly()!.Location)
|
||||||
doc.Value.Version
|
|
||||||
= FileVersionInfo
|
|
||||||
.GetVersionInfo(
|
|
||||||
Assembly
|
|
||||||
.GetEntryAssembly()!
|
|
||||||
.Location)
|
|
||||||
.ProductVersion;
|
.ProductVersion;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -12,8 +12,7 @@ public static class MethodInfoExtensions
|
|||||||
{
|
{
|
||||||
return serviceProvider.GetService<IActionDescriptorCollectionProvider>()
|
return serviceProvider.GetService<IActionDescriptorCollectionProvider>()
|
||||||
.ActionDescriptors.Items.FirstOrDefault(x => x.DisplayName!.StartsWith( //
|
.ActionDescriptors.Items.FirstOrDefault(x => x.DisplayName!.StartsWith( //
|
||||||
$"{me.DeclaringType}.{me.Name}"
|
$"{me.DeclaringType}.{me.Name}", StringComparison.Ordinal))
|
||||||
, StringComparison.Ordinal))
|
|
||||||
?.AttributeRouteInfo?.Template;
|
?.AttributeRouteInfo?.Template;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -90,8 +90,8 @@ public static class ServiceCollectionExtensions
|
|||||||
var sbLog = new StringBuilder();
|
var sbLog = new StringBuilder();
|
||||||
foreach (var type in optionsTypes) {
|
foreach (var type in optionsTypes) {
|
||||||
var configureMethod = typeof(ConfigurableOptionsServiceCollectionExtensions).GetMethod(
|
var configureMethod = typeof(ConfigurableOptionsServiceCollectionExtensions).GetMethod(
|
||||||
nameof(ConfigurableOptionsServiceCollectionExtensions.AddConfigurableOptions)
|
nameof(ConfigurableOptionsServiceCollectionExtensions.AddConfigurableOptions), BindingFlags.Public | BindingFlags.Static
|
||||||
, BindingFlags.Public | BindingFlags.Static, [typeof(IServiceCollection)]);
|
, [typeof(IServiceCollection)]);
|
||||||
_ = configureMethod!.MakeGenericMethod(type).Invoke(me, [me]);
|
_ = configureMethod!.MakeGenericMethod(type).Invoke(me, [me]);
|
||||||
_ = sbLog.Append(CultureInfo.InvariantCulture, $" {type.Name}");
|
_ = sbLog.Append(CultureInfo.InvariantCulture, $" {type.Name}");
|
||||||
}
|
}
|
||||||
@ -146,36 +146,32 @@ public static class ServiceCollectionExtensions
|
|||||||
/// 添加 freeSql orm工具
|
/// 添加 freeSql orm工具
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IServiceCollection AddFreeSql( //
|
public static IServiceCollection AddFreeSql( //
|
||||||
this IServiceCollection me, FreeSqlInitMethods initMethods = FreeSqlInitMethods.None
|
this IServiceCollection me, FreeSqlInitMethods initMethods = FreeSqlInitMethods.None, Action<IFreeSql> freeSqlConfig = null)
|
||||||
, Action<IFreeSql> freeSqlConfig = null)
|
|
||||||
{
|
{
|
||||||
// // 非调试模式下禁止同步数据库
|
// // 非调试模式下禁止同步数据库
|
||||||
// #if !DEBUG
|
// #if !DEBUG
|
||||||
// initOptions = FreeSqlInitOptions.None;
|
// initOptions = FreeSqlInitOptions.None;
|
||||||
// #endif
|
// #endif
|
||||||
var freeSql = new FreeSqlBuilder(App.GetOptions<DatabaseOptions>()).Build(initMethods);
|
var dbOptions = App.GetOptions<DatabaseOptions>();
|
||||||
_ = me.AddSingleton(freeSql);
|
var fSql = new FreeSqlBuilder(dbOptions).Build(initMethods);
|
||||||
|
_ = me.AddSingleton(fSql);
|
||||||
|
|
||||||
freeSql.Aop.AuditValue += SqlAuditor.DataAuditHandler; // Insert/Update自动值处理
|
fSql.Aop.AuditValue += SqlAuditor.DataAuditHandler; // Insert/Update自动值处理
|
||||||
var eventPublisher = App.GetService<IEventPublisher>();
|
var eventPublisher = App.GetService<IEventPublisher>();
|
||||||
|
|
||||||
#pragma warning disable VSTHRD110
|
#pragma warning disable VSTHRD110
|
||||||
|
|
||||||
// AOP事件发布(异步)
|
// AOP事件发布(异步)
|
||||||
freeSql.Aop.CommandBefore
|
fSql.Aop.CommandBefore += (_, e) => eventPublisher.PublishAsync(new SqlCommandBeforeEvent(e)); // 增删查改,执行命令之前触发
|
||||||
+= (_, e) => eventPublisher.PublishAsync(new SqlCommandBeforeEvent(e)); // 增删查改,执行命令之前触发
|
fSql.Aop.CommandAfter += (_, e) => eventPublisher.PublishAsync(new SqlCommandAfterEvent(e)); // 增删查改,执行命令完成后触发
|
||||||
freeSql.Aop.CommandAfter
|
|
||||||
+= (_, e) => eventPublisher.PublishAsync(new SqlCommandAfterEvent(e)); // 增删查改,执行命令完成后触发
|
|
||||||
|
|
||||||
freeSql.Aop.SyncStructureBefore += (_, e) =>
|
fSql.Aop.SyncStructureBefore += (_, e) => eventPublisher.PublishAsync(new SyncStructureBeforeEvent(e)); // CodeFirst迁移,执行之前触发
|
||||||
eventPublisher.PublishAsync(new SyncStructureBeforeEvent(e)); // CodeFirst迁移,执行之前触发
|
|
||||||
|
|
||||||
freeSql.Aop.SyncStructureAfter += (_, e) =>
|
fSql.Aop.SyncStructureAfter += (_, e) => eventPublisher.PublishAsync(new SyncStructureAfterEvent(e)); // CodeFirst迁移,执行完成触发
|
||||||
eventPublisher.PublishAsync(new SyncStructureAfterEvent(e)); // CodeFirst迁移,执行完成触发
|
|
||||||
#pragma warning restore VSTHRD110
|
#pragma warning restore VSTHRD110
|
||||||
|
|
||||||
// 全局过滤器设置
|
// 全局过滤器设置
|
||||||
freeSqlConfig?.Invoke(freeSql);
|
freeSqlConfig?.Invoke(fSql);
|
||||||
|
|
||||||
return me.AddScoped<UnitOfWorkManager>() // 注入工作单元管理器
|
return me.AddScoped<UnitOfWorkManager>() // 注入工作单元管理器
|
||||||
.AddFreeRepository(null, App.Assemblies.ToArray()) // 批量注入 Repository
|
.AddFreeRepository(null, App.Assemblies.ToArray()) // 批量注入 Repository
|
||||||
@ -209,8 +205,7 @@ public static class ServiceCollectionExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static IServiceCollection AddRedisCache(this IServiceCollection me)
|
public static IServiceCollection AddRedisCache(this IServiceCollection me)
|
||||||
{
|
{
|
||||||
var redisOptions = App.GetOptions<RedisOptions>()
|
var redisOptions = App.GetOptions<RedisOptions>().Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE);
|
||||||
.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE);
|
|
||||||
|
|
||||||
// IDistributedCache 分布式缓存通用接口
|
// IDistributedCache 分布式缓存通用接口
|
||||||
_ = me.AddStackExchangeRedisCache(options => {
|
_ = me.AddStackExchangeRedisCache(options => {
|
||||||
|
@ -64,8 +64,7 @@ public abstract class ApiResultHandler<T>
|
|||||||
{
|
{
|
||||||
SetErrorCodeToHeader(context.HttpContext, ErrorCodes.InvalidInput);
|
SetErrorCodeToHeader(context.HttpContext, ErrorCodes.InvalidInput);
|
||||||
|
|
||||||
return new JsonResult(RestfulResult(ErrorCodes.InvalidInput, metadata.Data
|
return new JsonResult(RestfulResult(ErrorCodes.InvalidInput, metadata.Data, GetValidationResult(metadata.ValidationResult))) {
|
||||||
, GetValidationResult(metadata.ValidationResult))) {
|
|
||||||
StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL
|
StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,7 @@ public sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logge
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将异常设置到HttpContext.Features中 以便中间件能获取到他
|
// 将异常设置到HttpContext.Features中 以便中间件能获取到他
|
||||||
context.HttpContext.Features.Set<IExceptionHandlerFeature>(
|
context.HttpContext.Features.Set<IExceptionHandlerFeature>(new ExceptionHandlerFeature { Error = context.Exception });
|
||||||
new ExceptionHandlerFeature { Error = context.Exception });
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@ public sealed class TransactionInterceptor(UnitOfWorkManager uowManager) : IAsyn
|
|||||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
{
|
{
|
||||||
// 跳过没有事务特性标记的方法
|
// 跳过没有事务特性标记的方法
|
||||||
if (context.HttpContext.GetControllerActionDescriptor().MethodInfo.GetCustomAttribute<TransactionAttribute>() ==
|
if (context.HttpContext.GetControllerActionDescriptor().MethodInfo.GetCustomAttribute<TransactionAttribute>() == null) {
|
||||||
null) {
|
|
||||||
_ = await next().ConfigureAwait(false);
|
_ = await next().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,9 @@ public sealed class RequestAuditMiddleware(
|
|||||||
, IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions
|
, IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions
|
||||||
, RequestLogger requestLogger)
|
, RequestLogger requestLogger)
|
||||||
{
|
{
|
||||||
private readonly PathString _defaultRoutePrefix
|
private readonly PathString _defaultRoutePrefix = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
|
||||||
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
|
|
||||||
|
|
||||||
private readonly PathString _healthCheckRoutePrefix
|
private readonly PathString _healthCheckRoutePrefix = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/probe/health.check");
|
||||||
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/probe/health.check");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主函数
|
/// 主函数
|
||||||
@ -25,8 +23,7 @@ public sealed class RequestAuditMiddleware(
|
|||||||
if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求
|
if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求
|
||||||
|| context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查
|
|| context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查
|
||||||
|| context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS // is options 请求
|
|| context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS // is options 请求
|
||||||
|| (context.Request.ContentType?.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) ??
|
|| (context.Request.ContentType?.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) ?? false) // 文件上传
|
||||||
false) // 文件上传
|
|
||||||
#pragma warning disable SA1009
|
#pragma warning disable SA1009
|
||||||
) {
|
) {
|
||||||
#pragma warning restore SA1009
|
#pragma warning restore SA1009
|
||||||
@ -58,8 +55,6 @@ public sealed class RequestAuditMiddleware(
|
|||||||
.FirstOrDefault()
|
.FirstOrDefault()
|
||||||
?.Enum<ErrorCodes>() ?? 0;
|
?.Enum<ErrorCodes>() ?? 0;
|
||||||
|
|
||||||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode
|
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode, exception).ConfigureAwait(false);
|
||||||
, exception)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -53,8 +53,8 @@ public sealed class SafetyShopHostMiddleware(RequestDelegate next)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
if (Volatile.Read(ref _trafficOff) &&
|
if (Volatile.Read(ref _trafficOff) && !context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_RPOBE}") &&
|
||||||
!context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_RPOBE}")) {
|
!context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_METRICS}")) {
|
||||||
context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
|
context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<ProjectReference Include="../NetAdmin.Cache/NetAdmin.Cache.csproj"/>
|
<ProjectReference Include="../NetAdmin.Cache/NetAdmin.Cache.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns2"/>
|
<PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns3"/>
|
||||||
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.179"/>
|
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.179"/>
|
||||||
<PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/>
|
<PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -29,9 +29,7 @@ public abstract class Startup : AppStartup
|
|||||||
private static void ShowBanner()
|
private static void ShowBanner()
|
||||||
{
|
{
|
||||||
AnsiConsole.WriteLine();
|
AnsiConsole.WriteLine();
|
||||||
var gridInfo = new Grid().AddColumn(new GridColumn().NoWrap().Width(50).PadRight(10))
|
var gridInfo = new Grid().AddColumn(new GridColumn().NoWrap().Width(50).PadRight(10)).AddColumn(new GridColumn().NoWrap()).Expand();
|
||||||
.AddColumn(new GridColumn().NoWrap())
|
|
||||||
.Expand();
|
|
||||||
foreach (var kv in ApplicationHelper.GetEnvironmentInfo().OrderBy(x => x.Key)) {
|
foreach (var kv in ApplicationHelper.GetEnvironmentInfo().OrderBy(x => x.Key)) {
|
||||||
_ = gridInfo.AddRow(kv.Key, kv.Value.ToString()!.EscapeMarkup());
|
_ = gridInfo.AddRow(kv.Key, kv.Value.ToString()!.EscapeMarkup());
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,7 @@ public sealed class CollectionJsonTypeInfoResolver : DefaultJsonTypeInfoResolver
|
|||||||
|
|
||||||
private static string GetMemberName(JsonPropertyInfo property)
|
private static string GetMemberName(JsonPropertyInfo property)
|
||||||
{
|
{
|
||||||
return property.GetType()
|
return property.GetType().GetRuntimeProperties().First(x => x.Name == "MemberName").GetValue(property) as string;
|
||||||
.GetRuntimeProperties()
|
|
||||||
.First(x => x.Name == "MemberName")
|
|
||||||
.GetValue(property) as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,10 +46,7 @@ public sealed class CollectionJsonTypeInfoResolver : DefaultJsonTypeInfoResolver
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static PropertyInfo GetNewProperty(string memberName, object obj)
|
private static PropertyInfo GetNewProperty(string memberName, object obj)
|
||||||
{
|
{
|
||||||
return obj.GetType()
|
return obj.GetType().GetProperties().Where(x => x.Name == memberName).First(x => x.DeclaringType == x.ReflectedType);
|
||||||
.GetProperties()
|
|
||||||
.Where(x => x.Name == memberName)
|
|
||||||
.First(x => x.DeclaringType == x.ReflectedType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -17,15 +17,14 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成审计数据
|
/// 生成审计数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<CreateRequestLogReq> LogAsync(HttpContext context, long duration, string responseBody
|
public async Task<CreateRequestLogReq> LogAsync(HttpContext context, long duration, string responseBody, ErrorCodes errorCode
|
||||||
, ErrorCodes errorCode, IExceptionHandlerFeature exception)
|
, IExceptionHandlerFeature exception)
|
||||||
{
|
{
|
||||||
// 从请求头中读取用户信息
|
// 从请求头中读取用户信息
|
||||||
var associatedUser = GetAssociatedUser(context);
|
var associatedUser = GetAssociatedUser(context);
|
||||||
var id = YitIdHelper.NextId();
|
var id = YitIdHelper.NextId();
|
||||||
var requestBody = Array.Exists( //
|
var requestBody = Array.Exists( //
|
||||||
_textContentTypes
|
_textContentTypes, x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
, x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
|
|
||||||
? await context.ReadBodyContentAsync().ConfigureAwait(false)
|
? await context.ReadBodyContentAsync().ConfigureAwait(false)
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
var apiId = context.Request.Path.Value!.TrimStart('/');
|
var apiId = context.Request.Path.Value!.TrimStart('/');
|
||||||
|
@ -29,10 +29,14 @@ public sealed class SwaggerEnumSchemaFixer : ISchemaFilter
|
|||||||
foreach (var e in Enum.GetValues(context.Type).Cast<Enum>()) {
|
foreach (var e in Enum.GetValues(context.Type).Cast<Enum>()) {
|
||||||
var value = Convert.ToInt64(e, CultureInfo.InvariantCulture);
|
var value = Convert.ToInt64(e, CultureInfo.InvariantCulture);
|
||||||
schema.Enum.Add(new OpenApiLong(value));
|
schema.Enum.Add(new OpenApiLong(value));
|
||||||
|
var enumName = Enum.GetName(context.Type, e).ToLowerCamelCase();
|
||||||
|
if (enumName.Length <= 3) {
|
||||||
|
enumName = enumName.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
_ = sb.Append(wrap)
|
_ = sb.Append(wrap)
|
||||||
.Append( //
|
.Append( //
|
||||||
CultureInfo.InvariantCulture
|
CultureInfo.InvariantCulture, $"{enumName} = {value} ({e.ResDesc<Ln>()})");
|
||||||
, $"{Enum.GetName(context.Type, e).ToLowerCamelCase()} = {value} ({e.ResDesc<Ln>()})");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.Description = sb.ToString();
|
schema.Description = sb.ToString();
|
||||||
|
@ -13,8 +13,7 @@ public sealed record CaptchaOptions : OptionAbstraction
|
|||||||
{
|
{
|
||||||
var rtn = new char[32];
|
var rtn = new char[32];
|
||||||
for (var i = 0; i != 32; i++) {
|
for (var i = 0; i != 32; i++) {
|
||||||
rtn[i] = Chars.FLGL_VISIBLE_ASCIIS[
|
rtn[i] = Chars.FLGL_VISIBLE_ASCIIS[(int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLGL_VISIBLE_ASCIIS.Length)];
|
||||||
(int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLGL_VISIBLE_ASCIIS.Length)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SecretKey = new string(rtn);
|
SecretKey = new string(rtn);
|
||||||
|
@ -73,6 +73,7 @@ public static class Chars
|
|||||||
public const string FLG_HTTP_METHOD_POST = "POST";
|
public const string FLG_HTTP_METHOD_POST = "POST";
|
||||||
public const string FLG_HTTP_METHOD_PUT = "PUT";
|
public const string FLG_HTTP_METHOD_PUT = "PUT";
|
||||||
public const string FLG_HTTP_METHOD_TRACE = "TRACE";
|
public const string FLG_HTTP_METHOD_TRACE = "TRACE";
|
||||||
|
public const string FLG_PATH_API_METRICS = "metrics";
|
||||||
|
|
||||||
public const string FLG_PATH_API_RPOBE = "api/probe";
|
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_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd";
|
||||||
@ -89,8 +90,7 @@ public static class Chars
|
|||||||
public const string FLGL_HTTP_HEADER_VALUE_UA_PC
|
public const string FLGL_HTTP_HEADER_VALUE_UA_PC
|
||||||
= "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
|
= "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
|
||||||
|
|
||||||
public const string FLGL_VISIBLE_ASCIIS
|
public const string FLGL_VISIBLE_ASCIIS = """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
|
||||||
= """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
|
|
||||||
|
|
||||||
public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$";
|
public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$";
|
||||||
public const string RGX_INVITE_CODE = """^\d{8}$""";
|
public const string RGX_INVITE_CODE = """^\d{8}$""";
|
||||||
@ -112,6 +112,5 @@ public static class Chars
|
|||||||
public const string RGXL_EMAIL
|
public const string RGXL_EMAIL
|
||||||
= """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$""";
|
= """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$""";
|
||||||
|
|
||||||
public const string RGXL_IP_V4
|
public const string RGXL_IP_V4 = @"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$";
|
||||||
= @"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$";
|
|
||||||
}
|
}
|
@ -23,7 +23,7 @@ public static class Numbers
|
|||||||
public const int MAX_LIMIT_QUERY_PAGE_SIZE = 100; // 最大限制:分页查询页容量
|
public const int MAX_LIMIT_QUERY_PAGE_SIZE = 100; // 最大限制:分页查询页容量
|
||||||
public const int MAX_LIMIT_RETRY_CNT_REDIS_LOCK = 10; // 最大限制:Redis锁重试次数
|
public const int MAX_LIMIT_RETRY_CNT_REDIS_LOCK = 10; // 最大限制:Redis锁重试次数
|
||||||
public const int REQUEST_LOG_BUFF_SIZE = 10; // 请求日志缓冲区大小
|
public const int REQUEST_LOG_BUFF_SIZE = 10; // 请求日志缓冲区大小
|
||||||
|
public const int SCHEDULED_JOB_PARALLEL_NUM = 5; // 计划作业并发数
|
||||||
public const int SECS_CACHE_CHART = 300; // 秒:缓存时间-仪表
|
public const int SECS_CACHE_CHART = 300; // 秒:缓存时间-仪表
|
||||||
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
|
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
|
||||||
public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码
|
public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码
|
||||||
|
@ -10,8 +10,7 @@ public static class HttpRequestPartExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置日志
|
/// 设置日志
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static HttpRequestPart SetLog<T>(this HttpRequestPart me, ILogger<T> logger
|
public static HttpRequestPart SetLog<T>(this HttpRequestPart me, ILogger<T> logger, Func<string, string> bodyHandle = null)
|
||||||
, Func<string, string> bodyHandle = null)
|
|
||||||
{
|
{
|
||||||
return me.OnRequesting(RequestHandleAsync).OnResponsing(ResponseHandleAsync).OnException(ExceptionHandleAsync);
|
return me.OnRequesting(RequestHandleAsync).OnResponsing(ResponseHandleAsync).OnException(ExceptionHandleAsync);
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ public static class HttpResponseMessageExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录日志
|
/// 记录日志
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger
|
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger, Func<string, string> bodyPreHandle = null)
|
||||||
, Func<string, string> bodyPreHandle = null)
|
|
||||||
{
|
{
|
||||||
logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}");
|
logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}");
|
||||||
}
|
}
|
||||||
@ -30,10 +29,7 @@ public static class HttpResponseMessageExtensions
|
|||||||
this HttpResponseMessage me, Func<string, string> bodyHandle = null)
|
this HttpResponseMessage me, Func<string, string> bodyHandle = null)
|
||||||
{
|
{
|
||||||
var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false);
|
var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
return new {
|
return new { Header = me?.ToString(), RequestHeader = me?.RequestMessage?.Headers, Body = bodyHandle is null ? body : bodyHandle(body) }
|
||||||
Header = me?.ToString()
|
.Json();
|
||||||
, RequestHeader = me?.RequestMessage?.Headers
|
|
||||||
, Body = bodyHandle is null ? body : bodyHandle(body)
|
|
||||||
}.Json();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Numerics;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
|
|
||||||
@ -8,8 +9,80 @@ namespace NetAdmin.Infrastructure.Extensions;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
private const string _CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
private static readonly Regex _regexIpV4 = new(Chars.RGXL_IP_V4);
|
private static readonly Regex _regexIpV4 = new(Chars.RGXL_IP_V4);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将指定的输入字符串进行Base62解码
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentException">ArgumentException</exception>
|
||||||
|
public static string Base62Decode(this string me)
|
||||||
|
{
|
||||||
|
BigInteger result = 0;
|
||||||
|
|
||||||
|
foreach (var index in me.Select(c => _CHARACTERS.IndexOf(c))) {
|
||||||
|
if (index < 0) {
|
||||||
|
throw new ArgumentException("Invalid character in Base62 string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable IDE0048, RCS1123, SA1407
|
||||||
|
result = result * 62 + index;
|
||||||
|
#pragma warning restore SA1407, RCS1123, IDE0048
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert BigInteger back to byte array and then to string
|
||||||
|
var bytes = result.ToByteArray();
|
||||||
|
|
||||||
|
// Handle the sign bit
|
||||||
|
if (bytes[^1] == 0) {
|
||||||
|
Array.Resize(ref bytes, bytes.Length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将指定的输入字符串进行Base62编码
|
||||||
|
/// </summary>
|
||||||
|
public static string Base62Encode(this string me)
|
||||||
|
{
|
||||||
|
// Convert string to byte array
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(me);
|
||||||
|
|
||||||
|
// Convert byte array to BigInteger for easier processing
|
||||||
|
var bigInteger = new BigInteger(bytes);
|
||||||
|
|
||||||
|
if (bigInteger == 0) {
|
||||||
|
return _CHARACTERS[0].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new StringBuilder();
|
||||||
|
|
||||||
|
while (bigInteger > 0) {
|
||||||
|
var remainder = (int)(bigInteger % 62);
|
||||||
|
bigInteger /= 62;
|
||||||
|
_ = result.Insert(0, _CHARACTERS[remainder]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解码避免转义的Base64
|
||||||
|
/// </summary>
|
||||||
|
public static string Base64InUrlDecode(this string me)
|
||||||
|
{
|
||||||
|
return me.Replace("-", "+").Replace("_", "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编码避免转义的Base64
|
||||||
|
/// </summary>
|
||||||
|
public static string Base64InUrlEncode(this string me)
|
||||||
|
{
|
||||||
|
return me.Replace("+", "-").Replace("/", "_");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算Crc32
|
/// 计算Crc32
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -21,12 +94,10 @@ public static class StringExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行C#代码
|
/// 执行C#代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies
|
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies, params string[] importNamespaces)
|
||||||
, params string[] importNamespaces)
|
|
||||||
{
|
{
|
||||||
// 使用 Roslyn 编译并执行代码
|
// 使用 Roslyn 编译并执行代码
|
||||||
return CSharpScript.EvaluateAsync<T>(
|
return CSharpScript.EvaluateAsync<T>(me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
||||||
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -15,8 +15,7 @@ public static class GlobalStatic
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 产品版本
|
/// 产品版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string ProductVersion
|
public static readonly string ProductVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion;
|
||||||
= FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion;
|
|
||||||
|
|
||||||
private static long _latestLogTime;
|
private static long _latestLogTime;
|
||||||
|
|
||||||
@ -34,14 +33,12 @@ public static class GlobalStatic
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最后一次日志时间
|
/// 最后一次日志时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime LatestLogTime => Volatile.Read(ref _latestLogTime).Time();
|
public static DateTime LatestLogTime => LogCounterOff ? DateTime.MinValue : Volatile.Read(ref _latestLogTime).Time();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 日志记录器忽略的API编号
|
/// 日志记录器忽略的API编号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string[] LoggerIgnoreApiIds => [
|
public static string[] LoggerIgnoreApiIds => ["api/adm/tools/query.es.log", "api/probe/health.check", "api/probe/is.system.safety.stopped"];
|
||||||
"api/adm/tools/query.es.log", "api/probe/health.check", "api/probe/is.system.safety.stopped"
|
|
||||||
];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 系统内部密钥
|
/// 系统内部密钥
|
||||||
@ -88,6 +85,11 @@ public static class GlobalStatic
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static JsonSerializerOptions JsonSerializerOptions { get; set; }
|
public static JsonSerializerOptions JsonSerializerOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止更新日志时间
|
||||||
|
/// </summary>
|
||||||
|
public static bool LogCounterOff { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加日志计数器
|
/// 增加日志计数器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns4"/>
|
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns4"/>
|
||||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns4"/>
|
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns4"/>
|
||||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.2"/>
|
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.8"/>
|
||||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.5.2-ns1"/>
|
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.5.8-ns1"/>
|
||||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.5.2-ns1"/>
|
<PackageReference Include="Furion.Pure.NS" Version="4.9.5.8-ns1"/>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.10.0"/>
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.11.0"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.7.24406.2"/>
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-rc.2.24474.3"/>
|
||||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||||
<PackageReference Include="NSExt" Version="2.2.0"/>
|
<PackageReference Include="NSExt" Version="2.2.0"/>
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/>
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/>
|
||||||
|
@ -11,8 +11,7 @@ public static class ApplicationHelper
|
|||||||
public static Dictionary<string, object> GetEnvironmentInfo()
|
public static Dictionary<string, object> GetEnvironmentInfo()
|
||||||
{
|
{
|
||||||
var ret = typeof(Environment).GetProperties(BindingFlags.Public | BindingFlags.Static)
|
var ret = typeof(Environment).GetProperties(BindingFlags.Public | BindingFlags.Static)
|
||||||
.Where(x => x.Name is not (nameof(Environment.StackTrace)
|
.Where(x => x.Name is not (nameof(Environment.StackTrace) or nameof(Environment.NewLine)))
|
||||||
or nameof(Environment.NewLine)))
|
|
||||||
.ToDictionary(x => x.Name, x => x.GetValue(null));
|
.ToDictionary(x => x.Name, x => x.GetValue(null));
|
||||||
|
|
||||||
var vars = Environment.GetEnvironmentVariables();
|
var vars = Environment.GetEnvironmentVariables();
|
||||||
|
@ -26,15 +26,13 @@ public static class CaptchaImageHelper
|
|||||||
/// <returns> 背景图(base64),滑块图(base64),缺口坐标 </returns>
|
/// <returns> 背景图(base64),滑块图(base64),缺口坐标 </returns>
|
||||||
#pragma warning disable SA1414
|
#pragma warning disable SA1414
|
||||||
public static async Task<(string BackgroundImage, string SliderImage, Point OffsetSaw)> CreateSawSliderImageAsync(
|
public static async Task<(string BackgroundImage, string SliderImage, Point OffsetSaw)> CreateSawSliderImageAsync(
|
||||||
Assembly resAsm, string bgPath, string tempPath, (int, int) bgIndexScope, (int, int) tempIndexScope
|
Assembly resAsm, string bgPath, string tempPath, (int, int) bgIndexScope, (int, int) tempIndexScope, Size sliderSize)
|
||||||
, Size sliderSize)
|
|
||||||
#pragma warning restore SA1414
|
#pragma warning restore SA1414
|
||||||
{
|
{
|
||||||
// 深色模板图
|
// 深色模板图
|
||||||
var templateIndex = new[] { tempIndexScope.Item1, tempIndexScope.Item2 }.Rand();
|
var templateIndex = new[] { tempIndexScope.Item1, tempIndexScope.Item2 }.Rand();
|
||||||
|
|
||||||
await using var bgStream = resAsm.GetManifestResourceStream(
|
await using var bgStream = resAsm.GetManifestResourceStream($"{bgPath}.{new[] { bgIndexScope.Item1, bgIndexScope.Item2 }.Rand()}.jpg");
|
||||||
$"{bgPath}.{new[] { bgIndexScope.Item1, bgIndexScope.Item2 }.Rand()}.jpg");
|
|
||||||
await using var darkStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.dark.png");
|
await using var darkStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.dark.png");
|
||||||
await using var tranStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.transparent.png");
|
await using var tranStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.transparent.png");
|
||||||
|
|
||||||
@ -57,8 +55,7 @@ public static class CaptchaImageHelper
|
|||||||
using var sliderBlockImage = new Image<Rgba32>(sliderSize.Width, backgroundImage.Height);
|
using var sliderBlockImage = new Image<Rgba32>(sliderSize.Width, backgroundImage.Height);
|
||||||
|
|
||||||
// 随机生成拼图坐标
|
// 随机生成拼图坐标
|
||||||
var offsetRand = GeneratePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width
|
var offsetRand = GeneratePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width, sliderSize.Height);
|
||||||
, sliderSize.Height);
|
|
||||||
|
|
||||||
// 根据深色模板图计算轮廓形状
|
// 根据深色模板图计算轮廓形状
|
||||||
var blockShape = CalcBlockShape(darkTemplateImage);
|
var blockShape = CalcBlockShape(darkTemplateImage);
|
||||||
@ -84,16 +81,13 @@ public static class CaptchaImageHelper
|
|||||||
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(offsetRand.X, offsetRand.Y), opacity));
|
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(offsetRand.X, offsetRand.Y), opacity));
|
||||||
|
|
||||||
// 生成干扰图坐标
|
// 生成干扰图坐标
|
||||||
var interferencePoint = GenerateInterferencePoint(backgroundImage.Width, backgroundImage.Height
|
var interferencePoint = GenerateInterferencePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width, sliderSize.Height
|
||||||
, sliderSize.Width, sliderSize.Height, offsetRand.X
|
, offsetRand.X, offsetRand.Y);
|
||||||
, offsetRand.Y);
|
|
||||||
|
|
||||||
// 底图叠加深色干扰模板图
|
// 底图叠加深色干扰模板图
|
||||||
// ReSharper disable once AccessToDisposedClosure
|
// ReSharper disable once AccessToDisposedClosure
|
||||||
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y)
|
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y), opacity));
|
||||||
, opacity));
|
return (backgroundImage.ToBase64String(PngFormat.Instance), sliderBlockImage.ToBase64String(PngFormat.Instance), offsetRand);
|
||||||
return (backgroundImage.ToBase64String(PngFormat.Instance), sliderBlockImage.ToBase64String(PngFormat.Instance)
|
|
||||||
, offsetRand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int BuildPathList(Span<Rgba32> rowSpan, int temp, List<IPath> pathList, int y)
|
private static int BuildPathList(Span<Rgba32> rowSpan, int temp, List<IPath> pathList, int y)
|
||||||
@ -133,8 +127,8 @@ public static class CaptchaImageHelper
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 随机生成干扰图坐标
|
/// 随机生成干扰图坐标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Point GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth
|
private static Point GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight, int blockX
|
||||||
, int templateHeight, int blockX, int blockY)
|
, int blockY)
|
||||||
{
|
{
|
||||||
var x =
|
var x =
|
||||||
|
|
||||||
@ -166,9 +160,7 @@ public static class CaptchaImageHelper
|
|||||||
{
|
{
|
||||||
var widthDifference = originalWidth - templateWidth;
|
var widthDifference = originalWidth - templateWidth;
|
||||||
var heightDifference = originalHeight - templateHeight;
|
var heightDifference = originalHeight - templateHeight;
|
||||||
var x = widthDifference switch {
|
var x = widthDifference switch { <= 0 => 5, _ => new[] { 0, originalWidth - templateWidth - 100 }.Rand() + 100 };
|
||||||
<= 0 => 5, _ => new[] { 0, originalWidth - templateWidth - 100 }.Rand() + 100
|
|
||||||
};
|
|
||||||
|
|
||||||
var y = heightDifference switch { <= 0 => 5, _ => new[] { 0, originalHeight - templateHeight - 5 }.Rand() + 5 };
|
var y = heightDifference switch { <= 0 => 5, _ => new[] { 0, originalHeight - templateHeight - 5 }.Rand() + 5 };
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
|
|||||||
{
|
{
|
||||||
var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr)
|
var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr)
|
||||||
.UseGenerateCommandParameterWithLambda(true)
|
.UseGenerateCommandParameterWithLambda(true)
|
||||||
.UseAutoSyncStructure(
|
.UseAutoSyncStructure(initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
|
||||||
initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
|
|
||||||
.Build();
|
.Build();
|
||||||
_ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
|
_ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
|
||||||
return freeSql;
|
return freeSql;
|
||||||
@ -90,8 +89,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
|
|||||||
private void InsertSeedData(IFreeSql freeSql, IEnumerable<Type> entityTypes)
|
private void InsertSeedData(IFreeSql freeSql, IEnumerable<Type> entityTypes)
|
||||||
{
|
{
|
||||||
foreach (var entityType in entityTypes) {
|
foreach (var entityType in entityTypes) {
|
||||||
var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, databaseOptions.SeedDataRelativePath
|
var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, databaseOptions.SeedDataRelativePath, $"{entityType.Name}.json");
|
||||||
, $"{entityType.Name}.json");
|
|
||||||
if (!File.Exists(file)) {
|
if (!File.Exists(file)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -102,12 +100,8 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
|
|||||||
fileContent, typeof(IEnumerable<>).MakeGenericType(entityType));
|
fileContent, typeof(IEnumerable<>).MakeGenericType(entityType));
|
||||||
|
|
||||||
// 如果表存在数据,跳过
|
// 如果表存在数据,跳过
|
||||||
var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes)
|
var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes)?.MakeGenericMethod(entityType).Invoke(freeSql, null);
|
||||||
?.MakeGenericMethod(entityType)
|
if (select?.GetType().GetMethod(nameof(ISelect<dynamic>.Any), 0, Type.EmptyTypes)?.Invoke(select, null) as bool? ?? true) {
|
||||||
.Invoke(freeSql, null);
|
|
||||||
if (select?.GetType()
|
|
||||||
.GetMethod(nameof(ISelect<dynamic>.Any), 0, Type.EmptyTypes)
|
|
||||||
?.Invoke(select, null) as bool? ?? true) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,10 +1018,8 @@ public static class MimeTypeHelper
|
|||||||
zmm application/vnd.handheld-entertainment+xml
|
zmm application/vnd.handheld-entertainment+xml
|
||||||
""";
|
""";
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> _mimeTypeDic = _MIME_TYPES_RAW_STRING
|
private static readonly Dictionary<string, string> _mimeTypeDic = _MIME_TYPES_RAW_STRING.Split('\n', StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Split(
|
.ToDictionary( //
|
||||||
'\n', StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.ToDictionary(
|
|
||||||
x => x.Split(' ')[0].Trim()
|
x => x.Split(' ')[0].Trim()
|
||||||
, x => x.Split(' ')[1].Trim());
|
, x => x.Split(' ')[1].Trim());
|
||||||
|
|
||||||
|
@ -30,16 +30,15 @@ public sealed class RedisLocker : IAsyncDisposable
|
|||||||
/// 获取锁
|
/// 获取锁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception>
|
/// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception>
|
||||||
public static async Task<RedisLocker> GetLockerAsync(IDatabase redisDatabase, string lockerName
|
public static async Task<RedisLocker> GetLockerAsync(IDatabase redisDatabase, string lockerName, TimeSpan lockerExpire, int retryCount
|
||||||
, TimeSpan lockerExpire, int retryCount, TimeSpan retryDelay)
|
, TimeSpan retryDelay)
|
||||||
{
|
{
|
||||||
lockerName = $"{nameof(RedisLocker)}.{lockerName}";
|
lockerName = $"{nameof(RedisLocker)}.{lockerName}";
|
||||||
var setOk = false;
|
var setOk = false;
|
||||||
for (var i = 0; i != retryCount; ++i) {
|
for (var i = 0; i != retryCount; ++i) {
|
||||||
try {
|
try {
|
||||||
setOk = await redisDatabase
|
setOk = await redisDatabase
|
||||||
.StringSetAsync(lockerName, RedisValue.EmptyString, lockerExpire, When.NotExists
|
.StringSetAsync(lockerName, RedisValue.EmptyString, lockerExpire, When.NotExists, CommandFlags.DemandMaster)
|
||||||
, CommandFlags.DemandMaster)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
@ -60,8 +59,7 @@ public sealed class RedisLocker : IAsyncDisposable
|
|||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_ = await _redisDatabase.KeyDeleteAsync(_redisKey, CommandFlags.DemandMaster | CommandFlags.FireAndForget)
|
_ = await _redisDatabase.KeyDeleteAsync(_redisKey, CommandFlags.DemandMaster | CommandFlags.FireAndForget).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
LogHelper.Get<RedisLocker>().Error(ex.Message);
|
LogHelper.Get<RedisLocker>().Error(ex.Message);
|
||||||
|
@ -15,10 +15,7 @@ public sealed class UserAgentParser
|
|||||||
, { "Opera.*?Version", "Opera" }
|
, { "Opera.*?Version", "Opera" }
|
||||||
, { "Opera", "Opera" }
|
, { "Opera", "Opera" }
|
||||||
, { "MSIE", "Internet Explorer" }
|
, { "MSIE", "Internet Explorer" }
|
||||||
, {
|
, { "Internet Explorer", "Internet Explorer" }
|
||||||
"Internet Explorer"
|
|
||||||
, "Internet Explorer"
|
|
||||||
}
|
|
||||||
, { "Trident.* rv", "Internet Explorer" }
|
, { "Trident.* rv", "Internet Explorer" }
|
||||||
, { "Shiira", "Shiira" }
|
, { "Shiira", "Shiira" }
|
||||||
, { "Firefox", "Firefox" }
|
, { "Firefox", "Firefox" }
|
||||||
@ -73,10 +70,7 @@ public sealed class UserAgentParser
|
|||||||
, { "benq", "BenQ" }
|
, { "benq", "BenQ" }
|
||||||
, { "ipaq", "HP iPaq" }
|
, { "ipaq", "HP iPaq" }
|
||||||
, { "mot-", "Motorola" }
|
, { "mot-", "Motorola" }
|
||||||
, {
|
, { "playstation portable", "PlayStation Portable" }
|
||||||
"playstation portable"
|
|
||||||
, "PlayStation Portable"
|
|
||||||
}
|
|
||||||
, { "playstation 3", "PlayStation 3" }
|
, { "playstation 3", "PlayStation 3" }
|
||||||
, { "playstation vita", "PlayStation Vita" }
|
, { "playstation vita", "PlayStation Vita" }
|
||||||
, { "hiptop", "Danger Hiptop" }
|
, { "hiptop", "Danger Hiptop" }
|
||||||
@ -195,16 +189,10 @@ public sealed class UserAgentParser
|
|||||||
, { "infoseek", "InfoSeek Robot 1.0" }
|
, { "infoseek", "InfoSeek Robot 1.0" }
|
||||||
, { "lycos", "Lycos" }
|
, { "lycos", "Lycos" }
|
||||||
, { "yandex", "YandexBot" }
|
, { "yandex", "YandexBot" }
|
||||||
, {
|
, { "mediapartners-google", "MediaPartners Google" }
|
||||||
"mediapartners-google"
|
|
||||||
, "MediaPartners Google"
|
|
||||||
}
|
|
||||||
, { "CRAZYWEBCRAWLER", "Crazy Webcrawler" }
|
, { "CRAZYWEBCRAWLER", "Crazy Webcrawler" }
|
||||||
, { "adsbot-google", "AdsBot Google" }
|
, { "adsbot-google", "AdsBot Google" }
|
||||||
, {
|
, { "feedfetcher-google", "Feedfetcher Google" }
|
||||||
"feedfetcher-google"
|
|
||||||
, "Feedfetcher Google"
|
|
||||||
}
|
|
||||||
, { "curious george", "Curious George" }
|
, { "curious george", "Curious George" }
|
||||||
, { "ia_archiver", "Alexa Crawler" }
|
, { "ia_archiver", "Alexa Crawler" }
|
||||||
, { "MJ12bot", "Majestic-12" }
|
, { "MJ12bot", "Majestic-12" }
|
||||||
@ -316,8 +304,7 @@ public sealed class UserAgentParser
|
|||||||
private bool SetPlatform()
|
private bool SetPlatform()
|
||||||
{
|
{
|
||||||
var kv = _platforms.FirstOrDefault(x => //
|
var kv = _platforms.FirstOrDefault(x => //
|
||||||
Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}"
|
Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}", RegexOptions.IgnoreCase));
|
||||||
, RegexOptions.IgnoreCase));
|
|
||||||
|
|
||||||
if (kv.Key == null) {
|
if (kv.Key == null) {
|
||||||
Platform = "Unknown Platform";
|
Platform = "Unknown Platform";
|
||||||
|
@ -17,8 +17,7 @@ public sealed class XmlCommentReader : ISingleton
|
|||||||
public XmlCommentReader(IOptions<SpecificationDocumentSettingsOptions> specificationDocumentSettings)
|
public XmlCommentReader(IOptions<SpecificationDocumentSettingsOptions> specificationDocumentSettings)
|
||||||
{
|
{
|
||||||
var xmlComments = specificationDocumentSettings.Value.XmlComments //
|
var xmlComments = specificationDocumentSettings.Value.XmlComments //
|
||||||
?? App.GetConfig<SpecificationDocumentSettingsOptions>(
|
?? App.GetConfig<SpecificationDocumentSettingsOptions>(nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
|
||||||
nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
|
|
||||||
.XmlComments;
|
.XmlComments;
|
||||||
foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) {
|
foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) {
|
||||||
var xmlDoc = new XmlDocument();
|
var xmlDoc = new XmlDocument();
|
||||||
@ -40,9 +39,7 @@ public sealed class XmlCommentReader : ISingleton
|
|||||||
public string GetComments(MemberInfo memberInfo)
|
public string GetComments(MemberInfo memberInfo)
|
||||||
{
|
{
|
||||||
var node = memberInfo switch {
|
var node = memberInfo switch {
|
||||||
MethodInfo method => GetNodeByMethod(method)
|
MethodInfo method => GetNodeByMethod(method), Type type => GetNodeByType(type), _ => throw new InvalidCastException()
|
||||||
, Type type => GetNodeByType(type)
|
|
||||||
, _ => throw new InvalidCastException()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (node?.FirstChild?.Name != "inheritdoc") {
|
if (node?.FirstChild?.Name != "inheritdoc") {
|
||||||
@ -60,9 +57,7 @@ public sealed class XmlCommentReader : ISingleton
|
|||||||
return GetComments(methodFromBaseType);
|
return GetComments(methodFromBaseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
var methodFromInterface = memberInfo.DeclaringType?.GetInterfaces()
|
var methodFromInterface = memberInfo.DeclaringType?.GetInterfaces().Select(x => x.GetMethod(memberInfo.Name)).FirstOrDefault(x => x != null);
|
||||||
.Select(x => x.GetMethod(memberInfo.Name))
|
|
||||||
.FirstOrDefault(x => x != null);
|
|
||||||
return methodFromInterface == null ? null : GetComments(methodFromInterface);
|
return methodFromInterface == null ? null : GetComments(methodFromInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +77,7 @@ public sealed class XmlCommentReader : ISingleton
|
|||||||
|
|
||||||
static string Replace(ParameterInfo parameterInfo)
|
static string Replace(ParameterInfo parameterInfo)
|
||||||
{
|
{
|
||||||
return _regex.Replace(parameterInfo.ParameterType.ToString(), string.Empty)
|
return _regex.Replace(parameterInfo.ParameterType.ToString(), string.Empty).Replace("[", "{").Replace("]", "}");
|
||||||
.Replace("[", "{")
|
|
||||||
.Replace("]", "}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,4 +10,10 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
|||||||
public interface IDicContentModule : ICrudModule<CreateDicContentReq, QueryDicContentRsp // 创建类型
|
public interface IDicContentModule : ICrudModule<CreateDicContentReq, QueryDicContentRsp // 创建类型
|
||||||
, QueryDicContentReq, QueryDicContentRsp // 查询类型
|
, QueryDicContentReq, QueryDicContentRsp // 查询类型
|
||||||
, DelReq // 删除类型
|
, DelReq // 删除类型
|
||||||
>;
|
>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 启用/禁用字典内容
|
||||||
|
/// </summary>
|
||||||
|
Task<int> SetEnabledAsync(SetDicContentEnabledReq req);
|
||||||
|
}
|
@ -67,7 +67,7 @@ public interface IDicModule
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取字典值
|
/// 获取字典值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task<string> GetDicValueAsync(GetDicValueReq req);
|
Task<string> GetDicValueAsync(GetDicValueReq req);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分页查询字典目录
|
/// 分页查询字典目录
|
||||||
@ -88,4 +88,9 @@ public interface IDicModule
|
|||||||
/// 查询字典内容
|
/// 查询字典内容
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<IEnumerable<QueryDicContentRsp>> QueryContentAsync(QueryReq<QueryDicContentReq> req);
|
Task<IEnumerable<QueryDicContentRsp>> QueryContentAsync(QueryReq<QueryDicContentReq> req);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用/禁用字典内容
|
||||||
|
/// </summary>
|
||||||
|
Task<int> SetEnabledAsync(SetDicContentEnabledReq req);
|
||||||
}
|
}
|
@ -7,6 +7,11 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IToolsModule
|
public interface IToolsModule
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Aes解密
|
||||||
|
/// </summary>
|
||||||
|
string AesDecode(AesDecodeReq req);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行SQL语句
|
/// 执行SQL语句
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -81,10 +81,7 @@ public sealed class ApiService(
|
|||||||
public async Task<IEnumerable<QueryApiRsp>> QueryAsync(QueryReq<QueryApiReq> req)
|
public async Task<IEnumerable<QueryApiRsp>> QueryAsync(QueryReq<QueryApiReq> req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter)
|
var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter).ToTreeListAsync().ConfigureAwait(false);
|
||||||
.WhereDynamic(req.Filter)
|
|
||||||
.ToTreeListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<IEnumerable<QueryApiRsp>>();
|
return ret.Adapt<IEnumerable<QueryApiRsp>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,9 +143,7 @@ public sealed class ApiService(
|
|||||||
Summary = xmlCommentReader.GetComments(x.MethodInfo)
|
Summary = xmlCommentReader.GetComments(x.MethodInfo)
|
||||||
, Name = x.ActionName
|
, Name = x.ActionName
|
||||||
, Id = id
|
, Id = id
|
||||||
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>()
|
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods.First()
|
||||||
.FirstOrDefault()
|
|
||||||
?.HttpMethods.First()
|
|
||||||
, PathCrc32 = id.Crc32()
|
, PathCrc32 = id.Crc32()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -63,15 +63,12 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
|
|||||||
var server = connectionMultiplexer.GetServers()[0];
|
var server = connectionMultiplexer.GetServers()[0];
|
||||||
|
|
||||||
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
|
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
|
||||||
var keys = server.Keys(_redisInstance.Database, $"*{req.Keywords}*", Numbers.MAX_LIMIT_BULK_REQ)
|
var keys = server.Keys(_redisInstance.Database, $"*{req.Keywords}*", Numbers.MAX_LIMIT_BULK_REQ).Take(Numbers.MAX_LIMIT_BULK_REQ).ToList();
|
||||||
.Take(Numbers.MAX_LIMIT_BULK_REQ)
|
|
||||||
.ToList();
|
|
||||||
#pragma warning restore VSTHRD103
|
#pragma warning restore VSTHRD103
|
||||||
|
|
||||||
var dic = new ConcurrentDictionary<string, (DateTime?, RedisType)>();
|
var dic = new ConcurrentDictionary<string, (DateTime?, RedisType)>();
|
||||||
|
|
||||||
await Parallel
|
await Parallel.ForEachAsync(
|
||||||
.ForEachAsync(
|
|
||||||
keys
|
keys
|
||||||
, async (key, _) =>
|
, async (key, _) =>
|
||||||
dic.TryAdd(
|
dic.TryAdd(
|
||||||
@ -90,8 +87,7 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
|
|||||||
var ret = new GetEntryRsp {
|
var ret = new GetEntryRsp {
|
||||||
Type = await database.KeyTypeAsync(req.Key).ConfigureAwait(false)
|
Type = await database.KeyTypeAsync(req.Key).ConfigureAwait(false)
|
||||||
, Key = req.Key
|
, Key = req.Key
|
||||||
, ExpireTime = DateTime.Now +
|
, ExpireTime = DateTime.Now + await database.KeyTimeToLiveAsync(req.Key).ConfigureAwait(false)
|
||||||
await database.KeyTimeToLiveAsync(req.Key).ConfigureAwait(false)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma warning disable IDE0072
|
#pragma warning disable IDE0072
|
||||||
@ -101,10 +97,8 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
|
|||||||
RedisType.String => await database.StringGetAsync(req.Key).ConfigureAwait(false)
|
RedisType.String => await database.StringGetAsync(req.Key).ConfigureAwait(false)
|
||||||
, RedisType.List => string.Join(", ", await database.ListRangeAsync(req.Key).ConfigureAwait(false))
|
, RedisType.List => string.Join(", ", await database.ListRangeAsync(req.Key).ConfigureAwait(false))
|
||||||
, RedisType.Set => string.Join(", ", await database.SetMembersAsync(req.Key).ConfigureAwait(false))
|
, RedisType.Set => string.Join(", ", await database.SetMembersAsync(req.Key).ConfigureAwait(false))
|
||||||
, RedisType.SortedSet =>
|
, RedisType.SortedSet => string.Join(", ", await database.SortedSetRangeByRankAsync(req.Key).ConfigureAwait(false))
|
||||||
string.Join(", ", await database.SortedSetRangeByRankAsync(req.Key).ConfigureAwait(false))
|
, RedisType.Hash => string.Join(", ", await database.HashGetAllAsync(req.Key).ConfigureAwait(false))
|
||||||
, RedisType.Hash => string.Join(
|
|
||||||
", ", await database.HashGetAllAsync(req.Key).ConfigureAwait(false))
|
|
||||||
, _ => "Unsupported key type"
|
, _ => "Unsupported key type"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,17 +21,13 @@ public sealed class CaptchaService : ServiceBase<ICaptchaService>, ICaptchaServi
|
|||||||
public async Task<GetCaptchaRsp> GetCaptchaImageAsync()
|
public async Task<GetCaptchaRsp> GetCaptchaImageAsync()
|
||||||
{
|
{
|
||||||
var (backgroundImage, sliderImage, offsetSaw) = await CaptchaImageHelper.CreateSawSliderImageAsync(
|
var (backgroundImage, sliderImage, offsetSaw) = await CaptchaImageHelper.CreateSawSliderImageAsync(
|
||||||
_entryAsm, $"{_entryAsmName}.Assets.Captcha.background", $"{_entryAsmName}.Assets.Captcha.template"
|
_entryAsm, $"{_entryAsmName}.Assets.Captcha.background"
|
||||||
, (1, 101), (1, 7), new Size(50, 50))
|
, $"{_entryAsmName}.Assets.Captcha.template", (1, 101), (1, 7)
|
||||||
|
, new Size(50, 50))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var id = $"{nameof(GetCaptchaImageAsync)}_{YitIdHelper.NextId()}";
|
var id = $"{nameof(GetCaptchaImageAsync)}_{YitIdHelper.NextId()}";
|
||||||
return new GetCaptchaRsp {
|
return new GetCaptchaRsp { Id = id, BackgroundImage = backgroundImage, SliderImage = sliderImage, SawOffsetX = offsetSaw.X };
|
||||||
Id = id
|
|
||||||
, BackgroundImage = backgroundImage
|
|
||||||
, SliderImage = sliderImage
|
|
||||||
, SawOffsetX = offsetSaw.X
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -84,18 +84,14 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
|
|||||||
public async Task<QueryConfigRsp> GetAsync(QueryConfigReq req)
|
public async Task<QueryConfigRsp> GetAsync(QueryConfigReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryConfigReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryConfigReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryConfigRsp>();
|
return ret.Adapt<QueryConfigRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<QueryConfigRsp> GetLatestConfigAsync()
|
public async Task<QueryConfigRsp> GetLatestConfigAsync()
|
||||||
{
|
{
|
||||||
var ret = await QueryAsync(
|
var ret = await QueryAsync(new QueryReq<QueryConfigReq> { Count = 1, Filter = new QueryConfigReq { Enabled = true } }).ConfigureAwait(false);
|
||||||
new QueryReq<QueryConfigReq> { Count = 1, Filter = new QueryConfigReq { Enabled = true } })
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.FirstOrDefault();
|
return ret.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,8 +108,7 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new PagedQueryRsp<QueryConfigRsp>(req.Page, req.PageSize, total
|
return new PagedQueryRsp<QueryConfigRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryConfigRsp>>());
|
||||||
, list.Adapt<IEnumerable<QueryConfigRsp>>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -26,19 +26,13 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
|
|||||||
var httpStatusCodes = Enum.GetNames<HttpStatusCode>().ToDictionary(x => x, GetHttpStatusCodeDicValue);
|
var httpStatusCodes = Enum.GetNames<HttpStatusCode>().ToDictionary(x => x, GetHttpStatusCodeDicValue);
|
||||||
httpStatusCodes.Add( //
|
httpStatusCodes.Add( //
|
||||||
nameof(ErrorCodes.Unhandled)
|
nameof(ErrorCodes.Unhandled)
|
||||||
, [
|
, [Numbers.HTTP_STATUS_BIZ_FAIL.ToInvString(), nameof(ErrorCodes.Unhandled), nameof(Indicates.Danger).ToLowerInvariant()]);
|
||||||
Numbers.HTTP_STATUS_BIZ_FAIL.ToInvString(), nameof(ErrorCodes.Unhandled)
|
|
||||||
, nameof(Indicates.Danger).ToLowerInvariant()
|
|
||||||
]);
|
|
||||||
ret.Add($"{nameof(HttpStatusCode)}s", httpStatusCodes);
|
ret.Add($"{nameof(HttpStatusCode)}s", httpStatusCodes);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
static string[] GetDicValue(Enum y)
|
static string[] GetDicValue(Enum y)
|
||||||
{
|
{
|
||||||
var ret = new[] {
|
var ret = new[] { Convert.ToInt64(y, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture), y.ResDesc<Ln>() };
|
||||||
Convert.ToInt64(y, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture)
|
|
||||||
, y.ResDesc<Ln>()
|
|
||||||
};
|
|
||||||
var indicate = y.GetAttributeOfType<IndicatorAttribute>()?.Indicate.ToLowerInvariant();
|
var indicate = y.GetAttributeOfType<IndicatorAttribute>()?.Indicate.ToLowerInvariant();
|
||||||
return indicate.NullOrEmpty() ? ret : [..ret, indicate];
|
return indicate.NullOrEmpty() ? ret : [..ret, indicate];
|
||||||
}
|
}
|
||||||
@ -48,11 +42,8 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
|
|||||||
var codeInt = Convert.ToInt64(Enum.Parse<HttpStatusCode>(name), CultureInfo.InvariantCulture);
|
var codeInt = Convert.ToInt64(Enum.Parse<HttpStatusCode>(name), CultureInfo.InvariantCulture);
|
||||||
return [
|
return [
|
||||||
codeInt.ToString(CultureInfo.InvariantCulture), name
|
codeInt.ToString(CultureInfo.InvariantCulture), name
|
||||||
, (codeInt switch {
|
, (codeInt switch { >= 200 and < 300 => nameof(Indicates.Success), < 400 => nameof(Indicates.Warning), _ => nameof(Indicates.Danger) })
|
||||||
>= 200 and < 300 => nameof(Indicates.Success)
|
.ToLowerInvariant()
|
||||||
, < 400 => nameof(Indicates.Warning)
|
|
||||||
, _ => nameof(Indicates.Danger)
|
|
||||||
}).ToLowerInvariant()
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,9 +74,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
|
|||||||
#if DBTYPE_SQLSERVER
|
#if DBTYPE_SQLSERVER
|
||||||
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>();
|
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>();
|
||||||
#else
|
#else
|
||||||
return await UpdateAsync(req, null).ConfigureAwait(false) > 0
|
return await UpdateAsync(req, null).ConfigureAwait(false) > 0 ? await GetAsync(new QueryDeptReq { Id = req.Id }).ConfigureAwait(false) : null;
|
||||||
? await GetAsync(new QueryDeptReq { Id = req.Id }).ConfigureAwait(false)
|
|
||||||
: null;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,9 +100,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
|
|||||||
public async Task<QueryDeptRsp> GetAsync(QueryDeptReq req)
|
public async Task<QueryDeptRsp> GetAsync(QueryDeptReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryDeptReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryDeptReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryDeptRsp>();
|
return ret.Adapt<QueryDeptRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +141,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
|
|||||||
.WhereDynamic(req.Filter)
|
.WhereDynamic(req.Filter)
|
||||||
.WhereIf( //
|
.WhereIf( //
|
||||||
req.Keywords?.Length > 0
|
req.Keywords?.Length > 0
|
||||||
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) ||
|
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) || a.Summary.Contains(req.Keywords));
|
||||||
a.Summary.Contains(req.Keywords));
|
|
||||||
if (asTreeCte) {
|
if (asTreeCte) {
|
||||||
ret = ret.AsTreeCte();
|
ret = ret.AsTreeCte();
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
private static readonly string _clientProjectPath = Path.Combine( //
|
private static readonly string _clientProjectPath = Path.Combine( //
|
||||||
Environment.CurrentDirectory, "../../frontend/admin");
|
Environment.CurrentDirectory, "../../frontend/admin");
|
||||||
|
|
||||||
private static readonly string[] _projectDirs
|
private static readonly string[] _projectDirs = Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../"));
|
||||||
= Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../"));
|
|
||||||
|
|
||||||
private static readonly Regex _regex = new(@"\.(\w)");
|
private static readonly Regex _regex = new(@"\.(\w)");
|
||||||
private static readonly Regex _regex2 = new("([a-zA-Z]+):");
|
private static readonly Regex _regex2 = new("([a-zA-Z]+):");
|
||||||
@ -26,6 +25,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
|
|
||||||
// 模块类型(Sys、Adm、等)
|
// 模块类型(Sys、Adm、等)
|
||||||
var moduleType = Enum.GetName(req.Type)!;
|
var moduleType = Enum.GetName(req.Type)!;
|
||||||
|
var @namespace = req.Type.ToString();
|
||||||
|
|
||||||
// 模板层目录
|
// 模板层目录
|
||||||
var tplHostDir = GetDir("SysComponent.Host");
|
var tplHostDir = GetDir("SysComponent.Host");
|
||||||
@ -51,57 +51,57 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
var entityDir = Path.Combine(dataDir, "DbMaps", moduleType[..3]);
|
var entityDir = Path.Combine(dataDir, "DbMaps", moduleType[..3]);
|
||||||
|
|
||||||
// 创建缺少的目录
|
// 创建缺少的目录
|
||||||
CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir
|
CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir, appServicesDependencyDir, dataDir, dtoDir
|
||||||
, appServicesDependencyDir, dataDir, dtoDir, entityDir);
|
, entityDir);
|
||||||
|
|
||||||
// Controller
|
// Controller
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs")
|
||||||
, Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs"))
|
, Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// CreateReq
|
// CreateReq
|
||||||
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs")
|
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs")
|
||||||
, Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs"))
|
, Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// QueryReq
|
// QueryReq
|
||||||
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs")
|
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs")
|
||||||
, Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs"))
|
, Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// QueryRsp
|
// QueryRsp
|
||||||
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs")
|
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs")
|
||||||
, Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs"))
|
, Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// ICache
|
// ICache
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs")
|
||||||
, Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs"))
|
, Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs"), Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs")
|
||||||
, Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs"))
|
, @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// IModule
|
// IModule
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs")
|
||||||
, Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs"))
|
, Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// IService
|
// IService
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs")
|
||||||
, Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs"))
|
, Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// Service
|
// Service
|
||||||
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs")
|
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs")
|
||||||
, Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs"))
|
, Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// Entity
|
// Entity
|
||||||
await WriteCodeFileAsync(req, Path.Combine(dataDir, "DbMaps", "Tpl", "Tpl_Example.cs")
|
await WriteCodeFileAsync(req, Path.Combine(dataDir, "DbMaps", "Tpl", "Tpl_Example.cs")
|
||||||
, Path.Combine(entityDir, $"{moduleType[..3]}_{req.ModuleName}.cs"))
|
, Path.Combine(entityDir, $"{moduleType[..3]}_{req.ModuleName}.cs"), @namespace)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,12 +109,8 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
public async Task GenerateIconCodeAsync(GenerateIconCodeReq req)
|
public async Task GenerateIconCodeAsync(GenerateIconCodeReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var tplSvg = await File.ReadAllTextAsync(
|
var tplSvg = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue")).ConfigureAwait(false);
|
||||||
Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue"))
|
var tplExport = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "export.js"))
|
||||||
.ConfigureAwait(false);
|
|
||||||
var tplExport = await File
|
|
||||||
.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl"
|
|
||||||
, "export.js"))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty);
|
var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty);
|
||||||
@ -130,9 +126,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
var indexJsFile = Path.Combine(dir, "index.js");
|
var indexJsFile = Path.Combine(dir, "index.js");
|
||||||
|
|
||||||
await File.AppendAllTextAsync(
|
await File.AppendAllTextAsync(
|
||||||
indexJsFile
|
indexJsFile, Environment.NewLine + tplExport.Replace("$iconName$", req.IconName).Replace(_REPLACE_TO_EMPTY, string.Empty))
|
||||||
, Environment.NewLine +
|
|
||||||
tplExport.Replace("$iconName$", req.IconName).Replace(_REPLACE_TO_EMPTY, string.Empty))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// 修改iconSelect.js
|
// 修改iconSelect.js
|
||||||
@ -152,10 +146,8 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
public async Task GenerateJsCodeAsync()
|
public async Task GenerateJsCodeAsync()
|
||||||
{
|
{
|
||||||
// 模板文件
|
// 模板文件
|
||||||
var tplOuter = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "outer.js"))
|
var tplOuter = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "outer.js")).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
var tplInner = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "inner.js")).ConfigureAwait(false);
|
||||||
var tplInner = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "inner.js"))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var item in apiService.ReflectionList(false)) {
|
foreach (var item in apiService.ReflectionList(false)) {
|
||||||
var dir = Path.Combine(_clientProjectPath, "src", "api", item.Namespace);
|
var dir = Path.Combine(_clientProjectPath, "src", "api", item.Namespace);
|
||||||
@ -168,8 +160,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
var content = tplOuter.Replace("$controllerDesc$", item.Summary)
|
var content = tplOuter.Replace("$controllerDesc$", item.Summary)
|
||||||
.Replace("$controllerPath$", item.Id)
|
.Replace("$controllerPath$", item.Id)
|
||||||
.Replace( //
|
.Replace( //
|
||||||
"$inner$"
|
"$inner$", string.Join(Environment.NewLine + Environment.NewLine, Select(item)))
|
||||||
, string.Join(Environment.NewLine + Environment.NewLine, Select(item)))
|
|
||||||
.Replace(_REPLACE_TO_EMPTY, string.Empty);
|
.Replace(_REPLACE_TO_EMPTY, string.Empty);
|
||||||
|
|
||||||
await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
|
await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
|
||||||
@ -180,9 +171,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
{
|
{
|
||||||
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
|
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
|
||||||
.Replace( //
|
.Replace( //
|
||||||
"$actionName$"
|
"$actionName$", _regex.Replace(x.Name, y => y.Groups[1].Value.ToUpperInvariant()))
|
||||||
, _regex.Replace(
|
|
||||||
x.Name, y => y.Groups[1].Value.ToUpperInvariant()))
|
|
||||||
.Replace("$actionPath$", x.Id)
|
.Replace("$actionPath$", x.Id)
|
||||||
.Replace( //
|
.Replace( //
|
||||||
"$actionMethod$", x.Method?.ToLowerInvariant())
|
"$actionMethod$", x.Method?.ToLowerInvariant())
|
||||||
@ -204,13 +193,13 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
|||||||
return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture));
|
return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile)
|
private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile, string @namespace = "SysComponent")
|
||||||
{
|
{
|
||||||
var tplContent = await File.ReadAllTextAsync(tplFile).ConfigureAwait(false);
|
var tplContent = await File.ReadAllTextAsync(tplFile).ConfigureAwait(false);
|
||||||
tplContent = tplContent.Replace("Tpl", Enum.GetName(req.Type)![..3])
|
tplContent = tplContent.Replace("Tpl", Enum.GetName(req.Type)![..3])
|
||||||
.Replace("示例", req.ModuleRemark)
|
.Replace("示例", req.ModuleRemark)
|
||||||
.Replace("Example", req.ModuleName)
|
.Replace("Example", req.ModuleName)
|
||||||
.Replace("NetAdmin.SysComponent", "SysComponent");
|
.Replace("NetAdmin.SysComponent", $"NetAdmin.{@namespace}");
|
||||||
|
|
||||||
await File.WriteAllTextAsync(writeFile, tplContent).ConfigureAwait(false);
|
await File.WriteAllTextAsync(writeFile, tplContent).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,12 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
|||||||
public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req)
|
public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
if (req.ParentId != 0 &&
|
if (req.ParentId != 0 && !await Rpo.Where(a => a.Id == req.ParentId)
|
||||||
!await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false)) {
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
|
.AnyAsync()
|
||||||
|
.ConfigureAwait(false)) {
|
||||||
throw new NetAdminInvalidOperationException(Ln.父节点不存在);
|
throw new NetAdminInvalidOperationException(Ln.父节点不存在);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,8 +66,12 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
|||||||
public async Task<int> EditAsync(EditDicCatalogReq req)
|
public async Task<int> EditAsync(EditDicCatalogReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
return req.ParentId == 0 ||
|
return req.ParentId == 0 || await Rpo.Where(a => a.Id == req.ParentId)
|
||||||
await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false)
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
|
.AnyAsync()
|
||||||
|
.ConfigureAwait(false)
|
||||||
? await UpdateAsync(req, null).ConfigureAwait(false)
|
? await UpdateAsync(req, null).ConfigureAwait(false)
|
||||||
: throw new NetAdminInvalidOperationException(Ln.父节点不存在);
|
: throw new NetAdminInvalidOperationException(Ln.父节点不存在);
|
||||||
}
|
}
|
||||||
@ -89,9 +97,7 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
|||||||
public async Task<QueryDicCatalogRsp> GetAsync(QueryDicCatalogReq req)
|
public async Task<QueryDicCatalogRsp> GetAsync(QueryDicCatalogReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryDicCatalogReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryDicCatalogReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryDicCatalogRsp>();
|
return ret.Adapt<QueryDicCatalogRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,8 +114,7 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new PagedQueryRsp<QueryDicCatalogRsp>(req.Page, req.PageSize, total
|
return new PagedQueryRsp<QueryDicCatalogRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryDicCatalogRsp>>());
|
||||||
, list.Adapt<IEnumerable<QueryDicCatalogRsp>>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -42,7 +42,9 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
|||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
|
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
|
||||||
.Where(a => a.Id == req.CatalogId)
|
.Where(a => a.Id == req.CatalogId)
|
||||||
.ForUpdate()
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
.AnyAsync()
|
.AnyAsync()
|
||||||
.ConfigureAwait(false)) {
|
.ConfigureAwait(false)) {
|
||||||
throw new NetAdminInvalidOperationException(Ln.字典目录不存在);
|
throw new NetAdminInvalidOperationException(Ln.字典目录不存在);
|
||||||
@ -66,15 +68,16 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
|||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
|
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
|
||||||
.Where(a => a.Id == req.CatalogId)
|
.Where(a => a.Id == req.CatalogId)
|
||||||
.ForUpdate()
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
.AnyAsync()
|
.AnyAsync()
|
||||||
.ConfigureAwait(false)) {
|
.ConfigureAwait(false)) {
|
||||||
throw new NetAdminInvalidOperationException(Ln.字典目录不存在);
|
throw new NetAdminInvalidOperationException(Ln.字典目录不存在);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DBTYPE_SQLSERVER
|
#if DBTYPE_SQLSERVER
|
||||||
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()
|
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDicContentRsp>();
|
||||||
?.Adapt<QueryDicContentRsp>();
|
|
||||||
#else
|
#else
|
||||||
return await UpdateAsync(req, null).ConfigureAwait(false) > 0
|
return await UpdateAsync(req, null).ConfigureAwait(false) > 0
|
||||||
? await GetAsync(new QueryDicContentReq { Id = req.Id }).ConfigureAwait(false)
|
? await GetAsync(new QueryDicContentReq { Id = req.Id }).ConfigureAwait(false)
|
||||||
@ -104,9 +107,7 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
|||||||
public async Task<QueryDicContentRsp> GetAsync(QueryDicContentReq req)
|
public async Task<QueryDicContentRsp> GetAsync(QueryDicContentReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryDicContentReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryDicContentReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryDicContentRsp>();
|
return ret.Adapt<QueryDicContentRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +124,7 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new PagedQueryRsp<QueryDicContentRsp>(req.Page, req.PageSize, total
|
return new PagedQueryRsp<QueryDicContentRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryDicContentRsp>>());
|
||||||
, list.Adapt<IEnumerable<QueryDicContentRsp>>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -150,11 +150,19 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
|||||||
#endif
|
#endif
|
||||||
.Include(a => a.Catalog)
|
.Include(a => a.Catalog)
|
||||||
.Where(a => a.Catalog.Code == catalogCode)
|
.Where(a => a.Catalog.Code == catalogCode)
|
||||||
|
.Where(a => a.Enabled)
|
||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return ret.Adapt<List<QueryDicContentRsp>>();
|
return ret.Adapt<List<QueryDicContentRsp>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> SetEnabledAsync(SetDicContentEnabledReq req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return UpdateAsync(req, [nameof(Sys_DicContent.Enabled)]);
|
||||||
|
}
|
||||||
|
|
||||||
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
|
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
|
||||||
{
|
{
|
||||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||||
|
@ -136,4 +136,11 @@ public sealed class DicService(IDicCatalogService catalogService, IDicContentSer
|
|||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
return contentService.QueryAsync(req);
|
return contentService.QueryAsync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> SetEnabledAsync(SetDicContentEnabledReq req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return contentService.SetEnabledAsync(req);
|
||||||
|
}
|
||||||
}
|
}
|
@ -18,8 +18,7 @@ public sealed class FileService(IOptions<UploadOptions> uploadOptions, MinioHelp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!uploadOptions.Value.ContentTypes.Contains(file.ContentType)) {
|
if (!uploadOptions.Value.ContentTypes.Contains(file.ContentType)) {
|
||||||
throw new NetAdminInvalidOperationException(
|
throw new NetAdminInvalidOperationException($"{Ln.允许的文件格式} {string.Join(",", uploadOptions.Value.ContentTypes)}");
|
||||||
$"{Ln.允许的文件格式} {string.Join(",", uploadOptions.Value.ContentTypes)}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.Length > uploadOptions.Value.MaxSize) {
|
if (file.Length > uploadOptions.Value.MaxSize) {
|
||||||
|
@ -73,9 +73,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
|||||||
public async Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req)
|
public async Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryJobRecordReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryJobRecordReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryJobRecordRsp>();
|
return ret.Adapt<QueryJobRecordRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,16 +86,10 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
|||||||
#if DBTYPE_SQLSERVER
|
#if DBTYPE_SQLSERVER
|
||||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
#endif
|
#endif
|
||||||
.GroupBy(a => new {
|
.GroupBy(a => new { a.CreatedTime.Year, a.CreatedTime.Month, a.CreatedTime.Day, a.CreatedTime.Hour })
|
||||||
a.CreatedTime.Year
|
|
||||||
, a.CreatedTime.Month
|
|
||||||
, a.CreatedTime.Day
|
|
||||||
, a.CreatedTime.Hour
|
|
||||||
})
|
|
||||||
.ToListAsync(a => new GetBarChartRsp {
|
.ToListAsync(a => new GetBarChartRsp {
|
||||||
Timestamp = new DateTime(
|
Timestamp = new DateTime(a.Key.Year, a.Key.Month, a.Key.Day, a.Key.Hour, 0, 0
|
||||||
a.Key.Year, a.Key.Month, a.Key.Day, a.Key.Hour, 0
|
, DateTimeKind.Unspecified)
|
||||||
, 0, DateTimeKind.Unspecified)
|
|
||||||
, Value = a.Count()
|
, Value = a.Count()
|
||||||
})
|
})
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -118,8 +110,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
|||||||
.ToListAsync(a => new GetPieChartRsp { Value = a.Count(), Key = a.Key.ToString() })
|
.ToListAsync(a => new GetPieChartRsp { Value = a.Count(), Key = a.Key.ToString() })
|
||||||
#pragma warning restore CA1305
|
#pragma warning restore CA1305
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return ret.Select(x => x with { Key = Enum.Parse<HttpStatusCode>(x.Key).ToString() })
|
return ret.Select(x => x with { Key = Enum.Parse<HttpStatusCode>(x.Key).ToString() }).OrderByDescending(x => x.Value);
|
||||||
.OrderByDescending(x => x.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -150,8 +141,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new PagedQueryRsp<QueryJobRecordRsp>(req.Page, req.PageSize, total
|
return new PagedQueryRsp<QueryJobRecordRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryJobRecordRsp>>());
|
||||||
, list.Adapt<IEnumerable<QueryJobRecordRsp>>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -175,8 +165,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
|||||||
.WhereDynamic(req.Filter)
|
.WhereDynamic(req.Filter)
|
||||||
.WhereIf( //
|
.WhereIf( //
|
||||||
req.Keywords?.Length > 0
|
req.Keywords?.Length > 0
|
||||||
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) ||
|
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) || a.Job.JobName == req.Keywords);
|
||||||
a.Job.JobName == req.Keywords);
|
|
||||||
|
|
||||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||||
switch (req.Order) {
|
switch (req.Order) {
|
||||||
|
@ -112,9 +112,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
var job
|
var job = await QueryInternal(new QueryReq<QueryJobReq> { Count = 1, Filter = req, DynamicFilter = df, Order = Orders.None })
|
||||||
= await QueryInternal(
|
|
||||||
new QueryReq<QueryJobReq> { Count = 1, Filter = req, DynamicFilter = df, Order = Orders.None })
|
|
||||||
.ToOneAsync()
|
.ToOneAsync()
|
||||||
.ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.未获取到待执行任务);
|
.ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.未获取到待执行任务);
|
||||||
|
|
||||||
@ -160,16 +158,9 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var nextExecTime = GetNextExecTime(req.ExecutionCron);
|
var nextExecTime = GetNextExecTime(req.ExecutionCron);
|
||||||
_ = await UpdateAsync(
|
_ = await UpdateAsync( //
|
||||||
req with {
|
req with { Status = JobStatues.Idle, NextExecTime = nextExecTime, NextTimeId = nextExecTime?.TimeUnixUtc() }
|
||||||
Status = JobStatues.Idle
|
, [nameof(req.Status), nameof(req.NextExecTime), nameof(req.NextTimeId), nameof(req.LastDuration), nameof(req.LastStatusCode)])
|
||||||
, NextExecTime = nextExecTime
|
|
||||||
, NextTimeId = nextExecTime?.TimeUnixUtc()
|
|
||||||
}
|
|
||||||
, [
|
|
||||||
nameof(req.Status), nameof(req.NextExecTime), nameof(req.NextTimeId), nameof(req.LastDuration)
|
|
||||||
, nameof(req.LastStatusCode)
|
|
||||||
])
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,9 +168,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
public async Task<QueryJobRsp> GetAsync(QueryJobReq req)
|
public async Task<QueryJobRsp> GetAsync(QueryJobReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryJobReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryJobReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryJobRsp>();
|
return ret.Adapt<QueryJobRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,10 +198,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
#if DBTYPE_SQLSERVER
|
#if DBTYPE_SQLSERVER
|
||||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
#endif
|
#endif
|
||||||
.Where(a => !Rpo.Orm.Select<Sys_JobRecord>()
|
.Where(a => !Rpo.Orm.Select<Sys_JobRecord>().As("b").Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId).Any())
|
||||||
.As("b")
|
|
||||||
.Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId)
|
|
||||||
.Any())
|
|
||||||
.ToOneAsync(a => new {
|
.ToOneAsync(a => new {
|
||||||
a.RequestUrl
|
a.RequestUrl
|
||||||
, a.HttpMethod
|
, a.HttpMethod
|
||||||
@ -317,16 +303,13 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
{
|
{
|
||||||
var ret1 = await UpdateAsync( // 运行中,运行时间超过超时设定;置为空闲状态
|
var ret1 = await UpdateAsync( // 运行中,运行时间超过超时设定;置为空闲状态
|
||||||
new Sys_Job { Status = JobStatues.Idle }, [nameof(Sys_Job.Status)], null
|
new Sys_Job { Status = JobStatues.Idle }, [nameof(Sys_Job.Status)], null
|
||||||
, a => a.Status == JobStatues.Running &&
|
, a => a.Status == JobStatues.Running && a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB), null, true)
|
||||||
a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB)
|
|
||||||
, null, true)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var ret2 = await UpdateAsync( // 空闲中,下次执行时间在当前时间减去超时时间以前;将下次执行时间调整到现在
|
var ret2 = await UpdateAsync( // 空闲中,下次执行时间在当前时间减去超时时间以前;将下次执行时间调整到现在
|
||||||
new Sys_Job { NextExecTime = DateTime.Now, NextTimeId = DateTime.Now.TimeUnixUtc() }
|
new Sys_Job { NextExecTime = DateTime.Now, NextTimeId = DateTime.Now.TimeUnixUtc() }
|
||||||
, [nameof(Sys_Job.NextExecTime), nameof(Sys_Job.NextTimeId)], null
|
, [nameof(Sys_Job.NextExecTime), nameof(Sys_Job.NextTimeId)], null
|
||||||
, a => a.Status == JobStatues.Idle && a.NextExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB)
|
, a => a.Status == JobStatues.Idle && a.NextExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB), null, true)
|
||||||
, null, true)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return ret1 + ret2;
|
return ret1 + ret2;
|
||||||
}
|
}
|
||||||
@ -340,9 +323,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
|
|
||||||
private static DateTime? GetNextExecTime(string cron)
|
private static DateTime? GetNextExecTime(string cron)
|
||||||
{
|
{
|
||||||
return CronExpression.Parse(cron, CronFormat.IncludeSeconds)
|
return CronExpression.Parse(cron, CronFormat.IncludeSeconds).GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local)?.ToLocalTime();
|
||||||
.GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local)
|
|
||||||
?.ToLocalTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req)
|
private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req)
|
||||||
@ -360,8 +341,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
|||||||
ret = ret.WhereDynamicFilter(req.DynamicFilter)
|
ret = ret.WhereDynamicFilter(req.DynamicFilter)
|
||||||
.WhereDynamic(req.Filter)
|
.WhereDynamic(req.Filter)
|
||||||
.WhereIf( //
|
.WhereIf( //
|
||||||
req.Keywords?.Length > 0
|
req.Keywords?.Length > 0, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
|
||||||
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
|
|
||||||
|
|
||||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||||
switch (req.Order) {
|
switch (req.Order) {
|
||||||
|
@ -72,9 +72,7 @@ public sealed class LoginLogService(BasicRepository<Sys_LoginLog, long> rpo) //
|
|||||||
public async Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
|
public async Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryLoginLogReq> { Filter = req, Order = Orders.None })
|
var ret = await QueryInternal(new QueryReq<QueryLoginLogReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
|
||||||
.ToOneAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
return ret.Adapt<QueryLoginLogRsp>();
|
return ret.Adapt<QueryLoginLogRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +126,7 @@ public sealed class LoginLogService(BasicRepository<Sys_LoginLog, long> rpo) //
|
|||||||
if (req.Keywords?.Length > 0) {
|
if (req.Keywords?.Length > 0) {
|
||||||
ret = req.Keywords.IsIpV4()
|
ret = req.Keywords.IsIpV4()
|
||||||
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
||||||
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) ||
|
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) || a.LoginUserName == req.Keywords);
|
||||||
a.LoginUserName == req.Keywords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user