diff --git a/Directory.Packages.props b/Directory.Packages.props
index 5df0b8e..0bf3d86 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -2,13 +2,14 @@
true
true
- 8.1.23
+ 8.1.24
+ 4.7.2
-
+
@@ -29,38 +30,37 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
-
+
-
+
-
-
-
-
+
+
+
+
-
+
@@ -72,7 +72,7 @@
-
+
@@ -108,7 +108,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Documents/SCRIPTS_MSSQL.md b/Documents/SCRIPTS_MSSQL.md
index 4ab7373..25c5e26 100644
--- a/Documents/SCRIPTS_MSSQL.md
+++ b/Documents/SCRIPTS_MSSQL.md
@@ -5,7 +5,7 @@ CREATE TABLE [operate_log] (
[Id] bigint NOT NULL,
[Module] varchar(20) NOT NULL,
[Type] varchar(50) NOT NULL,
- [Description] varchar(2000) NULL,
+ [Content] varchar(2000) NULL,
[UserName] varchar(64) NULL,
[OperateTime] datetime DEFAULT getdate() NOT NULL,
[Error] varchar(2000) NULL,
diff --git a/Documents/SCRIPTS_MYSQL.md b/Documents/SCRIPTS_MYSQL.md
index 15290ec..9a702ab 100644
--- a/Documents/SCRIPTS_MYSQL.md
+++ b/Documents/SCRIPTS_MYSQL.md
@@ -5,7 +5,7 @@ CREATE TABLE `operate_log` (
`Id` bigint NOT NULL,
`Module` varchar(20) NOT NULL,
`Type` varchar(50) NOT NULL,
- `Description` varchar(2000) NULL DEFAULT NULL,
+ `Content` varchar(2000) NULL DEFAULT NULL,
`UserName` varchar(64) NULL DEFAULT NULL,
`OperateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`Error` varchar(2000) NULL DEFAULT NULL,
diff --git a/Documents/SCRIPTS_PGSQL.md b/Documents/SCRIPTS_PGSQL.md
index c16ba7a..b0aa356 100644
--- a/Documents/SCRIPTS_PGSQL.md
+++ b/Documents/SCRIPTS_PGSQL.md
@@ -5,7 +5,7 @@ CREATE TABLE "public"."operate_log" (
"Id" int8 NOT NULL,
"Module" varchar(20) COLLATE "pg_catalog"."default" NOT NULL,
"Type" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
- "Description" varchar(2000) COLLATE "pg_catalog"."default",
+ "Content" varchar(2000) COLLATE "pg_catalog"."default",
"UserName" varchar(255) COLLATE "pg_catalog"."default",
"OperateTime" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"Error" varchar(2000) COLLATE "pg_catalog"."default",
@@ -86,10 +86,10 @@ CREATE TABLE "public"."configuration_item" (
;
CREATE INDEX "IDX_CONFIG_ITEM_FK" ON "public"."configuration_item" USING btree (
- "ConfigurationId" "pg_catalog"."int8_ops" ASC NULLS LAST
+ "ConfigurationId" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
CREATE UNIQUE INDEX "IDX_CONFIG_ITEM_UNIQUE" ON "public"."configuration_item" USING btree (
- "ConfigurationId" "pg_catalog"."int8_ops" ASC NULLS LAST,
+ "ConfigurationId" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
"Key" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
```
@@ -110,7 +110,7 @@ CREATE TABLE "public"."configuration_revision" (
;
CREATE INDEX "IDS_CONFIG_REVISION_FK" ON "public"."configuration_revision" USING btree (
- "ConfigurationId" "pg_catalog"."int8_ops" ASC NULLS LAST
+ "ConfigurationId" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
```
diff --git a/Documents/SCRIPTS_SQLITE.md b/Documents/SCRIPTS_SQLITE.md
index 330aeef..f68f195 100644
--- a/Documents/SCRIPTS_SQLITE.md
+++ b/Documents/SCRIPTS_SQLITE.md
@@ -5,7 +5,7 @@ CREATE TABLE "operate_log" (
"Id" integer NOT NULL,
"Module" text NOT NULL,
"Type" text NOT NULL,
- "Description" text,
+ "Content" text,
"UserName" text,
"OperateTime" text NOT NULL,
"Error" text,
diff --git a/README.md b/README.md
index a683d3c..e87cb5c 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
# Overview/概览 ⚡
-[]()
+[](https://github.com/NerosoftDev/Starfish/actions)
[](LICENSE)
-[]()
-[]()
+[](https://github.com/NerosoftDev/Starfish/releases)
+[](https://github.com/NerosoftDev/Starfish/stargazers)
Starfish is a lightweight powerful distributed configuration server for .NET application.
diff --git a/Source/Starfish.Common/Constants.cs b/Source/Starfish.Common/Constants.cs
index 4d7fecf..41cdbc6 100644
--- a/Source/Starfish.Common/Constants.cs
+++ b/Source/Starfish.Common/Constants.cs
@@ -37,5 +37,6 @@ public static class Configuration
public static class RegexPattern
{
public const string Secret = @"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,32}$";
+ public const string Password = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\x00-\xff]{8,32}$";
}
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Application/Commands/Identity/ChangePasswordCommand.cs b/Source/Starfish.Service/Application/Commands/Identity/ChangePasswordCommand.cs
index d21d04d..2333a0e 100644
--- a/Source/Starfish.Service/Application/Commands/Identity/ChangePasswordCommand.cs
+++ b/Source/Starfish.Service/Application/Commands/Identity/ChangePasswordCommand.cs
@@ -11,11 +11,12 @@ public ChangePasswordCommand()
{
}
- public ChangePasswordCommand(string userId, string password)
+ public ChangePasswordCommand(string userId, string password, string actionType)
: this()
{
UserId = userId;
Password = password;
+ ActionType = actionType;
}
///
@@ -27,4 +28,10 @@ public ChangePasswordCommand(string userId, string password)
/// 新密码
///
public string Password { get; set; }
+
+ ///
+ /// 操作方式
+ ///
+ /// change-修改;reset-重置
+ public string ActionType { get; set; }
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Application/Handlers/UserCommandHandler.cs b/Source/Starfish.Service/Application/Handlers/UserCommandHandler.cs
index 9a35d2d..c28aceb 100644
--- a/Source/Starfish.Service/Application/Handlers/UserCommandHandler.cs
+++ b/Source/Starfish.Service/Application/Handlers/UserCommandHandler.cs
@@ -10,10 +10,10 @@ namespace Nerosoft.Starfish.Application;
/// 用户命令处理器
///
public sealed class UserCommandHandler : CommandHandlerBase,
- IHandler,
- IHandler,
- IHandler,
- IHandler
+ IHandler,
+ IHandler,
+ IHandler,
+ IHandler
{
///
/// 初始化.
@@ -58,7 +58,7 @@ public Task HandleAsync(UserUpdateCommand message, MessageContext context, Cance
business.IsAdmin = message.Item2.IsAdmin;
business.MarkAsUpdate();
-
+
await business.SaveAsync(true, cancellationToken);
});
}
@@ -68,11 +68,7 @@ public Task HandleAsync(ChangePasswordCommand message, MessageContext context, C
{
return ExecuteAsync(async () =>
{
- var business = await Factory.FetchAsync(message.UserId, cancellationToken);
-
- business.Password = message.Password;
- business.MarkAsUpdate();
- await business.SaveAsync(true, cancellationToken);
+ _ = await Factory.ExecuteAsync(message.UserId, message.Password, message.ActionType, cancellationToken);
});
}
diff --git a/Source/Starfish.Service/Application/Mappings/LogsMappingProfile.cs b/Source/Starfish.Service/Application/Mappings/LogsMappingProfile.cs
index 1dc330f..167682c 100644
--- a/Source/Starfish.Service/Application/Mappings/LogsMappingProfile.cs
+++ b/Source/Starfish.Service/Application/Mappings/LogsMappingProfile.cs
@@ -15,17 +15,20 @@ internal class LogsMappingProfile : Profile
public LogsMappingProfile()
{
CreateMap()
- .ForMember(dest => dest.Type, opt => opt.MapFrom(src => GetTypeName(src.Type)));
+ .ForMember(dest => dest.Description, opt => opt.MapFrom(GetDescription));
}
- private static string GetTypeName(string type)
+ private static string GetDescription(OperateLog source, OperateLogDto destination, object obj, ResolutionContext context)
{
- return type.ToLowerInvariant() switch
+ var key = $"IDS_LOG_MESSAGE_{source.Module}_{source.Type}".Normalize(TextCaseType.Upper).Replace(".", "_");
+
+ var value = Resources.ResourceManager.GetString(key);
+
+ if (string.IsNullOrEmpty(value))
{
- "auth.password" => "密码登录",
- "auth.refresh_token" => "刷新Token",
- "auth.otp" => "验证码登录",
- _ => type
- };
+ return value;
+ }
+
+ return string.Format(value, source.Content);
}
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Auth.cs b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Auth.cs
new file mode 100644
index 0000000..b556022
--- /dev/null
+++ b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Auth.cs
@@ -0,0 +1,54 @@
+using Nerosoft.Euonia.Bus;
+using Nerosoft.Starfish.Domain;
+
+namespace Nerosoft.Starfish.Application;
+
+internal partial class LoggingEventSubscriber
+{
+ private const string MODULE_AUTH = "auth";
+
+ ///
+ /// 处理用户认证成功事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(UserAuthSucceedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_AUTH,
+ Type = @event.AuthType,
+ UserName = @event.UserName,
+ OperateTime = DateTime.Now,
+ Description = Resources.IDS_MESSAGE_LOGS_AUTH_SUCCEED,
+ RequestTraceId = context.RequestTraceId
+ };
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理用户认证失败事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(UserAuthFailedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_AUTH,
+ Type = @event.AuthType,
+ Description = Resources.IDS_MESSAGE_LOGS_AUTH_FAILED,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ Error = @event.Error
+ };
+
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+}
diff --git a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Config.cs b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Config.cs
new file mode 100644
index 0000000..d309122
--- /dev/null
+++ b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Config.cs
@@ -0,0 +1,179 @@
+using Nerosoft.Euonia.Bus;
+using Nerosoft.Starfish.Domain;
+
+namespace Nerosoft.Starfish.Application;
+
+internal partial class LoggingEventSubscriber
+{
+ private const string MODULE_CONFIG = "config";
+
+ ///
+ /// 处理配置启用事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationEnabledEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "status.enable",
+ Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_ENABLE, aggregate.Id, aggregate.Name),
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置禁用事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationDisableEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "status.disable",
+ Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_DISABLE, aggregate.Id, aggregate.Name),
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置密钥重置事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationSecretChangedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "secret",
+ Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_RESET_SECRET, aggregate.Id, aggregate.Name),
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置更新事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationUpdatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "update",
+ Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_UPDATE, aggregate.Id, aggregate.Name),
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置节点创建事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationCreatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_CREATE, @event.Configuration.Id, @event.Configuration.Name);
+
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "create",
+ Description = description,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置节点删除事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationDeletedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_DELETE, aggregate.Id, aggregate.Name);
+
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "delete",
+ Description = description,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ ///
+ /// 处理配置发布事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Subscribe]
+ public Task HandleAsync(ConfigurationPublishedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_PUBLISH, aggregate.Id, aggregate.Name);
+
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_CONFIG,
+ Type = "publish",
+ Description = description,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId,
+ UserName = context.User?.Identity?.Name
+ };
+ return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+}
diff --git a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Team.cs b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Team.cs
new file mode 100644
index 0000000..fb45ab2
--- /dev/null
+++ b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.Team.cs
@@ -0,0 +1,54 @@
+using Nerosoft.Euonia.Bus;
+using Nerosoft.Starfish.Domain;
+
+namespace Nerosoft.Starfish.Application;
+
+internal partial class LoggingEventSubscriber
+{
+ private const string MODULE_TEAM = "team";
+
+ [Subscribe]
+ public async Task HandleAsync(TeamCreatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_TEAM,
+ Type = "create",
+ OperateTime = DateTime.Now,
+ UserName = context.User?.Identity?.Name,
+ RequestTraceId = context.RequestTraceId
+ };
+ await _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ [Subscribe]
+ public async Task HandleAsync(TeamMemberAppendedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_TEAM,
+ Type = "member.append",
+ OperateTime = DateTime.Now,
+ UserName = context.User?.Identity?.Name,
+ RequestTraceId = context.RequestTraceId
+ };
+ await _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ [Subscribe]
+ public async Task HandleAsync(TeamMemberRemovedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_TEAM,
+ Type = "member.remove",
+ OperateTime = DateTime.Now,
+ UserName = context.User?.Identity?.Name,
+ RequestTraceId = context.RequestTraceId
+ };
+ await _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+}
diff --git a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.User.cs b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.User.cs
new file mode 100644
index 0000000..1e2933e
--- /dev/null
+++ b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.User.cs
@@ -0,0 +1,38 @@
+using Nerosoft.Euonia.Bus;
+using Nerosoft.Starfish.Domain;
+
+namespace Nerosoft.Starfish.Application;
+
+internal sealed partial class LoggingEventSubscriber
+{
+ private const string MODULE_USER = "user";
+
+ [Subscribe]
+ public async Task HandleAsync(UserCreatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_USER,
+ Type = "create",
+ UserName = @event.UserName,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId
+ };
+ await _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+
+ [Subscribe]
+ public async Task HandleAsync(UserPasswordChangedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
+ {
+ var aggregate = @event.GetAggregate();
+ var command = new OperateLogCreateCommand
+ {
+ Module = MODULE_USER,
+ Type = "password",
+ UserName = aggregate.UserName,
+ OperateTime = DateTime.Now,
+ RequestTraceId = context.RequestTraceId
+ };
+ await _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
+ }
+}
diff --git a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.cs b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.cs
index 9b90848..bd35a7d 100644
--- a/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.cs
+++ b/Source/Starfish.Service/Application/Subscribers/LoggingEventSubscriber.cs
@@ -6,229 +6,12 @@ namespace Nerosoft.Starfish.Application;
///
/// 应用日志收集处理器
///
-public sealed class LoggingEventSubscriber
+internal sealed partial class LoggingEventSubscriber
{
- private const string MODULE_CONFIG = "config";
-
private readonly IBus _bus;
public LoggingEventSubscriber(IBus bus)
{
_bus = bus;
}
-
- ///
- /// 处理用户认证成功事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(UserAuthSucceedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var command = new OperateLogCreateCommand
- {
- Module = "auth",
- Type = @event.AuthType,
- UserName = @event.UserName,
- OperateTime = DateTime.Now,
- Description = Resources.IDS_MESSAGE_LOGS_AUTH_SUCCEED,
- RequestTraceId = context.RequestTraceId
- };
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理用户认证失败事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(UserAuthFailedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var command = new OperateLogCreateCommand
- {
- Module = "auth",
- Type = @event.AuthType,
- Description = Resources.IDS_MESSAGE_LOGS_AUTH_FAILED,
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- Error = @event.Error
- };
-
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置启用事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationEnabledEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "status",
- Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_ENABLE, aggregate.Id, aggregate.Name),
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
-
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置禁用事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationDisableEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "status",
- Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_DISABLE, aggregate.Id, aggregate.Name),
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
-
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置密钥重置事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationSecretChangedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "secret",
- Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_RESET_SECRET, aggregate.Id, aggregate.Name),
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
-
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置更新事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationUpdatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "update",
- Description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_UPDATE, aggregate.Id, aggregate.Name),
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
-
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置节点创建事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationCreatedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_CREATE, @event.Configuration.Id, @event.Configuration.Name);
-
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "create",
- Description = description,
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置节点删除事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationDeletedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_DELETE, aggregate.Id, aggregate.Name);
-
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "delete",
- Description = description,
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
-
- ///
- /// 处理配置发布事件
- ///
- ///
- ///
- ///
- ///
- [Subscribe]
- public Task HandleAsync(ConfigurationPublishedEvent @event, MessageContext context, CancellationToken cancellationToken = default)
- {
- var aggregate = @event.GetAggregate();
- var description = string.Format(Resources.IDS_MESSAGE_LOGS_CONFIG_PUBLISH, aggregate.Id, aggregate.Name);
-
- var command = new OperateLogCreateCommand
- {
- Module = MODULE_CONFIG,
- Type = "publish",
- Description = description,
- OperateTime = DateTime.Now,
- RequestTraceId = context.RequestTraceId,
- UserName = context.User?.Identity?.Name
- };
- return _bus.SendAsync(command, new SendOptions { RequestTraceId = context.RequestTraceId }, null, cancellationToken);
- }
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Application/TokenGenerator.cs b/Source/Starfish.Service/Application/TokenGenerator.cs
index 1b8412f..ad4b525 100644
--- a/Source/Starfish.Service/Application/TokenGenerator.cs
+++ b/Source/Starfish.Service/Application/TokenGenerator.cs
@@ -189,7 +189,7 @@ public string Build()
Issuer = Issuer,
Audience = Audience,
IssuedAt = IssueTime,
- SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
+ SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), Algorithm)
};
var token = handler.CreateToken(descriptor);
diff --git a/Source/Starfish.Service/Domain/Aggregates/OperateLog.cs b/Source/Starfish.Service/Domain/Aggregates/OperateLog.cs
index 61735e5..dd91898 100644
--- a/Source/Starfish.Service/Domain/Aggregates/OperateLog.cs
+++ b/Source/Starfish.Service/Domain/Aggregates/OperateLog.cs
@@ -24,7 +24,7 @@ private OperateLog()
///
/// 描述
///
- public string Description { get; set; }
+ public string Content { get; set; }
///
/// 用户名
@@ -46,13 +46,13 @@ private OperateLog()
///
public string RequestTraceId { get; set; }
- internal static OperateLog Create(string module, string type, string description, string userName, DateTime operateTime, string error, string requestTraceId)
+ internal static OperateLog Create(string module, string type, string content, string userName, DateTime operateTime, string error, string requestTraceId)
{
return new OperateLog
{
Module = module,
Type = type,
- Description = description,
+ Content = content,
UserName = userName,
OperateTime = operateTime,
Error = error,
diff --git a/Source/Starfish.Service/Domain/Aggregates/Team.cs b/Source/Starfish.Service/Domain/Aggregates/Team.cs
index 1386b0b..8319d24 100644
--- a/Source/Starfish.Service/Domain/Aggregates/Team.cs
+++ b/Source/Starfish.Service/Domain/Aggregates/Team.cs
@@ -7,14 +7,26 @@ namespace Nerosoft.Starfish.Domain;
/// 团队聚合根对象
///
public sealed class Team : Aggregate,
- IAuditing
+ IAuditing
{
+ ///
+ /// 团队名称
+ ///
public string Name { get; set; }
+ ///
+ /// 团队描述
+ ///
public string Description { get; set; }
+ ///
+ /// 团队负责人Id
+ ///
public string OwnerId { get; set; }
+ ///
+ /// 团队成员数
+ ///
public int MemberCount { get; set; }
public DateTime CreateTime { get; set; }
@@ -35,10 +47,15 @@ internal static Team Create(string name, string description, string ownerId)
Description = description,
OwnerId = ownerId
};
- team.AddMember(ownerId);
+ team.AppendMember(ownerId);
+ team.RaiseEvent(new TeamCreatedEvent());
return team;
}
+ ///
+ /// 设置团队名称
+ ///
+ ///
internal void SetName(string name)
{
if (string.Equals(Name, name))
@@ -49,6 +66,10 @@ internal void SetName(string name)
Name = name;
}
+ ///
+ /// 设置团队描述
+ ///
+ ///
internal void SetDescription(string description)
{
if (string.Equals(Description, description))
@@ -59,7 +80,11 @@ internal void SetDescription(string description)
Description = description;
}
- internal void AddMember(string userId)
+ ///
+ /// 添加团队成员
+ ///
+ ///
+ internal void AppendMember(string userId)
{
Members ??= [];
@@ -71,8 +96,18 @@ internal void AddMember(string userId)
Members.Add(TeamMember.Create(userId));
MemberCount++;
+
+ if (!string.IsNullOrEmpty(Id))
+ {
+ RaiseEvent(new TeamMemberAppendedEvent { UserId = userId });
+ }
}
+ ///
+ /// 移除团队成员
+ ///
+ ///
+ ///
internal void RemoveMember(string userId)
{
if (Members == null || Members.All(t => t.UserId != userId))
@@ -88,5 +123,7 @@ internal void RemoveMember(string userId)
Members.RemoveWhere(t => t.UserId == userId);
MemberCount--;
+
+ RaiseEvent(new TeamMemberRemovedEvent { UserId = userId });
}
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Domain/Aggregates/User.cs b/Source/Starfish.Service/Domain/Aggregates/User.cs
index 04141ab..4fb6b9f 100644
--- a/Source/Starfish.Service/Domain/Aggregates/User.cs
+++ b/Source/Starfish.Service/Domain/Aggregates/User.cs
@@ -21,14 +21,13 @@ private User()
/// 初始化用户聚合根
///
///
- ///
- ///
- private User(string userName, string passwordHash, string passwordSalt)
+ ///
+ ///
+ private User(string userName, string password)
: this()
{
UserName = userName;
- PasswordHash = passwordHash;
- PasswordSalt = passwordSalt;
+ SetPassword(password);
}
///
@@ -115,22 +114,25 @@ private User(string userName, string passwordHash, string passwordSalt)
///
internal static User Create(string userName, string password)
{
- var salt = RandomUtility.GenerateUniqueId();
- var hash = Cryptography.DES.Encrypt(password, Encoding.UTF8.GetBytes(salt));
- var entity = new User(userName, hash, salt);
+ var entity = new User(userName, password);
return entity;
}
///
- /// 修改密码
+ /// 设置密码
///
///
- internal void ChangePassword(string password)
+ ///
+ internal void SetPassword(string password, string actionType = null)
{
var salt = RandomUtility.GenerateUniqueId();
var hash = Cryptography.DES.Encrypt(password, Encoding.UTF8.GetBytes(salt));
PasswordHash = hash;
PasswordSalt = salt;
+ if (!string.IsNullOrWhiteSpace(actionType))
+ {
+ RaiseEvent(new UserPasswordChangedEvent { Type = actionType });
+ }
}
///
diff --git a/Source/Starfish.Service/Domain/Business/TeamMemberBusiness.cs b/Source/Starfish.Service/Domain/Business/TeamMemberBusiness.cs
index d1f4f33..a8ee16e 100644
--- a/Source/Starfish.Service/Domain/Business/TeamMemberBusiness.cs
+++ b/Source/Starfish.Service/Domain/Business/TeamMemberBusiness.cs
@@ -43,7 +43,7 @@ protected override Task InsertAsync(CancellationToken cancellationToken = defaul
{
foreach (var userId in UserIds)
{
- Aggregate.AddMember(userId);
+ Aggregate.AppendMember(userId);
}
return TeamRepository.UpdateAsync(Aggregate, true, cancellationToken);
diff --git a/Source/Starfish.Service/Domain/Business/UserGeneralBusiness.cs b/Source/Starfish.Service/Domain/Business/UserGeneralBusiness.cs
index 44ed584..00e2944 100644
--- a/Source/Starfish.Service/Domain/Business/UserGeneralBusiness.cs
+++ b/Source/Starfish.Service/Domain/Business/UserGeneralBusiness.cs
@@ -160,11 +160,6 @@ protected override Task UpdateAsync(CancellationToken cancellationToken = defaul
Aggregate.SetNickName(NickName);
}
- if (ChangedProperties.Contains(PasswordProperty))
- {
- Aggregate.ChangePassword(Password);
- }
-
if (ChangedProperties.Contains(IsAdminProperty))
{
Aggregate.SetIsAdmin(IsAdmin);
@@ -272,8 +267,6 @@ public override async Task ExecuteAsync(IRuleContext context, CancellationToken
public class PasswordStrengthRule : RuleBase
{
- private const string REGEX_PATTERN = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\x00-\xff]{8,32}$";
-
public override Task ExecuteAsync(IRuleContext context, CancellationToken cancellationToken = default)
{
var target = (UserGeneralBusiness)context.Target;
@@ -284,12 +277,12 @@ public override Task ExecuteAsync(IRuleContext context, CancellationToken cancel
{
context.AddErrorResult(Resources.IDS_ERROR_USER_RULE_PASSWORD_REQUIRED);
}
- else if (!Regex.IsMatch(target.Password, REGEX_PATTERN))
+ else if (!Regex.IsMatch(target.Password, Constants.RegexPattern.Password))
{
context.AddErrorResult(Resources.IDS_ERROR_USER_RULE_PASSWORD_NOT_MARCHED_RULES);
}
}
- else if (target.IsUpdate && target.ChangedProperties.Contains(PasswordProperty) && !Regex.IsMatch(target.Password, REGEX_PATTERN))
+ else if (target.IsUpdate && target.ChangedProperties.Contains(PasswordProperty) && !Regex.IsMatch(target.Password, Constants.RegexPattern.Password))
{
context.AddErrorResult(Resources.IDS_ERROR_USER_RULE_PASSWORD_NOT_MARCHED_RULES);
}
diff --git a/Source/Starfish.Service/Domain/Business/UserPasswordBusiness.cs b/Source/Starfish.Service/Domain/Business/UserPasswordBusiness.cs
new file mode 100644
index 0000000..b21ebf4
--- /dev/null
+++ b/Source/Starfish.Service/Domain/Business/UserPasswordBusiness.cs
@@ -0,0 +1,36 @@
+using System.Text.RegularExpressions;
+using Nerosoft.Euonia.Business;
+using Nerosoft.Euonia.Domain;
+using Nerosoft.Starfish.Service;
+
+namespace Nerosoft.Starfish.Domain;
+
+internal class UserPasswordBusiness : CommandObjectBase, IDomainService
+{
+ [Inject]
+ public IUserRepository Repository { get; set; }
+
+ [FactoryExecute]
+ protected async Task ExecuteAsync(string id, string password, string actionType, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(password))
+ {
+ throw new ValidationException(Resources.IDS_ERROR_USER_RULE_PASSWORD_REQUIRED);
+ }
+ else if (!Regex.IsMatch(password, Constants.RegexPattern.Password))
+ {
+ throw new ValidationException(Resources.IDS_ERROR_USER_RULE_PASSWORD_NOT_MARCHED_RULES);
+ }
+
+ var aggregate = await Repository.GetAsync(id, true, cancellationToken);
+
+ if (aggregate == null)
+ {
+ throw new UserNotFoundException(id);
+ }
+
+ aggregate.SetPassword(password, actionType);
+
+ await Repository.UpdateAsync(aggregate, true, cancellationToken);
+ }
+}
diff --git a/Source/Starfish.Service/Domain/Events/TeamCreatedEvent.cs b/Source/Starfish.Service/Domain/Events/TeamCreatedEvent.cs
new file mode 100644
index 0000000..34fd9b4
--- /dev/null
+++ b/Source/Starfish.Service/Domain/Events/TeamCreatedEvent.cs
@@ -0,0 +1,7 @@
+using Nerosoft.Euonia.Domain;
+
+namespace Nerosoft.Starfish.Domain;
+
+internal sealed class TeamCreatedEvent : DomainEvent
+{
+}
diff --git a/Source/Starfish.Service/Domain/Events/TeamMemberAppendedEvent.cs b/Source/Starfish.Service/Domain/Events/TeamMemberAppendedEvent.cs
new file mode 100644
index 0000000..5ac46e5
--- /dev/null
+++ b/Source/Starfish.Service/Domain/Events/TeamMemberAppendedEvent.cs
@@ -0,0 +1,8 @@
+using Nerosoft.Euonia.Domain;
+
+namespace Nerosoft.Starfish.Domain;
+
+internal sealed class TeamMemberAppendedEvent : DomainEvent
+{
+ public string UserId { get; set; }
+}
diff --git a/Source/Starfish.Service/Domain/Events/TeamMemberRemovedEvent.cs b/Source/Starfish.Service/Domain/Events/TeamMemberRemovedEvent.cs
new file mode 100644
index 0000000..b079cf0
--- /dev/null
+++ b/Source/Starfish.Service/Domain/Events/TeamMemberRemovedEvent.cs
@@ -0,0 +1,8 @@
+using Nerosoft.Euonia.Domain;
+
+namespace Nerosoft.Starfish.Domain;
+
+internal class TeamMemberRemovedEvent : DomainEvent
+{
+ public string UserId { get; set; }
+}
diff --git a/Source/Starfish.Service/Domain/Events/UserCreatedEvent.cs b/Source/Starfish.Service/Domain/Events/UserCreatedEvent.cs
index 6a7c829..4a835ee 100644
--- a/Source/Starfish.Service/Domain/Events/UserCreatedEvent.cs
+++ b/Source/Starfish.Service/Domain/Events/UserCreatedEvent.cs
@@ -5,7 +5,7 @@ namespace Nerosoft.Starfish.Domain;
///
/// 用户创建事件
///
-public sealed class UserCreatedEvent : DomainEvent
+internal sealed class UserCreatedEvent : DomainEvent
{
///
/// 用户名
diff --git a/Source/Starfish.Service/Domain/Events/UserPasswordChangedEvent.cs b/Source/Starfish.Service/Domain/Events/UserPasswordChangedEvent.cs
index e18874f..e788d69 100644
--- a/Source/Starfish.Service/Domain/Events/UserPasswordChangedEvent.cs
+++ b/Source/Starfish.Service/Domain/Events/UserPasswordChangedEvent.cs
@@ -7,4 +7,12 @@ namespace Nerosoft.Starfish.Domain;
///
public sealed class UserPasswordChangedEvent : DomainEvent
{
+ ///
+ /// 操作类型
+ ///
+ ///
+ /// - change
+ /// - reset
+ ///
+ public string Type { get; set; }
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/Properties/Resources.resx b/Source/Starfish.Service/Properties/Resources.resx
index 10f0254..45f5b53 100644
--- a/Source/Starfish.Service/Properties/Resources.resx
+++ b/Source/Starfish.Service/Properties/Resources.resx
@@ -258,6 +258,39 @@
UserName '{0}' not available.
+
+ Login with one-time-password
+
+
+ Login with password
+
+
+ Refresh token
+
+
+ Create team
+
+
+ Add new member
+
+
+ Remove member
+
+
+ Update team
+
+
+ Create user
+
+
+ Change password
+
+
+ Reset password
+
+
+ Update user
+
User authenticate failed.
diff --git a/Source/Starfish.Service/UseCases/Identity/ChangePasswordUseCase.cs b/Source/Starfish.Service/UseCases/Identity/ChangePasswordUseCase.cs
index 8bd518b..11a7215 100644
--- a/Source/Starfish.Service/UseCases/Identity/ChangePasswordUseCase.cs
+++ b/Source/Starfish.Service/UseCases/Identity/ChangePasswordUseCase.cs
@@ -45,7 +45,7 @@ public async Task ExecuteAsync(ChangePasswordInput input, CancellationToken canc
throw new BadRequestException(Resources.IDS_ERROR_PASSWORD_INCORRECT);
}
- var command = new ChangePasswordCommand(user.Id, input.NewPassword);
+ var command = new ChangePasswordCommand(user.Id, input.NewPassword, "change");
await _bus.SendAsync(command, cancellationToken);
}
}
\ No newline at end of file
diff --git a/Source/Starfish.Service/UseCases/Identity/ResetPasswordUseCase.cs b/Source/Starfish.Service/UseCases/Identity/ResetPasswordUseCase.cs
index 1240a2f..77ab0db 100644
--- a/Source/Starfish.Service/UseCases/Identity/ResetPasswordUseCase.cs
+++ b/Source/Starfish.Service/UseCases/Identity/ResetPasswordUseCase.cs
@@ -19,7 +19,7 @@ public ResetPasswordUseCase(IBus bus)
public Task ExecuteAsync(ResetPasswordInput input, CancellationToken cancellationToken = default)
{
- var command = new ChangePasswordCommand(input.Id, input.Password);
+ var command = new ChangePasswordCommand(input.Id, input.Password, "reset");
return _bus.SendAsync(command, cancellationToken);
}
}
\ No newline at end of file
diff --git a/Source/Starfish.Transit/Logging/OperateLogDto.cs b/Source/Starfish.Transit/Logging/OperateLogDto.cs
index 5b07802..b30eef2 100644
--- a/Source/Starfish.Transit/Logging/OperateLogDto.cs
+++ b/Source/Starfish.Transit/Logging/OperateLogDto.cs
@@ -10,16 +10,6 @@ public class OperateLogDto
///
public long Id { get; set; }
- ///
- /// 模块
- ///
- public string Module { get; set; }
-
- ///
- /// 类型
- ///
- public string Type { get; set; }
-
///
/// 描述
///
diff --git a/Source/Starfish.Webapi/Controllers/UserController.cs b/Source/Starfish.Webapi/Controllers/UserController.cs
index b43c90e..8b8810e 100644
--- a/Source/Starfish.Webapi/Controllers/UserController.cs
+++ b/Source/Starfish.Webapi/Controllers/UserController.cs
@@ -102,7 +102,7 @@ public async Task DeleteAsync(string id)
await _service.DeleteAsync(id, HttpContext.RequestAborted);
return Ok();
}
-
+
///
/// 重置指定用户密码
///
diff --git a/Tests/common.props b/Tests/common.props
index 4eeba74..e177f4c 100644
--- a/Tests/common.props
+++ b/Tests/common.props
@@ -13,13 +13,14 @@
+
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/global.props b/global.props
index a0a653a..ad45b6d 100644
--- a/global.props
+++ b/global.props
@@ -1,6 +1,6 @@
- 1.0.4
+ 1.0.5
damon
Nerosoft Ltd.
Starfish