feat: 计划作业 (#87)

This commit is contained in:
2024-02-02 14:05:39 +08:00
committed by GitHub
parent 473b0c26f2
commit 8293ec0297
70 changed files with 2171 additions and 14 deletions

View File

@ -2,6 +2,7 @@ using NetAdmin.BizServer.Host;
using NetAdmin.BizServer.Host.Extensions;
using NetAdmin.Host.Extensions;
using NetAdmin.Host.Middlewares;
using NetAdmin.SysComponent.Host.Extensions;
using Spectre.Console.Cli;
using ValidationResult = Spectre.Console.ValidationResult;
#if !DEBUG
@ -62,6 +63,7 @@ namespace NetAdmin.BizServer.Host
.AddCorsAccessor() // 添加支持跨域访问
.AddContextUser() // 添加上下文用户
.AddRedisCache() // 添加 Redis 缓存
.AddSchedules() // 添加计划任务
// IMvcBuilder
.AddControllers() // 添加控制器

View File

@ -4,6 +4,6 @@
<ProjectReference Include="../NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0-release-23619-01"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-preview-24080-01"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Api;
namespace NetAdmin.Domain.Attributes.DataValidation;
/// <summary>
/// 接口编码验证器
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)]
public sealed class ApiIdAttribute : ValidationAttribute
{
/// <inheritdoc />
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = App.GetService(App.EffectiveTypes.Single(
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IApiCache"));
var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } };
var method = service.GetType().GetMethod("ExistAsync");
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
return !exist ? new ValidationResult(Ln.) : ValidationResult.Success;
}
}

View File

@ -0,0 +1,18 @@
namespace NetAdmin.Domain.Attributes.DataValidation;
/// <summary>
/// 时间表达式验证器
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)]
public sealed class CronAttribute : RegexAttribute
{
/// <summary>
/// Initializes a new instance of the <see cref="CronAttribute" /> class.
/// </summary>
public CronAttribute() //
: base(Chars.RGX_CRON)
{
ErrorMessageResourceName = nameof(Ln.);
ErrorMessageResourceType = typeof(Ln);
}
}

View File

@ -0,0 +1,24 @@
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.User;
namespace NetAdmin.Domain.Attributes.DataValidation;
/// <summary>
/// 用户编号验证器
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)]
public sealed class UserIdAttribute : ValidationAttribute
{
/// <inheritdoc />
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = App.GetService(App.EffectiveTypes.Single(
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IUserCache"));
var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } };
var method = service.GetType().GetMethod("ExistAsync");
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
return !exist ? new ValidationResult(Ln.) : ValidationResult.Success;
}
}

View File

@ -5,6 +5,17 @@ namespace NetAdmin.Domain;
/// </summary>
public abstract record DataAbstraction
{
/// <summary>
/// 如果数据校验失败,抛出异常
/// </summary>
/// <exception cref="NetAdminInvalidInputException">NetAdminInvalidInputException</exception>
public void ThrowIfInvalid()
{
if (!this.TryValidate().IsValid) {
throw new NetAdminInvalidInputException(Ln.);
}
}
/// <inheritdoc />
public override string ToString()
{

View File

@ -0,0 +1,107 @@
using NetAdmin.Domain.DbMaps.Dependency;
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.Enums.Sys;
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary>
/// 计划作业表
/// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Job))]
public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
{
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore]
[Column]
public virtual bool Enabled { get; init; }
/// <summary>
/// 执行时间计划
/// </summary>
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
public virtual string ExecutionCron { get; init; }
/// <summary>
/// 请求方法
/// </summary>
[JsonIgnore]
[Column]
public virtual HttpMethods HttpMethod { get; init; }
/// <summary>
/// 作业名称
/// </summary>
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
public virtual string JobName { get; init; }
/// <summary>
/// 上次执行时间
/// </summary>
[JsonIgnore]
[Column]
public virtual DateTime? LastExecTime { get; init; }
/// <summary>
/// 上次执行状态
/// </summary>
[JsonIgnore]
[Column]
public virtual HttpStatusCode? LastStatusCode { get; init; }
/// <summary>
/// 下次执行时间
/// </summary>
[JsonIgnore]
[Column]
public virtual DateTime? NextExecTime { get; init; }
/// <summary>
/// 下次执行时间编号
/// </summary>
[JsonIgnore]
[Column]
public virtual long? NextTimeId { get; init; }
/// <summary>
/// 请求体
/// </summary>
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
public virtual string RequestBody { get; init; }
/// <summary>
/// 请求头
/// </summary>
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
public virtual string RequestHeader { get; init; }
/// <summary>
/// 请求的网络地址
/// </summary>
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
public virtual string RequestUrl { get; init; }
/// <summary>
/// 作业状态
/// </summary>
[JsonIgnore]
[Column]
public virtual JobStatues Status { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore]
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
public virtual string Summary { get; init; }
/// <summary>
/// 执行用户编号
/// </summary>
[JsonIgnore]
[Column]
public virtual long UserId { get; init; }
}

View File

@ -0,0 +1,82 @@
using NetAdmin.Domain.DbMaps.Dependency;
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary>
/// 计划作业执行记录表
/// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_JobRecord))]
[Index($"idx_{{tablename}}_{nameof(JobId)}_{nameof(TimeId)}", $"{nameof(JobId)},{nameof(TimeId)}", true)]
public record Sys_JobRecord : LiteImmutableEntity
{
/// <summary>
/// 执行耗时(毫秒)
/// </summary>
[Column]
[JsonIgnore]
public virtual long Duration { get; init; }
/// <summary>
/// 请求方法
/// </summary>
[JsonIgnore]
[Column]
public virtual HttpMethods HttpMethod { get; init; }
/// <summary>
/// HTTP 状态码
/// </summary>
[Column]
[JsonIgnore]
public virtual HttpStatusCode HttpStatusCode { get; init; }
/// <summary>
/// 作业编号
/// </summary>
[Column]
[JsonIgnore]
public long JobId { get; init; }
/// <summary>
/// 请求体
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[JsonIgnore]
public virtual string RequestBody { get; init; }
/// <summary>
/// 请求头
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[JsonIgnore]
public virtual string RequestHeader { get; init; }
/// <summary>
/// 请求的网络地址
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
[JsonIgnore]
public virtual string RequestUrl { get; init; }
/// <summary>
/// 响应体
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[JsonIgnore]
public virtual string ResponseBody { get; init; }
/// <summary>
/// 响应头
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[JsonIgnore]
public virtual string ResponseHeader { get; init; }
/// <summary>
/// 执行时间编号
/// </summary>
[Column]
[JsonIgnore]
public long TimeId { get; set; }
}

View File

@ -0,0 +1,65 @@
using NetAdmin.Domain.Attributes.DataValidation;
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.DbMaps.Sys;
using NetAdmin.Domain.Enums.Sys;
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.Dto.Sys.Job;
/// <summary>
/// 请求:创建计划作业
/// </summary>
public record CreateJobReq : Sys_Job
{
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; } = true;
/// <inheritdoc cref="Sys_Job.ExecutionCron" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Cron]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.时间计划不能为空))]
public override string ExecutionCron { get; init; }
/// <inheritdoc cref="Sys_Job.HttpMethod" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[EnumDataType(typeof(HttpMethods), ErrorMessageResourceType = typeof(Ln)
, ErrorMessageResourceName = nameof(Ln.请求方法不正确))]
public override HttpMethods HttpMethod { get; init; }
/// <inheritdoc cref="Sys_Job.JobName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.作业名称不能为空))]
public override string JobName { get; init; }
/// <inheritdoc />
public override long? NextTimeId { get; init; }
/// <inheritdoc cref="Sys_Job.RequestBody" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestBody { get; init; }
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> RequestHeaders { get; init; }
/// <inheritdoc cref="Sys_Job.RequestUrl" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求地址不能为空))]
[Url(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.网络地址不正确))]
public override string RequestUrl { get; init; }
/// <inheritdoc />
public override JobStatues Status { get; init; } = JobStatues.Idle;
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
/// <inheritdoc cref="Sys_Job.UserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[Range(1, long.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户编号不存在))]
[UserId]
public override long UserId { get; init; }
}

View File

@ -0,0 +1,14 @@
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.DbMaps.Sys;
namespace NetAdmin.Domain.Dto.Sys.Job;
/// <summary>
/// 请求:查询计划作业
/// </summary>
public sealed record QueryJobReq : Sys_Job
{
/// <inheritdoc cref="IFieldPrimary{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
}

View File

@ -0,0 +1,80 @@
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.DbMaps.Sys;
using NetAdmin.Domain.Enums.Sys;
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.Dto.Sys.Job;
/// <summary>
/// 响应:查询计划作业
/// </summary>
public sealed record QueryJobRsp : Sys_Job
{
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; }
/// <inheritdoc cref="Sys_Job.ExecutionCron" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string ExecutionCron { get; init; }
/// <inheritdoc cref="Sys_Job.HttpMethod" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override HttpMethods HttpMethod { get; init; }
/// <inheritdoc cref="IFieldPrimary{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="Sys_Job.JobName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string JobName { get; init; }
/// <inheritdoc cref="Sys_Job.LastExecTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override DateTime? LastExecTime { get; init; }
/// <inheritdoc cref="Sys_Job.LastStatusCode" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override HttpStatusCode? LastStatusCode { get; init; }
/// <inheritdoc cref="Sys_Job.NextExecTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override DateTime? NextExecTime { get; init; }
/// <inheritdoc cref="Sys_Job.NextTimeId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? NextTimeId { get; init; }
/// <inheritdoc cref="Sys_Job.RequestBody" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestBody { get; init; }
/// <inheritdoc cref="Sys_Job.RequestHeader" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestHeader { get; init; }
/// <inheritdoc cref="Sys_Job.RequestUrl" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestUrl { get; init; }
/// <inheritdoc cref="Sys_Job.Status" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override JobStatues Status { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
/// <inheritdoc cref="Sys_Job.UserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long UserId { get; init; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -0,0 +1,13 @@
using NetAdmin.Domain.DbMaps.Dependency.Fields;
namespace NetAdmin.Domain.Dto.Sys.Job;
/// <summary>
/// 请求:更新计划作业
/// </summary>
public sealed record UpdateJobReq : CreateJobReq
{
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -0,0 +1,8 @@
using NetAdmin.Domain.DbMaps.Sys;
namespace NetAdmin.Domain.Dto.Sys.JobRecord;
/// <summary>
/// 请求:创建计划作业执行记录
/// </summary>
public record CreateJobRecordReq : Sys_JobRecord;

View File

@ -0,0 +1,14 @@
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.DbMaps.Sys;
namespace NetAdmin.Domain.Dto.Sys.JobRecord;
/// <summary>
/// 请求:查询计划作业执行记录
/// </summary>
public sealed record QueryJobRecordReq : Sys_JobRecord
{
/// <inheritdoc cref="IFieldPrimary{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
}

View File

@ -0,0 +1,14 @@
using NetAdmin.Domain.DbMaps.Dependency.Fields;
using NetAdmin.Domain.DbMaps.Sys;
namespace NetAdmin.Domain.Dto.Sys.JobRecord;
/// <summary>
/// 响应:查询计划作业执行记录
/// </summary>
public sealed record QueryJobRecordRsp : Sys_JobRecord
{
/// <inheritdoc cref="IFieldPrimary{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
}

View File

@ -0,0 +1,6 @@
namespace NetAdmin.Domain.Dto.Sys.JobRecord;
/// <summary>
/// 请求:更新计划作业执行记录
/// </summary>
public sealed record UpdateJobRecordReq : CreateJobRecordReq { }

View File

@ -0,0 +1,69 @@
namespace NetAdmin.Domain.Enums;
/// <summary>
/// HTTP 请求方法
/// </summary>
[Export]
public enum HttpMethods
{
/// <summary>
/// Connect
/// </summary>
Connect = 1
,
/// <summary>
/// Delete
/// </summary>
Delete = 2
,
/// <summary>
/// Get
/// </summary>
Get = 3
,
/// <summary>
/// Head
/// </summary>
Head = 4
,
/// <summary>
/// Options
/// </summary>
Options = 5
,
/// <summary>
/// Patch
/// </summary>
Patch = 6
,
/// <summary>
/// Post
/// </summary>
Post = 7
,
/// <summary>
/// Put
/// </summary>
Put = 8
,
/// <summary>
/// Trace
/// </summary>
Trace = 9
}

View File

@ -0,0 +1,22 @@
namespace NetAdmin.Domain.Enums.Sys;
/// <summary>
/// 计划作业状态
/// </summary>
[Export]
public enum JobStatues
{
/// <summary>
/// 空闲
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.空闲))]
Idle = 1
,
/// <summary>
/// 运行
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.运行))]
Running = 2
}

View File

@ -11,7 +11,9 @@ namespace NetAdmin.Infrastructure.Constant;
public static class Chars
{
public const string FLG_ACCESS_TOKEN = "ACCESS-TOKEN";
public const string FLG_ACCESS_TOKEN_HEADER_KEY = "Authorization";
public const string FLG_APPLICATION_JSON = "application/json";
public const string FLG_AUTH_SCHEMA = "Bearer";
public const string FLG_CONSUL_REG_HOSTNAME = "CONSUL_REG_HOSTNAME";
public const string FLG_CONSUL_REG_PORT = "CONSUL_REG_PORT";
public const string FLG_CONTEXT_MEMBER_INFO = nameof(FLG_CONTEXT_MEMBER_INFO);
@ -66,13 +68,17 @@ public static class Chars
public const string FLG_VISIBLE_ASCIIS
= """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
public const string FLG_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
public const string FLG_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
public const string FLG_X_ACCESS_TOKEN_HEADER_KEY = "X-Authorization";
public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$";
public const string RGX_CHINESE_NAME
= """^(?:赵|钱|孙|李|周|吴|郑|王|冯|陈|褚|卫|蒋|沈|韩|杨|朱|秦|尤|许|何|吕|施|张|孔|曹|严|华|金|魏|陶|姜|戚|谢|邹|喻|柏|水|窦|章|云|苏|潘|葛|奚|范|彭|郎|鲁|韦|昌|马|苗|凤|花|方|俞|任|袁|柳|酆|鲍|史|唐|费|廉|岑|薛|雷|贺|倪|汤|滕|殷|罗|毕|郝|邬|安|常|乐|于|时|傅|皮|卞|齐|康|伍|余|元|卜|顾|孟|平|黄|和|穆|萧|尹|姚|邵|湛|汪|祁|毛|禹|狄|米|贝|明|臧|计|伏|成|戴|谈|宋|茅|庞|熊|纪|舒|屈|项|祝|董|梁|杜|阮|蓝|闵|席|季|麻|强|贾|路|娄|危|江|童|颜|郭|梅|盛|林|刁|钟|徐|邱|骆|高|夏|蔡|田|樊|胡|凌|霍|虞|万|支|柯|昝|管|卢|莫|经|房|裘|缪|干|解|应|宗|丁|宣|贲|邓|郁|单|杭|洪|包|诸|左|石|崔|吉|钮|龚|程|嵇|邢|滑|裴|陆|荣|翁|荀|羊|於|惠|甄|曲|家|封|芮|羿|储|靳|汲|邴|糜|松|井|段|富|巫|乌|焦|巴|弓|牧|隗|山|谷|车|侯|宓|蓬|全|郗|班|仰|秋|仲|伊|宫|宁|仇|栾|暴|甘|钭|厉|戎|祖|武|符|刘|景|詹|束|龙|叶|幸|司|韶|郜|黎|蓟|薄|印|宿|白|怀|蒲|邰|从|鄂|索|咸|籍|赖|卓|蔺|屠|蒙|池|乔|阴|胥|能|苍|双|闻|莘|党|翟|谭|贡|劳|逄|姬|申|扶|堵|冉|宰|郦|雍|郤|璩|桑|桂|濮|牛|寿|通|边|扈|燕|冀|郏|浦|尚|农|温|别|庄|晏|柴|瞿|阎|充|慕|连|茹|习|宦|艾|鱼|容|向|古|易|慎|戈|廖|庾|终|暨|居|衡|步|都|耿|满|弘|匡|国|文|寇|广|禄|阙|东|欧|殳|沃|利|蔚|越|夔|隆|师|巩|厍|聂|晁|勾|敖|融|冷|訾|辛|阚|那|简|饶|空|曾|毋|沙|乜|养|鞠|须|丰|巢|关|蒯|相|查|後|荆|红|游|竺|权|逯|盖|益|桓|公|万俟|司马|上官|欧阳|夏侯|诸葛|闻人|东方|赫连|皇甫|尉迟|公羊|澹台|公冶|宗政|濮阳|淳于|单于|太叔|申屠|公孙|仲孙|轩辕|令狐|钟离|宇文|长孙|慕容|鲜于|闾丘|司徒|司空|亓官|司寇|仉|督|子车|颛孙|端木|巫马|公西|漆雕|乐正|壤驷|公良|拓跋|夹谷|宰父|谷梁|晋|楚|闫|法|汝|鄢|涂|钦|段干|百里|东郭|南门|呼延|归|海|羊舌|微生|岳|帅|缑|亢|况|后|有|琴|梁丘|左丘|东门|西门|商|牟|佘|佴|伯|赏|南宫|墨|哈|谯|笪|年|爱|阳|佟|第五|言|福)[\u4e00-\u9fa5]{1,3}$""";
public const string RGX_CRON
= """^(?:[0-5]?[0-9]|[0-9]|[1-5]?[0-9](?:,[0-5]?[0-9])?|\*|\*/[0-5]?[0-9])\s+(?:[01]?[0-9]|2[0-3]|\*)\s+(?:[0-2]?[0-9]|3[01]|\*)\s+(?:0?[0-9]|1[0-1]|\*)\s+(?:[0-6]|\*)$""";
public const string RGX_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])))$""";

View File

@ -1,3 +1,5 @@
using DataType = FreeSql.DataType;
namespace NetAdmin.Infrastructure;
/// <summary>
@ -27,6 +29,41 @@ public static class GlobalStatic
/// </summary>
public static string SecretKey => "{6C4922D3-499A-46db-BFC4-0B51A9C4395F}";
/// <summary>
/// SQL 随机排序语法
/// </summary>
/// <exception cref="NotImplementedException">NotImplementedException</exception>
public static string SqlRandomSorting =>
App.GetOptions<DatabaseOptions>().DbType switch {
DataType.MySql => "RAND()"
, DataType.SqlServer => "NEWID()"
, DataType.PostgreSQL => "RANDOM()"
, DataType.Oracle => "DBMS_RANDOM.value"
, DataType.Sqlite => "RANDOM()"
, DataType.OdbcOracle => throw new NotImplementedException()
, DataType.OdbcSqlServer => throw new NotImplementedException()
, DataType.OdbcMySql => throw new NotImplementedException()
, DataType.OdbcPostgreSQL => throw new NotImplementedException()
, DataType.Odbc => throw new NotImplementedException()
, DataType.OdbcDameng => throw new NotImplementedException()
, DataType.MsAccess => throw new NotImplementedException()
, DataType.Dameng => throw new NotImplementedException()
, DataType.OdbcKingbaseES => throw new NotImplementedException()
, DataType.ShenTong => throw new NotImplementedException()
, DataType.KingbaseES => throw new NotImplementedException()
, DataType.Firebird => throw new NotImplementedException()
, DataType.Custom => throw new NotImplementedException()
, DataType.ClickHouse => throw new NotImplementedException()
, DataType.GBase => throw new NotImplementedException()
, DataType.QuestDb => throw new NotImplementedException()
, DataType.Xugu => throw new NotImplementedException()
, DataType.CustomOracle => throw new NotImplementedException()
, DataType.CustomSqlServer => throw new NotImplementedException()
, DataType.CustomMySql => throw new NotImplementedException()
, DataType.CustomPostgreSQL => throw new NotImplementedException()
, _ => throw new NotImplementedException()
};
/// <summary>
/// Json序列化选项
/// </summary>

View File

@ -6,16 +6,17 @@
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
<ItemGroup>
<PackageReference Include="Cronos" Version="0.8.2"/>
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.810-preview20231229-ns1"/>
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.810-preview20231229-ns1"/>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.24"/>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.1.24-ns1"/>
<PackageReference Include="Furion.Pure.NS" Version="4.9.1.24-ns1"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.1"/>
<PackageReference Include="Minio" Version="6.0.1"/>
<PackageReference Include="NSExt" Version="2.0.11"/>
<PackageReference Include="RedLock.net" Version="2.3.2"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0"/>
<PackageReference Include="Minio" Version="6.0.1"/>
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14"/>
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,20 @@
using NetAdmin.Application.Modules;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Job;
namespace NetAdmin.SysComponent.Application.Modules.Sys;
/// <summary>
/// 计划作业模块
/// </summary>
public interface IJobModule : ICrudModule<CreateJobReq, QueryJobRsp // 创建类型
, QueryJobReq, QueryJobRsp // 查询类型
, UpdateJobReq, QueryJobRsp // 修改类型
, DelReq // 删除类型
>
{
/// <summary>
/// 启用/禁用作业
/// </summary>
Task SetEnabledAsync(UpdateJobReq req);
}

View File

@ -0,0 +1,14 @@
using NetAdmin.Application.Modules;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.JobRecord;
namespace NetAdmin.SysComponent.Application.Modules.Sys;
/// <summary>
/// 计划作业执行记录模块
/// </summary>
public interface IJobRecordModule : ICrudModule<CreateJobRecordReq, QueryJobRecordRsp // 创建类型
, QueryJobRecordReq, QueryJobRecordRsp // 查询类型
, UpdateJobRecordReq, QueryJobRecordRsp // 修改类型
, DelReq // 删除类型
>;

View File

@ -17,42 +17,49 @@ public sealed class ApiService(
/// <inheritdoc />
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<QueryApiRsp> CreateAsync(CreateApiReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryApiReq> req)
{
throw new NotImplementedException();
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public Task<QueryApiRsp> GetAsync(QueryApiReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryApiRsp>> PagedQueryAsync(PagedQueryReq<QueryApiReq> req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public async Task<IEnumerable<QueryApiRsp>> QueryAsync(QueryReq<QueryApiReq> req)
{
req.ThrowIfInvalid();
var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter)
.ToTreeListAsync()
@ -108,6 +115,7 @@ public sealed class ApiService(
/// <inheritdoc />
public Task<NopReq> UpdateAsync(NopReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
@ -129,4 +137,17 @@ public sealed class ApiService(
?.HttpMethods.First()
});
}
private ISelect<Sys_Api> QueryInternal(QueryReq<QueryApiReq> req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter)
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.CreatedTime);
}
return ret;
}
}

View File

@ -23,6 +23,7 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
/// <inheritdoc />
public async Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
{
req.ThrowIfInvalid();
var database = connectionMultiplexer.GetDatabase((int?)req.Filter?.DbIndex ?? 0);
var redisResults = (RedisResult[])await database
.ExecuteAsync("scan", (req.Page - 1) * req.PageSize, "count"

View File

@ -37,6 +37,7 @@ public sealed class CaptchaService : ServiceBase<ICaptchaService>, ICaptchaServi
/// <inheritdoc />
public Task<bool> VerifyCaptchaAsync(VerifyCaptchaReq req)
{
req.ThrowIfInvalid();
if (req.SawOffsetX == null) {
return Task.FromResult(false);
}

View File

@ -15,6 +15,7 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public async Task<QueryConfigRsp> CreateAsync(CreateConfigReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryConfigRsp>();
}
@ -33,18 +35,21 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryConfigReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryConfigRsp> GetAsync(QueryConfigReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryConfigReq> { Filter = req }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryConfigRsp>();
}
@ -61,6 +66,7 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryConfigRsp>> PagedQueryAsync(PagedQueryReq<QueryConfigReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -74,6 +80,7 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryConfigRsp>> QueryAsync(QueryReq<QueryConfigReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryConfigRsp>>();
}
@ -81,6 +88,7 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
/// <inheritdoc />
public async Task<QueryConfigRsp> UpdateAsync(UpdateConfigReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QueryConfigRsp;
}

View File

@ -0,0 +1,9 @@
using NetAdmin.Application.Services;
using NetAdmin.SysComponent.Application.Modules.Sys;
namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency;
/// <summary>
/// 计划作业执行记录服务
/// </summary>
public interface IJobRecordService : IService, IJobRecordModule;

View File

@ -0,0 +1,21 @@
using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.SysComponent.Application.Modules.Sys;
namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency;
/// <summary>
/// 计划作业服务
/// </summary>
public interface IJobService : IService, IJobModule
{
/// <summary>
/// 完成计划作业
/// </summary>
Task FinishJobAsync(UpdateJobReq req);
/// <summary>
/// 获取下一个要执行的计划作业
/// </summary>
Task<QueryJobRsp> GetNextJobAsync();
}

View File

@ -14,6 +14,11 @@ public interface IUserService : IService, IUserModule
/// </summary>
Task<QueryUserRsp> GetForUpdateAsync(QueryUserReq req);
/// <summary>
/// 用户编号登录
/// </summary>
Task<LoginRsp> LoginByUserIdAsync(long userId);
/// <summary>
/// 单体更新
/// </summary>

View File

@ -14,6 +14,7 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <exception cref="NetAdminInvalidOperationException">Parent_department_does_not_exist</exception>
public async Task<QueryDeptRsp> CreateAsync(CreateDeptReq req)
{
req.ThrowIfInvalid();
if (req.ParentId != 0 && !await Rpo.Select.AnyAsync(a => a.Id == req.ParentId).ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
}
@ -40,6 +42,7 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <exception cref="NetAdminInvalidOperationException">该部门下存在子部门</exception>
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
if (await Rpo.Orm.Select<Sys_User>().AnyAsync(a => a.DeptId == req.Id).ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
}
@ -56,12 +59,14 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryDeptReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryDeptRsp> GetAsync(QueryDeptReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDeptReq> { Filter = req }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryDeptRsp>();
}
@ -69,12 +74,14 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <inheritdoc />
public Task<PagedQueryRsp<QueryDeptRsp>> PagedQueryAsync(PagedQueryReq<QueryDeptReq> req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public async Task<IEnumerable<QueryDeptRsp>> QueryAsync(QueryReq<QueryDeptReq> req)
{
req.ThrowIfInvalid();
return (await QueryInternal(req).ToTreeListAsync().ConfigureAwait(false)).Adapt<IEnumerable<QueryDeptRsp>>();
}
@ -82,6 +89,7 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDeptRsp> UpdateAsync(UpdateDeptReq req)
{
req.ThrowIfInvalid();
return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0
? throw new NetAdminUnexpectedException()
: (await QueryInternal(new QueryReq<QueryDeptReq> { Filter = new QueryDeptReq { Id = req.Id } }, true)

View File

@ -22,6 +22,8 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
/// <inheritdoc />
public async Task GenerateCsCodeAsync(GenerateCsCodeReq req)
{
req.ThrowIfInvalid();
// 模块类型Sys、Biz、等
var moduleType = Enum.GetName(req.Type)!;
@ -111,6 +113,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
/// <inheritdoc />
public async Task GenerateIconCodeAsync(GenerateIconCodeReq req)
{
req.ThrowIfInvalid();
var tplSvg = await File.ReadAllTextAsync(
Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue"))
.ConfigureAwait(false);

View File

@ -14,6 +14,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <exception cref="NetAdminInvalidOperationException">The_parent_node_does_not_exist</exception>
public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req)
{
req.ThrowIfInvalid();
if (req.ParentId != 0 &&
!await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
@ -38,6 +40,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc />
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.DeleteCascadeByDatabaseAsync(a => a.Id == req.Id).ConfigureAwait(false);
return ret.Count;
}
@ -45,12 +48,14 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryDicCatalogRsp> GetAsync(QueryDicCatalogReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDicCatalogReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -60,6 +65,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryDicCatalogRsp>> PagedQueryAsync(PagedQueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -73,6 +79,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryDicCatalogRsp>> QueryAsync(QueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).ToTreeListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryDicCatalogRsp>>();
}
@ -82,6 +89,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDicCatalogRsp> UpdateAsync(UpdateDicCatalogReq req)
{
req.ThrowIfInvalid();
if (req.ParentId != 0 &&
!await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);

View File

@ -14,6 +14,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <exception cref="NetAdminInvalidOperationException">Dictionary_directory_does_not_exist</exception>
public async Task<QueryDicContentRsp> CreateAsync(CreateDicContentReq req)
{
req.ThrowIfInvalid();
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
.Where(a => a.Id == req.CatalogId)
.ForUpdate()
@ -41,18 +43,21 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryDicContentRsp> GetAsync(QueryDicContentReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDicContentReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -62,6 +67,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryDicContentRsp>> PagedQueryAsync(PagedQueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -75,6 +81,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryDicContentRsp>> QueryAsync(QueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryDicContentRsp>>();
}
@ -84,6 +91,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDicContentRsp> UpdateAsync(UpdateDicContentReq req)
{
req.ThrowIfInvalid();
if (!await Rpo.Orm.Select<Sys_DicCatalog>()
.Where(a => a.Id == req.CatalogId)
.ForUpdate()

View File

@ -13,84 +13,98 @@ public sealed class DicService(IDicCatalogService catalogService, IDicContentSer
/// <inheritdoc />
public Task<int> BulkDeleteCatalogAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
return catalogService.BulkDeleteAsync(req);
}
/// <inheritdoc />
public Task<int> BulkDeleteContentAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
return contentService.BulkDeleteAsync(req);
}
/// <inheritdoc />
public Task<QueryDicCatalogRsp> CreateCatalogAsync(CreateDicCatalogReq req)
{
req.ThrowIfInvalid();
return catalogService.CreateAsync(req);
}
/// <inheritdoc />
public Task<QueryDicContentRsp> CreateContentAsync(CreateDicContentReq req)
{
req.ThrowIfInvalid();
return contentService.CreateAsync(req);
}
/// <inheritdoc />
public Task<int> DeleteCatalogAsync(DelReq req)
{
req.ThrowIfInvalid();
return catalogService.DeleteAsync(req);
}
/// <inheritdoc />
public Task<int> DeleteContentAsync(DelReq req)
{
req.ThrowIfInvalid();
return contentService.DeleteAsync(req);
}
/// <inheritdoc />
public Task<QueryDicCatalogRsp> GetCatalogAsync(QueryDicCatalogReq req)
{
req.ThrowIfInvalid();
return catalogService.GetAsync(req);
}
/// <inheritdoc />
public Task<QueryDicContentRsp> GetContentAsync(QueryDicContentReq req)
{
req.ThrowIfInvalid();
return contentService.GetAsync(req);
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryDicCatalogRsp>> PagedQueryCatalogAsync(PagedQueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
return catalogService.PagedQueryAsync(req);
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryDicContentRsp>> PagedQueryContentAsync(PagedQueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
return contentService.PagedQueryAsync(req);
}
/// <inheritdoc />
public Task<IEnumerable<QueryDicCatalogRsp>> QueryCatalogAsync(QueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
return catalogService.QueryAsync(req);
}
/// <inheritdoc />
public Task<IEnumerable<QueryDicContentRsp>> QueryContentAsync(QueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
return contentService.QueryAsync(req);
}
/// <inheritdoc />
public Task<QueryDicCatalogRsp> UpdateCatalogAsync(UpdateDicCatalogReq req)
{
req.ThrowIfInvalid();
return catalogService.UpdateAsync(req);
}
/// <inheritdoc />
public Task<QueryDicContentRsp> UpdateContentAsync(UpdateDicContentReq req)
{
req.ThrowIfInvalid();
return contentService.UpdateAsync(req);
}
}

View File

@ -0,0 +1,112 @@
using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services;
using NetAdmin.Domain.DbMaps.Sys;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.JobRecord;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using DataType = FreeSql.DataType;
namespace NetAdmin.SysComponent.Application.Services.Sys;
/// <inheritdoc cref="IJobRecordService" />
public sealed class JobRecordService(DefaultRepository<Sys_JobRecord> rpo) //
: RepositoryService<Sys_JobRecord, IJobRecordService>(rpo), IJobRecordService
{
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
}
return sum;
}
/// <inheritdoc />
public async Task<QueryJobRecordRsp> CreateAsync(CreateJobRecordReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryJobRecordRsp>();
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryJobRecordReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryJobRecordReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryJobRecordRsp>();
}
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryJobRecordRsp>> PagedQueryAsync(PagedQueryReq<QueryJobRecordReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
.ToListAsync()
.ConfigureAwait(false);
return new PagedQueryRsp<QueryJobRecordRsp>(req.Page, req.PageSize, total
, list.Adapt<IEnumerable<QueryJobRecordRsp>>());
}
/// <inheritdoc />
public async Task<IEnumerable<QueryJobRecordRsp>> QueryAsync(QueryReq<QueryJobRecordReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryJobRecordRsp>>();
}
/// <inheritdoc />
public async Task<QueryJobRecordRsp> UpdateAsync(UpdateJobRecordReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QueryJobRecordRsp;
}
var ret = await Rpo.UpdateDiy.SetSource(req).ExecuteUpdatedAsync().ConfigureAwait(false);
return ret.FirstOrDefault()?.Adapt<QueryJobRecordRsp>();
}
/// <inheritdoc />
protected override async Task<Sys_JobRecord> UpdateForSqliteAsync(Sys_JobRecord req)
{
return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0
? null
: await GetAsync(new QueryJobRecordReq { Id = req.Id }).ConfigureAwait(false);
}
private ISelect<Sys_JobRecord> QueryInternal(QueryReq<QueryJobRecordReq> req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter)
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id);
}
return ret;
}
}

View File

@ -0,0 +1,175 @@
using Cronos;
using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services;
using NetAdmin.Domain.DbMaps.Sys;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.Domain.Enums.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using DataType = FreeSql.DataType;
namespace NetAdmin.SysComponent.Application.Services.Sys;
/// <inheritdoc cref="IJobService" />
public sealed class JobService(DefaultRepository<Sys_Job> rpo) //
: RepositoryService<Sys_Job, IJobService>(rpo), IJobService
{
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
}
return sum;
}
/// <inheritdoc />
public async Task<QueryJobRsp> CreateAsync(CreateJobReq req)
{
req.ThrowIfInvalid();
var nextExecTime = CronExpression.Parse(req.ExecutionCron).GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Utc);
var ret = await Rpo.InsertAsync(req with {
NextExecTime = nextExecTime
, NextTimeId = nextExecTime?.TimeUnixUtc()
, RequestHeader = req.RequestHeaders?.Json()
})
.ConfigureAwait(false);
return ret.Adapt<QueryJobRsp>();
}
/// <inheritdoc />
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.DeleteCascadeByDatabaseAsync(a => a.Id == req.Id).ConfigureAwait(false);
return ret.Count;
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task FinishJobAsync(UpdateJobReq req)
{
var nextExecTime = CronExpression.Parse(req.ExecutionCron).GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Utc);
_ = await UpdateAsync(req with {
Status = JobStatues.Idle
, NextExecTime = nextExecTime
, NextTimeId = nextExecTime?.TimeUnixUtc()
})
.ConfigureAwait(false);
}
/// <inheritdoc />
public async Task<QueryJobRsp> GetAsync(QueryJobReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryJobReq> { Filter = req }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryJobRsp>();
}
/// <inheritdoc />
public async Task<QueryJobRsp> GetNextJobAsync()
{
var df = new DynamicFilterInfo {
Filters = [
new DynamicFilterInfo {
Field = nameof(QueryJobReq.NextExecTime)
, Value = DateTime.UtcNow
, Operator = DynamicFilterOperators.LessThan
}
, new DynamicFilterInfo {
Field = nameof(QueryJobReq.Status)
, Value = JobStatues.Idle
, Operator = DynamicFilterOperators.Eq
}
, new DynamicFilterInfo {
Field = nameof(QueryJobReq.Enabled)
, Value = true
, Operator = DynamicFilterOperators.Eq
}
]
};
var job = await QueryInternal(new QueryReq<QueryJobReq> { DynamicFilter = df, Count = 1 }, true)
.Where(a => !Rpo.Orm.Select<Sys_JobRecord>()
.As("b")
.Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId)
.Any())
.ToOneAsync()
.ConfigureAwait(false);
return job == null
? null
: await UpdateAsync(job.Adapt<UpdateJobReq>() with {
Status = JobStatues.Running
, LastExecTime = DateTime.UtcNow
})
.ConfigureAwait(false);
}
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryJobRsp>> PagedQueryAsync(PagedQueryReq<QueryJobReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
.ToListAsync()
.ConfigureAwait(false);
return new PagedQueryRsp<QueryJobRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryJobRsp>>());
}
/// <inheritdoc />
public async Task<IEnumerable<QueryJobRsp>> QueryAsync(QueryReq<QueryJobReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryJobRsp>>();
}
/// <inheritdoc />
public Task SetEnabledAsync(UpdateJobReq req)
{
req.ThrowIfInvalid();
return Rpo.UpdateDiy.Set(a => a.Enabled == req.Enabled).Where(a => a.Id == req.Id).ExecuteAffrowsAsync();
}
/// <inheritdoc />
public async Task<QueryJobRsp> UpdateAsync(UpdateJobReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return (await UpdateForSqliteAsync(req).ConfigureAwait(false)).Adapt<QueryJobRsp>();
}
_ = await Rpo.UpdateAsync(req).ConfigureAwait(false);
return req.Adapt<QueryJobRsp>();
}
/// <inheritdoc />
protected override async Task<Sys_Job> UpdateForSqliteAsync(Sys_Job req)
{
_ = await Rpo.UpdateAsync(req).ConfigureAwait(false);
return req;
}
private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req, bool orderByRandom = false)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter)
.WhereIf( //
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords))
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
return !orderByRandom && (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true)
? ret.OrderByDescending(a => a.Id)
: ret.OrderByRandom();
}
}

View File

@ -14,6 +14,7 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -25,6 +26,7 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
/// <inheritdoc />
public async Task<QueryMenuRsp> CreateAsync(CreateMenuReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryMenuRsp>();
}
@ -32,18 +34,21 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryMenuReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryMenuRsp> GetAsync(QueryMenuReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryMenuReq> { Filter = req }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryMenuRsp>();
}
@ -51,12 +56,14 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
/// <inheritdoc />
public Task<PagedQueryRsp<QueryMenuRsp>> PagedQueryAsync(PagedQueryReq<QueryMenuReq> req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public async Task<IEnumerable<QueryMenuRsp>> QueryAsync(QueryReq<QueryMenuReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).ToTreeListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryMenuRsp>>();
}
@ -65,6 +72,7 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryMenuRsp> UpdateAsync(UpdateMenuReq req)
{
req.ThrowIfInvalid();
if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException();
}

View File

@ -14,6 +14,7 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -25,6 +26,7 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public async Task<QueryRequestLogRsp> CreateAsync(CreateRequestLogReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryRequestLogRsp>();
}
@ -32,18 +34,21 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryRequestLogReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryRequestLogRsp> GetAsync(QueryRequestLogReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryRequestLogReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -53,6 +58,7 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryRequestLogRsp>> PagedQueryAsync(PagedQueryReq<QueryRequestLogReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -78,6 +84,7 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryRequestLogRsp>> QueryAsync(QueryReq<QueryRequestLogReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryRequestLogRsp>>();
}
@ -85,6 +92,7 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
/// <inheritdoc />
public Task<NopReq> UpdateAsync(NopReq req)
{
req.ThrowIfInvalid();
throw new NotImplementedException();
}

View File

@ -14,6 +14,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -25,6 +26,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public async Task<QueryRoleRsp> CreateAsync(CreateRoleReq req)
{
req.ThrowIfInvalid();
var entity = req.Adapt<Sys_Role>();
var ret = await Rpo.InsertAsync(entity).ConfigureAwait(false);
@ -40,6 +42,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <exception cref="NetAdminInvalidOperationException">Users_exist_under_this_role_and_deletion_is_not_allowed</exception>
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return await Rpo.Orm.Select<Sys_UserRole>().ForUpdate().AnyAsync(a => a.RoleId == req.Id).ConfigureAwait(false)
? throw new NetAdminInvalidOperationException(Ln.)
: await Rpo.DeleteAsync(a => a.Id == req.Id).ConfigureAwait(false);
@ -48,12 +51,14 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryRoleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryRoleRsp> GetAsync(QueryRoleReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryRoleReq> { Filter = req }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryRoleRsp>();
}
@ -61,6 +66,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryRoleRsp>> PagedQueryAsync(PagedQueryReq<QueryRoleReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -73,6 +79,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryRoleRsp>> QueryAsync(QueryReq<QueryRoleReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryRoleRsp>>();
}
@ -80,6 +87,7 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
/// <inheritdoc />
public async Task<QueryRoleRsp> UpdateAsync(UpdateRoleReq req)
{
req.ThrowIfInvalid();
var entity = req.Adapt<Sys_Role>();
_ = await Rpo.UpdateAsync(entity).ConfigureAwait(false);
await Rpo.SaveManyAsync(entity, nameof(entity.Depts)).ConfigureAwait(false);

View File

@ -15,6 +15,7 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgDeptRsp> CreateAsync(CreateSiteMsgDeptReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QuerySiteMsgDeptRsp>();
}
@ -33,18 +35,21 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QuerySiteMsgDeptReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QuerySiteMsgDeptRsp> GetAsync(QuerySiteMsgDeptReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QuerySiteMsgDeptReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -54,6 +59,7 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public async Task<PagedQueryRsp<QuerySiteMsgDeptRsp>> PagedQueryAsync(PagedQueryReq<QuerySiteMsgDeptReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -67,6 +73,7 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public async Task<IEnumerable<QuerySiteMsgDeptRsp>> QueryAsync(QueryReq<QuerySiteMsgDeptReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QuerySiteMsgDeptRsp>>();
}
@ -74,6 +81,7 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgDeptRsp> UpdateAsync(UpdateSiteMsgDeptReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QuerySiteMsgDeptRsp;
}

View File

@ -15,6 +15,7 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgFlagRsp> CreateAsync(CreateSiteMsgFlagReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QuerySiteMsgFlagRsp>();
}
@ -33,18 +35,21 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QuerySiteMsgFlagReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QuerySiteMsgFlagRsp> GetAsync(QuerySiteMsgFlagReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QuerySiteMsgFlagReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -54,6 +59,7 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public async Task<PagedQueryRsp<QuerySiteMsgFlagRsp>> PagedQueryAsync(PagedQueryReq<QuerySiteMsgFlagReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -67,6 +73,7 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public async Task<IEnumerable<QuerySiteMsgFlagRsp>> QueryAsync(QueryReq<QuerySiteMsgFlagReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QuerySiteMsgFlagRsp>>();
}
@ -74,6 +81,7 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgFlagRsp> UpdateAsync(UpdateSiteMsgFlagReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QuerySiteMsgFlagRsp;
}

View File

@ -15,6 +15,7 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgRoleRsp> CreateAsync(CreateSiteMsgRoleReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QuerySiteMsgRoleRsp>();
}
@ -33,18 +35,21 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QuerySiteMsgRoleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QuerySiteMsgRoleRsp> GetAsync(QuerySiteMsgRoleReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QuerySiteMsgRoleReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -54,6 +59,7 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public async Task<PagedQueryRsp<QuerySiteMsgRoleRsp>> PagedQueryAsync(PagedQueryReq<QuerySiteMsgRoleReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -67,6 +73,7 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public async Task<IEnumerable<QuerySiteMsgRoleRsp>> QueryAsync(QueryReq<QuerySiteMsgRoleReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QuerySiteMsgRoleRsp>>();
}
@ -74,6 +81,7 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgRoleRsp> UpdateAsync(UpdateSiteMsgRoleReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QuerySiteMsgRoleRsp;
}

View File

@ -21,6 +21,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -32,6 +33,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<QuerySiteMsgRsp> CreateAsync(CreateSiteMsgReq req)
{
req.ThrowIfInvalid();
await CreateUpdateCheckAsync(req).ConfigureAwait(false);
// 主表
@ -56,6 +58,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.DeleteCascadeByDatabaseAsync(a => a.Id == req.Id).ConfigureAwait(false);
return ret.Count;
}
@ -63,12 +66,14 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QuerySiteMsgReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QuerySiteMsgRsp> GetAsync(QuerySiteMsgReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QuerySiteMsgReq> { Filter = req })
.IncludeMany(a => a.Roles)
.IncludeMany(a => a.Users)
@ -81,6 +86,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<QuerySiteMsgRsp> GetMineAsync(QuerySiteMsgReq req)
{
req.ThrowIfInvalid();
var ret = await PagedQueryMineAsync(
new PagedQueryReq<QuerySiteMsgReq> {
DynamicFilter
@ -97,6 +103,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<PagedQueryRsp<QuerySiteMsgRsp>> PagedQueryAsync(PagedQueryReq<QuerySiteMsgReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -118,12 +125,14 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public Task<PagedQueryRsp<QuerySiteMsgRsp>> PagedQueryMineAsync(PagedQueryReq<QuerySiteMsgReq> req)
{
req.ThrowIfInvalid();
return PagedQueryMineAsync(req, false);
}
/// <inheritdoc />
public async Task<IEnumerable<QuerySiteMsgRsp>> QueryAsync(QueryReq<QuerySiteMsgReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QuerySiteMsgRsp>>();
}
@ -131,6 +140,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task SetSiteMsgStatusAsync(UpdateSiteMsgFlagReq req)
{
req.ThrowIfInvalid();
if (!await ExistAsync(new QueryReq<QuerySiteMsgReq> { Filter = new QuerySiteMsgReq { Id = req.SiteMsgId } })
.ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
@ -160,6 +170,7 @@ public sealed class SiteMsgService(
/// <inheritdoc />
public async Task<QuerySiteMsgRsp> UpdateAsync(UpdateSiteMsgReq req)
{
req.ThrowIfInvalid();
await CreateUpdateCheckAsync(req).ConfigureAwait(false);
// 主表

View File

@ -15,6 +15,7 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgUserRsp> CreateAsync(CreateSiteMsgUserReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QuerySiteMsgUserRsp>();
}
@ -33,18 +35,21 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QuerySiteMsgUserReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QuerySiteMsgUserRsp> GetAsync(QuerySiteMsgUserReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QuerySiteMsgUserReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -54,6 +59,7 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public async Task<PagedQueryRsp<QuerySiteMsgUserRsp>> PagedQueryAsync(PagedQueryReq<QuerySiteMsgUserReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -67,6 +73,7 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public async Task<IEnumerable<QuerySiteMsgUserRsp>> QueryAsync(QueryReq<QuerySiteMsgUserReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QuerySiteMsgUserRsp>>();
}
@ -74,6 +81,7 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
/// <inheritdoc />
public async Task<QuerySiteMsgUserRsp> UpdateAsync(UpdateSiteMsgUserReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QuerySiteMsgUserRsp;
}

View File

@ -16,6 +16,7 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -27,6 +28,7 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public async Task<QueryUserProfileRsp> CreateAsync(CreateUserProfileReq req)
{
req.ThrowIfInvalid();
var entity = req.Adapt<Sys_UserProfile>();
var ret = await Rpo.InsertAsync(entity).ConfigureAwait(false);
return ret.Adapt<QueryUserProfileRsp>();
@ -35,18 +37,21 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryUserProfileReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryUserProfileRsp> GetAsync(QueryUserProfileReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryUserProfileReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -56,6 +61,7 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryUserProfileRsp>> PagedQueryAsync(PagedQueryReq<QueryUserProfileReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -82,6 +88,7 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public async Task<IEnumerable<QueryUserProfileRsp>> QueryAsync(QueryReq<QueryUserProfileReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req)
.Take(req.Count)
.ToListAsync((a, b, c, d, e) => new {
@ -115,6 +122,7 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
/// <inheritdoc />
public async Task<QueryUserProfileRsp> UpdateAsync(UpdateUserProfileReq req)
{
req.ThrowIfInvalid();
var entity = req.Adapt<Sys_UserProfile>();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(entity).ConfigureAwait(false) as QueryUserProfileRsp;

View File

@ -38,6 +38,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -49,12 +50,14 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<bool> CheckMobileAvailableAsync(CheckMobileAvailableReq req)
{
req.ThrowIfInvalid();
return !await Rpo.Select.Where(a => a.Mobile == req.Mobile && a.Id != req.Id).AnyAsync().ConfigureAwait(false);
}
/// <inheritdoc />
public async Task<bool> CheckUserNameAvailableAsync(CheckUserNameAvailableReq req)
{
req.ThrowIfInvalid();
return !await Rpo.Select.Where(a => a.UserName == req.UserName && a.Id != req.Id)
.AnyAsync()
.ConfigureAwait(false);
@ -63,6 +66,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<QueryUserRsp> CreateAsync(CreateUserReq req)
{
req.ThrowIfInvalid();
await CreateUpdateCheckAsync(req).ConfigureAwait(false);
// 主表
@ -82,6 +86,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
var effect = 0;
// 删除主表
@ -101,12 +106,14 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<bool> ExistAsync(QueryReq<QueryUserReq> req)
{
req.ThrowIfInvalid();
return await (await QueryInternalAsync(req).ConfigureAwait(false)).AnyAsync().ConfigureAwait(false);
}
/// <inheritdoc />
public async Task<QueryUserRsp> GetAsync(QueryUserReq req)
{
req.ThrowIfInvalid();
var ret = await (await QueryInternalAsync(new QueryReq<QueryUserReq> { Filter = req }).ConfigureAwait(false))
.ToOneAsync()
.ConfigureAwait(false);
@ -116,6 +123,8 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<QueryUserRsp> GetForUpdateAsync(QueryUserReq req)
{
req.ThrowIfInvalid();
// ReSharper disable once MethodHasAsyncOverload
#pragma warning disable VSTHRD103
return (await QueryInternal(new QueryReq<QueryUserReq> { Filter = req })
@ -129,6 +138,7 @@ public sealed class UserService(
/// <exception cref="NetAdminInvalidOperationException">用户名或密码错误</exception>
public async Task<LoginRsp> LoginByPwdAsync(LoginByPwdReq req)
{
req.ThrowIfInvalid();
var pwd = req.Password.Pwd().Guid();
Sys_User dbUser;
@ -155,6 +165,7 @@ public sealed class UserService(
/// <exception cref="NetAdminInvalidOperationException">用户不存在</exception>
public async Task<LoginRsp> LoginBySmsAsync(LoginBySmsReq req)
{
req.ThrowIfInvalid();
if (!await verifyCodeService.VerifyAsync(req.Adapt<VerifySmsCodeReq>()).ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
}
@ -163,9 +174,18 @@ public sealed class UserService(
return dbUser == null ? throw new NetAdminInvalidOperationException(Ln.) : LoginInternal(dbUser);
}
/// <inheritdoc />
public async Task<LoginRsp> LoginByUserIdAsync(long userId)
{
var dbUser = await Rpo.Where(a => a.Id == userId).ToOneAsync().ConfigureAwait(false);
return LoginInternal(dbUser);
}
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryUserRsp>> PagedQueryAsync(PagedQueryReq<QueryUserReq> req)
{
req.ThrowIfInvalid();
var list = await (await QueryInternalAsync(req).ConfigureAwait(false)).Page(req.Page, req.PageSize)
.Count(out var total)
.ToListAsync(_selectUserFields)
@ -176,6 +196,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<IEnumerable<QueryUserRsp>> QueryAsync(QueryReq<QueryUserReq> req)
{
req.ThrowIfInvalid();
var list = await (await QueryInternalAsync(req).ConfigureAwait(false)).Take(req.Count)
.ToListAsync(_selectUserFields)
.ConfigureAwait(false);
@ -185,6 +206,7 @@ public sealed class UserService(
/// <inheritdoc />
public Task<IEnumerable<QueryUserProfileRsp>> QueryProfileAsync(QueryReq<QueryUserProfileReq> req)
{
req.ThrowIfInvalid();
return userProfileService.QueryAsync(req);
}
@ -192,6 +214,7 @@ public sealed class UserService(
/// <exception cref="NetAdminInvalidOperationException">验证码不正确</exception>
public async Task<UserInfoRsp> RegisterAsync(RegisterUserReq req)
{
req.ThrowIfInvalid();
if (!await verifyCodeService.VerifyAsync(req.VerifySmsCodeReq).ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.);
}
@ -205,6 +228,7 @@ public sealed class UserService(
/// <exception cref="NetAdminInvalidOperationException">用户不存在</exception>
public async Task<uint> ResetPasswordAsync(ResetPasswordReq req)
{
req.ThrowIfInvalid();
return !await verifyCodeService.VerifyAsync(req.VerifySmsCodeReq).ConfigureAwait(false)
? throw new NetAdminInvalidOperationException(Ln.)
: (uint)await Rpo.UpdateDiy
@ -221,6 +245,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<UserInfoRsp> SetAvatarAsync(SetAvatarReq req)
{
req.ThrowIfInvalid();
if (await Rpo.UpdateDiy
.SetSource(req with {
Id = UserToken.Id
@ -244,6 +269,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<UserInfoRsp> SetEmailAsync(SetEmailReq req)
{
req.ThrowIfInvalid();
var user = Rpo.Where(a => a.Id == UserToken.Id).ToOne(a => new { a.Mobile, a.Version, a.Email });
// 如果已绑定手机号、需要手机安全验证
@ -277,6 +303,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<UserInfoRsp> SetMobileAsync(SetMobileReq req)
{
req.ThrowIfInvalid();
var user = await Rpo.Where(a => a.Id == UserToken.Id)
.ToOneAsync(a => new { a.Version, a.Mobile })
.ConfigureAwait(false);
@ -321,6 +348,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<uint> SetPasswordAsync(SetPasswordReq req)
{
req.ThrowIfInvalid();
var version = await Rpo.Where(a => a.Id == UserToken.Id && a.Password == req.OldPassword.Pwd().Guid())
.ToOneAsync(a => new long?(a.Version))
.ConfigureAwait(false);
@ -343,6 +371,7 @@ public sealed class UserService(
/// <inheritdoc />
public async Task<QueryUserRsp> UpdateAsync(UpdateUserReq req)
{
req.ThrowIfInvalid();
await CreateUpdateCheckAsync(req).ConfigureAwait(false);
// 主表
@ -374,6 +403,7 @@ public sealed class UserService(
/// <inheritdoc />
public Task UpdateSingleAsync(UpdateUserReq req)
{
req.ThrowIfInvalid();
return Rpo.UpdateAsync(req);
}

View File

@ -19,6 +19,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -30,6 +31,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<QueryVerifyCodeRsp> CreateAsync(CreateVerifyCodeReq req)
{
req.ThrowIfInvalid();
var entity = await Rpo.InsertAsync(req).ConfigureAwait(false);
var ret = entity.Adapt<QueryVerifyCodeRsp>();
@ -43,18 +45,21 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryVerifyCodeReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryVerifyCodeRsp> GetAsync(QueryVerifyCodeReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryVerifyCodeReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -64,6 +69,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryVerifyCodeRsp>> PagedQueryAsync(PagedQueryReq<QueryVerifyCodeReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -77,6 +83,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<IEnumerable<QueryVerifyCodeRsp>> QueryAsync(QueryReq<QueryVerifyCodeReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryVerifyCodeRsp>>();
}
@ -84,6 +91,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<SendVerifyCodeRsp> SendVerifyCodeAsync(SendVerifyCodeReq req)
{
req.ThrowIfInvalid();
var lastSent = await GetLastSentAsync(req.DestDevice).ConfigureAwait(false);
QueryVerifyCodeRsp ret;
@ -110,6 +118,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<QueryVerifyCodeRsp> UpdateAsync(UpdateVerifyCodeReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QueryVerifyCodeRsp;
}
@ -121,6 +130,7 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
/// <inheritdoc />
public async Task<bool> VerifyAsync(VerifyCodeReq req)
{
req.ThrowIfInvalid();
#if DEBUG
if (req.Code == "8888") {
return true;

View File

@ -15,6 +15,7 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var sum = 0;
foreach (var item in req.Items) {
sum += await DeleteAsync(item).ConfigureAwait(false);
@ -26,6 +27,7 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public async Task<QueryExampleRsp> CreateAsync(CreateExampleReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryExampleRsp>();
}
@ -33,18 +35,21 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).AnyAsync();
}
/// <inheritdoc />
public async Task<QueryExampleRsp> GetAsync(QueryExampleReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryExampleReq> { Filter = req })
.ToOneAsync()
.ConfigureAwait(false);
@ -54,6 +59,7 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.Count(out var total)
@ -67,6 +73,7 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public async Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).Take(req.Count).ToListAsync().ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryExampleRsp>>();
}
@ -74,6 +81,7 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
/// <inheritdoc />
public async Task<QueryExampleRsp> UpdateAsync(UpdateExampleReq req)
{
req.ThrowIfInvalid();
if (Rpo.Orm.Ado.DataType == DataType.Sqlite) {
return await UpdateForSqliteAsync(req).ConfigureAwait(false) as QueryExampleRsp;
}

View File

@ -0,0 +1,10 @@
using NetAdmin.Cache;
using NetAdmin.SysComponent.Application.Modules.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Cache.Sys.Dependency;
/// <summary>
/// 计划作业缓存
/// </summary>
public interface IJobCache : ICache<IDistributedCache, IJobService>, IJobModule;

View File

@ -0,0 +1,10 @@
using NetAdmin.Cache;
using NetAdmin.SysComponent.Application.Modules.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Cache.Sys.Dependency;
/// <summary>
/// 计划作业执行记录缓存
/// </summary>
public interface IJobRecordCache : ICache<IDistributedCache, IJobRecordService>, IJobRecordModule;

View File

@ -0,0 +1,66 @@
using NetAdmin.Cache;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using NetAdmin.SysComponent.Cache.Sys.Dependency;
namespace NetAdmin.SysComponent.Cache.Sys;
/// <inheritdoc cref="IJobCache" />
public sealed class JobCache(IDistributedCache cache, IJobService service)
: DistributedCache<IJobService>(cache, service), IScoped, IJobCache
{
/// <inheritdoc />
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
return Service.BulkDeleteAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRsp> CreateAsync(CreateJobReq req)
{
return Service.CreateAsync(req);
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
return Service.DeleteAsync(req);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
{
return Service.ExistAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRsp> GetAsync(QueryJobReq req)
{
return Service.GetAsync(req);
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryJobRsp>> PagedQueryAsync(PagedQueryReq<QueryJobReq> req)
{
return Service.PagedQueryAsync(req);
}
/// <inheritdoc />
public Task<IEnumerable<QueryJobRsp>> QueryAsync(QueryReq<QueryJobReq> req)
{
return Service.QueryAsync(req);
}
/// <inheritdoc />
public Task SetEnabledAsync(UpdateJobReq req)
{
return Service.SetEnabledAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRsp> UpdateAsync(UpdateJobReq req)
{
return Service.UpdateAsync(req);
}
}

View File

@ -0,0 +1,60 @@
using NetAdmin.Cache;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.JobRecord;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using NetAdmin.SysComponent.Cache.Sys.Dependency;
namespace NetAdmin.SysComponent.Cache.Sys;
/// <inheritdoc cref="IJobRecordCache" />
public sealed class JobRecordCache(IDistributedCache cache, IJobRecordService service)
: DistributedCache<IJobRecordService>(cache, service), IScoped, IJobRecordCache
{
/// <inheritdoc />
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
return Service.BulkDeleteAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRecordRsp> CreateAsync(CreateJobRecordReq req)
{
return Service.CreateAsync(req);
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
return Service.DeleteAsync(req);
}
/// <inheritdoc />
public Task<bool> ExistAsync(QueryReq<QueryJobRecordReq> req)
{
return Service.ExistAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req)
{
return Service.GetAsync(req);
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryJobRecordRsp>> PagedQueryAsync(PagedQueryReq<QueryJobRecordReq> req)
{
return Service.PagedQueryAsync(req);
}
/// <inheritdoc />
public Task<IEnumerable<QueryJobRecordRsp>> QueryAsync(QueryReq<QueryJobRecordReq> req)
{
return Service.QueryAsync(req);
}
/// <inheritdoc />
public Task<QueryJobRecordRsp> UpdateAsync(UpdateJobRecordReq req)
{
return Service.UpdateAsync(req);
}
}

View File

@ -0,0 +1,92 @@
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.Host.Attributes;
using NetAdmin.Host.Controllers;
using NetAdmin.SysComponent.Application.Modules.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using NetAdmin.SysComponent.Cache.Sys.Dependency;
namespace NetAdmin.SysComponent.Host.Controllers.Sys;
/// <summary>
/// 计划作业服务
/// </summary>
[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))]
public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, IJobService>(cache), IJobModule
{
/// <summary>
/// 批量删除计划作业
/// </summary>
[Transaction]
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
return Cache.BulkDeleteAsync(req);
}
/// <summary>
/// 创建计划作业
/// </summary>
[Transaction]
public Task<QueryJobRsp> CreateAsync(CreateJobReq req)
{
return Cache.CreateAsync(req);
}
/// <summary>
/// 删除计划作业
/// </summary>
[Transaction]
public Task<int> DeleteAsync(DelReq req)
{
return Cache.DeleteAsync(req);
}
/// <summary>
/// 计划作业是否存在
/// </summary>
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
{
return Cache.ExistAsync(req);
}
/// <summary>
/// 获取单个计划作业
/// </summary>
public Task<QueryJobRsp> GetAsync(QueryJobReq req)
{
return Cache.GetAsync(req);
}
/// <summary>
/// 分页查询计划作业
/// </summary>
public Task<PagedQueryRsp<QueryJobRsp>> PagedQueryAsync(PagedQueryReq<QueryJobReq> req)
{
return Cache.PagedQueryAsync(req);
}
/// <summary>
/// 查询计划作业
/// </summary>
public Task<IEnumerable<QueryJobRsp>> QueryAsync(QueryReq<QueryJobReq> req)
{
return Cache.QueryAsync(req);
}
/// <summary>
/// 启用/禁用作业
/// </summary>
public Task SetEnabledAsync(UpdateJobReq req)
{
return Cache.SetEnabledAsync(req);
}
/// <summary>
/// 更新计划作业
/// </summary>
[Transaction]
public Task<QueryJobRsp> UpdateAsync(UpdateJobReq req)
{
return Cache.UpdateAsync(req);
}
}

View File

@ -0,0 +1,21 @@
using Furion.Schedule;
using NetAdmin.SysComponent.Host.Jobs;
namespace NetAdmin.SysComponent.Host.Extensions;
/// <summary>
/// ServiceCollection 扩展方法
/// </summary>
[SuppressSniffer]
public static class ServiceCollectionExtensions
{
/// <summary>
/// 添加定时任务
/// </summary>
public static IServiceCollection AddSchedules(this IServiceCollection me)
{
return me.AddSchedule( //
builder => builder //
.AddJob<ScheduledJob>(false, Triggers.PeriodSeconds(5).SetRunOnStart(true)));
}
}

View File

@ -0,0 +1,141 @@
using FreeSql.Internal;
using Furion.RemoteRequest;
using Furion.RemoteRequest.Extensions;
using Furion.Schedule;
using NetAdmin.Domain.DbMaps.Sys;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.Domain.Dto.Sys.JobRecord;
using NetAdmin.Host.BackgroundRunning;
using NetAdmin.Host.Extensions;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Host.Jobs;
/// <summary>
/// 计划作业
/// </summary>
public sealed class ScheduledJob : WorkBase<ScheduledJob>, IJob
{
private static string _accessToken;
private static string _refreshToken;
private readonly IJobRecordService _jobRecordService;
private readonly IJobService _jobService;
private readonly ILogger<ScheduledJob> _logger;
private readonly IUserService _userService;
private string _requestHeader;
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledJob" /> class.
/// </summary>
public ScheduledJob()
{
_jobRecordService = ServiceProvider.GetService<IJobRecordService>();
_jobService = ServiceProvider.GetService<IJobService>();
_logger = ServiceProvider.GetService<ILogger<ScheduledJob>>();
_userService = ServiceProvider.GetService<IUserService>();
}
/// <summary>
/// 具体处理逻辑
/// </summary>
/// <param name="context">作业执行前上下文</param>
/// <param name="stoppingToken">取消任务 Token</param>
/// <exception cref="NetAdminGetLockerException">加锁失败异常</exception>
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
await WorkflowAsync(stoppingToken).ConfigureAwait(false);
}
/// <summary>
/// 通用工作流
/// </summary>
/// <exception cref="NotImplementedException">NotImplementedException</exception>
/// <exception cref="ArgumentOutOfRangeException">ArgumentOutOfRangeException</exception>
protected override async ValueTask WorkflowAsync(CancellationToken cancelToken)
{
QueryJobRsp job = null;
try {
job = await _jobService.GetNextJobAsync().ConfigureAwait(false);
}
catch (DbUpdateVersionException) {
// ignore
}
if (job == null) {
_logger.Info(Ln.);
return;
}
var request = BuildRequest(job);
var sw = new Stopwatch();
sw.Start();
var rsp = await request.SendAsync(cancelToken).ConfigureAwait(false);
if (rsp.StatusCode == HttpStatusCode.Unauthorized) {
var loginRsp = await _userService.LoginByUserIdAsync(job.UserId).ConfigureAwait(false);
#pragma warning disable S2696
_accessToken = loginRsp.AccessToken;
_refreshToken = loginRsp.RefreshToken;
#pragma warning restore S2696
request = BuildRequest(job);
rsp = await request.SendAsync(cancelToken).ConfigureAwait(false);
}
sw.Stop();
await UowManager.AtomicOperateAsync(async () => {
var rspBody = await rsp.Content.ReadAsStringAsync(cancelToken).ConfigureAwait(false);
var jobRecord = new CreateJobRecordReq //
{
Duration = sw.ElapsedMilliseconds
, HttpMethod = job.HttpMethod
, HttpStatusCode = rsp.StatusCode
, JobId = job.Id
, RequestBody = job.RequestBody
, RequestHeader = _requestHeader
, RequestUrl = job.RequestUrl
, ResponseBody = rspBody
, ResponseHeader = rsp.Headers.Json()
, TimeId = job.NextTimeId!.Value
};
_ = await _jobRecordService.CreateAsync(jobRecord).ConfigureAwait(false);
await _jobService
.FinishJobAsync(job.Adapt<UpdateJobReq>() with { LastStatusCode = rsp.StatusCode })
.ConfigureAwait(false);
})
.ConfigureAwait(false);
}
private HttpRequestPart BuildRequest(Sys_Job job)
{
var ret = job.RequestUrl.SetHttpMethod(new HttpMethod(job.HttpMethod.ToString()));
var headers = new Dictionary<string, string>();
if (!_accessToken.NullOrEmpty()) {
headers.Add(Chars.FLG_ACCESS_TOKEN_HEADER_KEY, $"{Chars.FLG_AUTH_SCHEMA} {_accessToken}");
}
if (!_refreshToken.NullOrEmpty()) {
headers.Add(Chars.FLG_X_ACCESS_TOKEN_HEADER_KEY, $"{Chars.FLG_AUTH_SCHEMA} {_refreshToken}");
}
if (!job.RequestHeader.NullOrEmpty()) {
ret = ret.SetHeaders(headers.Union(job.RequestHeader.Object<Dictionary<string, string>>())
.ToDictionary(x => x.Key, x => x.Value));
}
if (!job.RequestBody.NullOrEmpty()) {
ret = ret.SetBody(job.RequestBody);
}
return ret.OnResponsing(GetRequestHeader).OnException(GetRequestHeader);
}
private void GetRequestHeader(HttpClient _, HttpResponseMessage rsp, string __)
{
_requestHeader = rsp!.RequestMessage!.Headers.Json();
}
private void GetRequestHeader(HttpClient _, HttpResponseMessage rsp)
{
GetRequestHeader(_, rsp, null);
}
}