wip: 解决配置管理+短信功能。优化大部分功能,解决启动bug

main
NoahLan 6 months ago
parent 76219dcfc3
commit f3382f9c8e

@ -0,0 +1,28 @@
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling;
namespace NPin.Framework.AspNetCore.Abp;
/// <summary>
/// NPin框架自定义 HttpStatusCode 处理器
/// 将 IBusinessException 与 IUserFriendlyException 默认返回403改为500
/// </summary>
public class NPinHttpExceptionStatusCodeFinder : DefaultHttpExceptionStatusCodeFinder
{
public NPinHttpExceptionStatusCodeFinder(IOptions<AbpExceptionHttpStatusCodeOptions> options) : base(options)
{
}
public override HttpStatusCode GetStatusCode(HttpContext httpContext, Exception exception)
{
switch (exception)
{
case IBusinessException _:
return HttpStatusCode.InternalServerError;
default:
return base.GetStatusCode(httpContext, exception);
}
}
}

@ -1,9 +1,17 @@
using NPin.Framework.Core;
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NPin.Framework.AspNetCore.Abp;
using NPin.Framework.Core;
using Volo.Abp.AspNetCore.ExceptionHandling;
namespace NPin.Framework.AspNetCore;
[DependsOn(typeof(NPinFrameworkCoreModule))]
public class NPinFrameworkAspNetCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(new ServiceDescriptor(typeof(IHttpExceptionStatusCodeFinder),
typeof(NPinHttpExceptionStatusCodeFinder), ServiceLifetime.Transient));
}
}

@ -69,7 +69,7 @@ public class DbConnOptions
return new SaasMultiTenancyOptions { Name = DefaultTenantName, Url = Url };
}
public SaasMultiTenancyOptions? GetDefaultMasterSaasMultiTenancy()
public SaasMultiTenancyOptions? GetMasterSaasMultiTenancy()
{
if (EnabledSaasMultiTenancy == false)
{

@ -1,16 +1,17 @@
using System.Reflection;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions;
using NPin.Framework.SqlSugarCore.Repositories;
using NPin.Framework.SqlSugarCore.Uow;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Modularity;
using Volo.Abp.Guids;
namespace NPin.Framework.SqlSugarCore;
@ -44,6 +45,37 @@ public class NPinFrameworkSqlSugarCoreModule : AbpModule
var service = context.ServiceProvider;
var options = service.GetRequiredService<IOptions<DbConnOptions>>().Value;
Configure<AbpSequentialGuidGeneratorOptions>(opt =>
{
switch (options.DbType)
{
case DbType.PostgreSQL:
case DbType.MySql:
opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString;
break;
case DbType.Oracle:
opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
break;
default:
opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAtEnd;
break;
}
});
var logger = service.GetRequiredService<ILogger<NPinFrameworkSqlSugarCoreModule>>();
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("==========NPin-SQL配置:==========");
sb.AppendLine($"数据库连接字符串:{options.Url}");
sb.AppendLine($"数据库类型:{options.DbType.ToString()}");
sb.AppendLine($"是否开启种子数据:{options.EnabledDbSeed}");
sb.AppendLine($"是否开启CodeFirst{options.EnabledCodeFirst}");
sb.AppendLine($"是否开启Saas多租户{options.EnabledSaasMultiTenancy}");
sb.AppendLine("===============================");
logger.LogInformation(sb.ToString());
if (options.EnabledCodeFirst)
{
CodeFirst(service);

@ -29,6 +29,7 @@ public class SqlSugarRepository<TEntity> : ISqlSugarRepository<TEntity>, IReposi
public virtual async Task<ISqlSugarClient> GetDbContextAsync()
{
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
// await Console.Out.WriteLineAsync("获取的id" + db.ContextID);
return db;
}

@ -78,6 +78,13 @@ public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransi
ConnectionString = dbConnOptions.Url,
IsAutoCloseConnection = true,
SlaveConnectionConfigs = slaveConfigs,
LanguageType = LanguageType.Chinese,
MoreSettings = new ConnMoreSettings
{
SqliteCodeFirstEnableDescription = true,
PgSqlIsAutoToLower = true,
PgSqlIsAutoToLowerCodeFirst = true,
},
// CodeFirst 非空值判断
ConfigureExternalServices = new ConfigureExternalServices
{

@ -23,7 +23,7 @@ public class SqlSugarDbContext : ISqlSugarDbContext
public ISqlSugarClient SqlSugarClient { get; private set; }
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
public ICurrentTenant? CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
@ -51,10 +51,42 @@ public class SqlSugarDbContext : ISqlSugarDbContext
connectionCreator.DataExecuted = DataExecuted;
connectionCreator.OnLogExecuting = OnLogExecuting;
connectionCreator.OnLogExecuted = OnLogExecuted;
SqlSugarClient = new SqlSugarClient(connectionCreator.Build());
var connStr = GetCurrentConnectionString();
SqlSugarClient = new SqlSugarClient(connectionCreator.Build(action: opt =>
{
opt.ConnectionString = connStr;
}));
connectionCreator.SetDbAop(SqlSugarClient);
}
/// <summary>
/// db切换多库支持
/// </summary>
/// <returns></returns>
protected virtual string GetCurrentConnectionString()
{
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
var connectionString = connectionStringResolver.ResolveAsync().Result;
//没有检测到使用多租户功能,默认使用默认库即可
if (string.IsNullOrWhiteSpace(connectionString))
{
Volo.Abp.Check.NotNull(Options.Url, "租户默认库Default未找到");
connectionString = Options.Url;
}
//如果当前租户是主库,单独使用主要库
if (CurrentTenant.Name == DbConnOptions.MasterTenantName)
{
var conStrOrNull = Options.GetMasterSaasMultiTenancy();
Volo.Abp.Check.NotNull(conStrOrNull, "租户主库Master未找到");
connectionString = conStrOrNull.Url;
}
return connectionString!;
}
/// <summary>
/// 上下文对象扩展
/// </summary>
@ -69,7 +101,7 @@ public class SqlSugarDbContext : ISqlSugarDbContext
if (IsMultiTenantFilterEnabled)
{
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == GuidGenerator.Create());
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == CurrentTenant.Id);
}
// 自定义其它Filter
@ -200,6 +232,11 @@ public class SqlSugarDbContext : ISqlSugarDbContext
protected virtual void OnLogExecuted(string sql, SugarParameter[] pars)
{
if (Options.EnabledSqlLog)
{
var sqllog = $"=========NPin-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog);
}
}
/// <summary>

@ -14,7 +14,7 @@ public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextPr
{
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
private ILogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>> Logger { get; set; }
private IServiceProvider ServiceProvider { get; set; }
public IServiceProvider ServiceProvider { get; set; }
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
protected readonly IUnitOfWorkManager UnitOfWorkManager;
@ -50,7 +50,10 @@ public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextPr
if (unitOfWork == null || !unitOfWork.Options.IsTransactional)
{
// set if is null
ContextInstance.Current ??= (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
if (ContextInstance.Current is null)
{
ContextInstance.Current = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
}
var dbContext = (TDbContext)ContextInstance.Current;
// 提高体验取消uow的强制性
@ -62,9 +65,11 @@ public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextPr
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
if (databaseApi == null)
{
databaseApi =
new SqlSugarDatabaseApi(CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
.Result);
// db根据连接字符串来创建
databaseApi = new SqlSugarDatabaseApi(
CreateDbContextAsync(unitOfWork, connectionStringName, connectionString).Result
);
// 创建的db加入到当前工作单元中
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
}
@ -126,7 +131,7 @@ public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextPr
);
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
// await dbContext.SqlSugarClient.Ado.BeginTranAsync();
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
return dbContext;
}

@ -1,4 +1,5 @@
using NPin.Framework.AuditLogging.Domain.Entities;
using Microsoft.Extensions.Options;
using NPin.Framework.AuditLogging.Domain.Entities;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
@ -17,12 +18,12 @@ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter,
public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator,
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer,
AbpExceptionHandlingOptions exceptionHandlingOptions)
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
{
GuidGenerator = guidGenerator;
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
JsonSerializer = jsonSerializer;
ExceptionHandlingOptions = exceptionHandlingOptions;
ExceptionHandlingOptions = exceptionHandlingOptions.Value;
}
public virtual Task<AuditLogAggregateRoot> ConvertAsync(AuditLogInfo auditLogInfo)

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using NPin.Framework.AuditLogging.Domain.Repositories;
@ -17,12 +18,12 @@ public class AuditingStore : IAuditingStore, ITransientDependency
protected IAuditLogInfoToAuditLogConverter Converter { get; }
public AuditingStore(ILogger<AuditingStore> logger, IAuditLogRepository auditLogRepository,
IUnitOfWorkManager unitOfWorkManager, AbpAuditingOptions options, IAuditLogInfoToAuditLogConverter converter)
IUnitOfWorkManager unitOfWorkManager, IOptions<AbpAuditingOptions> options, IAuditLogInfoToAuditLogConverter converter)
{
Logger = logger;
AuditLogRepository = auditLogRepository;
UnitOfWorkManager = unitOfWorkManager;
Options = options;
Options = options.Value;
Converter = converter;
}

@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities;
[DisableAuditing]
[SugarTable("NPinAuditLogAction", "审计日志操作表")]
[SugarTable("SysAuditLogAction", "审计日志操作表")]
[SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(TenantId)}_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ServiceName),
OrderByType.Asc, nameof(MethodName), OrderByType.Asc, nameof(ExecutionTime), OrderByType.Asc)]

@ -8,7 +8,7 @@ using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities;
[DisableAuditing]
[SugarTable("NPinAuditLog", "审计日志")]
[SugarTable("SysAuditLog", "审计日志")]
[SugarIndex($"index_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ExecutionTime),
OrderByType.Asc)]
[SugarIndex($"index_{nameof(ExecutionTime)}_{nameof(UserId)}", nameof(TenantId), OrderByType.Asc, nameof(UserId),

@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities;
[SugarTable("NPinEntityChange")]
[SugarTable("SysEntityChange")]
[SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(TenantId)}_{nameof(EntityId)}", nameof(TenantId), OrderByType.Asc,
nameof(EntityTypeFullName), OrderByType.Asc, nameof(EntityId), OrderByType.Asc)]

@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities;
[SugarTable("NPinEntityPropertyChange")]
[SugarTable("SysEntityPropertyChange")]
[SugarIndex($"index_{nameof(EntityChangeId)}", nameof(EntityChangeId), OrderByType.Asc)]
public class EntityPropertyChangeEntity : Entity<Guid>, IMultiTenant
{

@ -1,38 +1,40 @@
using JetBrains.Annotations;
using SqlSugar;
using Volo.Abp.Domain.Entities;
using Check = Volo.Abp.Check;
namespace NPin.Framework.SettingManagement.Domain.Entities;
[SugarTable("SysSetting", "系统配置表")]
public class SettingEntity : Entity<Guid>, IAggregateRoot<Guid>
{
[NotNull]
public virtual string Name { get; protected set; }
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[NotNull]
public virtual string Value { get; internal set; }
[SugarColumn(ColumnDescription = "配置名称")]
public string Name { get; protected set; }
[CanBeNull]
public virtual string ProviderName { get; protected set; }
[SugarColumn(ColumnDescription = "配置值", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string Value { get; internal set; }
[CanBeNull]
public virtual string ProviderKey { get; protected set; }
[SugarColumn(ColumnDescription = "配置提供者")]
public string? ProviderName { get; protected set; }
[SugarColumn(ColumnDescription = "配置提供者Key")]
public string? ProviderKey { get; protected set; }
public SettingEntity()
{
}
public SettingEntity(
Guid id,
[NotNull] string name,
[NotNull] string value,
[CanBeNull] string providerName = null,
[CanBeNull] string providerKey = null)
string name,
string value,
string? providerName = null,
string? providerKey = null)
{
Check.NotNull(name, nameof(name));
Check.NotNull(value, nameof(value));
Id = id;
Name = name;
Value = value;
ProviderName = providerName;
@ -41,6 +43,7 @@ public class SettingEntity: Entity<Guid>, IAggregateRoot<Guid>
public override string ToString()
{
return $"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}";
return
$"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}";
}
}

@ -11,4 +11,8 @@
<PackageReference Include="Volo.Abp.SettingManagement.Domain.Shared" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
</ItemGroup>
</Project>

@ -10,6 +10,8 @@ namespace NPin.Framework.SettingManagement.Domain;
public class SettingManager : ISettingManager, ISingletonDependency
{
private readonly Lazy<List<ISettingManagementProvider>> _lazyProviders;
protected readonly IServiceProvider ServiceProvider;
protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingEncryptionService SettingEncryptionService { get; }
protected List<ISettingManagementProvider> Providers => _lazyProviders.Value;
@ -21,18 +23,21 @@ public class SettingManager : ISettingManager, ISingletonDependency
ISettingEncryptionService settingEncryptionService,
IOptions<SettingManagementOptions> options)
{
ServiceProvider = serviceProvider;
SettingDefinitionManager = settingDefinitionManager;
SettingEncryptionService = settingEncryptionService;
Options = options.Value;
// TODO use IServiceScopeFactory and create a scope ?
_lazyProviders = new Lazy<List<ISettingManagementProvider>>(
() => Options
.Providers
.Select(c => serviceProvider.GetRequiredService(c) as ISettingManagementProvider)
.ToList(),
true
);
_lazyProviders = new Lazy<List<ISettingManagementProvider>>(CreateSettingManagementProviders, true);
}
protected virtual List<ISettingManagementProvider> CreateSettingManagementProviders()
{
using var scope = ServiceProvider.CreateScope();
return Options.Providers
.Select(p => (scope.ServiceProvider.GetRequiredService(p) as ISettingManagementProvider)!)
.ToList();
}
public virtual Task<string?> GetOrNullAsync(string name, string providerName, string? providerKey,

@ -13,16 +13,13 @@ public class SettingManagementStore : ISettingManagementStore, ITransientDepende
protected IDistributedCache<SettingCacheItem> Cache { get; }
protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingRepository SettingRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public SettingManagementStore(IDistributedCache<SettingCacheItem> cache,
ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository,
IGuidGenerator guidGenerator)
ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository)
{
Cache = cache;
SettingDefinitionManager = settingDefinitionManager;
SettingRepository = settingRepository;
GuidGenerator = guidGenerator;
}
[UnitOfWork]
@ -65,7 +62,7 @@ public class SettingManagementStore : ISettingManagementStore, ITransientDepende
var setting = await SettingRepository.FindAsync(name, providerName, providerKey);
if (setting == null)
{
setting = new SettingEntity(GuidGenerator.Create(), name, value, providerName, providerKey);
setting = new SettingEntity(name, value, providerName, providerKey);
await SettingRepository.InsertAsync(setting);
}
else

@ -29,7 +29,17 @@ public class TenantService : NPinCrudAppService<TenantAggregateRoot, TenantGetOu
}
/// <summary>
/// 多查
/// 租户单查
/// </summary>
/// <param name="id">唯一ID</param>
/// <returns></returns>
public override Task<TenantGetOutputDto> GetAsync(Guid id)
{
return base.GetAsync(id);
}
/// <summary>
/// 租户多查
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
@ -87,7 +97,6 @@ public class TenantService : NPinCrudAppService<TenantAggregateRoot, TenantGetOu
return await base.UpdateAsync(id, input);
}
// 只是为了可以在swagger上展示?
/// <summary>
/// 租户删除
/// </summary>

@ -9,7 +9,7 @@ using Check = Volo.Abp.Check;
namespace NPin.Framework.TenantManagement.Domain;
[SugarTable("NPinTenant")]
[SugarTable("SysTenant", "租户表")]
[MasterTenant]
public class TenantAggregateRoot : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
{

@ -5,9 +5,14 @@ public class ConfigConst
/// <summary>
/// 系统配置前缀
/// </summary>
public const string SysConfigPrefix = "Sys";
public const string SysConfigPrefix = "sys";
public const string AliyunConfigKey = "Aliyun";
public const string TencentConfigKey = "Tencent";
public const string SmsConfigKey = "Sms";
/// <summary>
/// 短信配置相关
/// </summary>
public const string SmsConfigKey = "sms";
public const string SmsProvidersKey = $"{SysConfigPrefix}.{SmsConfigKey}.providers";
public const string SmsTemplatesKey = $"{SysConfigPrefix}.{SmsConfigKey}.templates";
public const string SmsSettingsKey = $"{SysConfigPrefix}.{SmsConfigKey}.settings";
public const string SmsConfigModelKey = $"{SysConfigPrefix}.{SmsConfigKey}.config";
}

@ -5,7 +5,7 @@ namespace NPin.Framework.Upms.Domain.Shared.Enums;
/// <summary>
/// 短信提供商枚举
/// </summary>
public enum SmsProviderEnum
public enum SmsProviderTypeEnum
{
Aliyun,
Tencent

@ -1,24 +0,0 @@
namespace NPin.Framework.Upms.Domain.Shared.Model;
public class AliyunConfigModel
{
/// <summary>
/// 访问密钥Key
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 默认 区域ID
/// </summary>
public string RegionId { get; set; }
/// <summary>
/// 默认 短信访问 端点
/// </summary>
public string SmsEndpoint { get; set; } = "dysmsapi.aliyuncs.com";
}

@ -1,4 +1,5 @@
using NPin.Framework.Upms.Domain.Shared.Enums;
using Newtonsoft.Json;
using NPin.Framework.Upms.Domain.Shared.Enums;
namespace NPin.Framework.Upms.Domain.Shared.Model;
@ -10,22 +11,64 @@ public class SmsConfigModel
public bool Enabled { get; set; } = false;
/// <summary>
/// 设定集
/// 提供商列表
/// </summary>
public Dictionary<SmsTypeEnum, SmsSettings> Settings { get; set; }
[JsonIgnore]
public List<SmsProvider> Providers { get; set; } = [];
/// <summary>
/// 短信模板列表
/// </summary>
[JsonIgnore]
public List<SmsTemplate> Templates { get; set; } = [];
/// <summary>
/// 系统短信设定集
/// 类型:设定
/// </summary>
[JsonIgnore]
public Dictionary<SmsTypeEnum, SmsSettings> Settings { get; set; } = new();
public SmsProvider GetProvider(SmsSettings settings)
{
return Providers.First(it => it.Id == settings.ProviderId);
}
public class SmsSettings
public SmsTemplate GetTemplate(SmsSettings settings)
{
return Templates.First(it => it.Id == settings.TemplateId);
}
public SmsSettings? GetSetting(SmsTypeEnum typeEnum)
{
return Settings.GetValueOrDefault(typeEnum, null);
}
}
/// <summary>
/// 是否启用
/// 短信提供商配置
/// </summary>
public bool Enabled { get; set; } = false;
public class SmsProvider
{
/// <summary>
/// ID
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 服务提供商
/// </summary>
public SmsProviderEnum Provider { get; set; }
public SmsProviderTypeEnum ProviderType { get; set; }
/// <summary>
/// 访问密钥Key
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 区域
@ -37,6 +80,19 @@ public class SmsSettings
/// </summary>
public string Endpoint { get; set; }
/// <summary>
/// 短信SdkAppId
/// </summary>
public string SmsSdkAppId { get; set; }
}
public class SmsTemplate
{
/// <summary>
/// ID
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 短信签名名称
/// </summary>
@ -46,6 +102,24 @@ public class SmsSettings
/// 短信模板Code
/// </summary>
public string TemplateCode { get; set; }
}
public class SmsSettings
{
/// <summary>
/// 短信类型
/// </summary>
public SmsTypeEnum SmsType { get; set; }
/// <summary>
/// 提供商ID
/// </summary>
public Guid ProviderId { get; set; }
/// <summary>
/// 模板ID
/// </summary>
public Guid TemplateId { get; set; }
/// <summary>
/// 过期时间,单位:秒

@ -1,31 +0,0 @@
using Newtonsoft.Json;
namespace NPin.Framework.Upms.Domain.Shared.Model;
public class TencentConfigModel
{
/// <summary>
/// 访问密钥Key
/// </summary>
public string SecretId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string SecretKey { get; set; }
/// <summary>
/// 默认区域
/// </summary>
public string Region { get; set; }
/// <summary>
/// 默认短信访问 端点
/// </summary>
public string SmsEndpoint { get; set; } = "sms.tencentcloudapi.com";
/// <summary>
/// 短信SdkAppId
/// </summary>
public string SmsSdkAppId { get; set; }
}

@ -5,7 +5,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Authorization;
[SugarTable("Social", "第三方授权表")]
[SugarTable("SysSocial", "第三方授权表")]
public class SocialAggregateRoot: AggregateRoot<Guid>, ISoftDelete, IHasCreationTime
{
[SugarColumn(IsPrimaryKey = true)]

@ -5,7 +5,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("announcement", "系统公告表")]
[SugarTable("SysAnnouncement", "系统公告表")]
public class AnnouncementEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }

@ -6,7 +6,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Config", "系统配置表")]
[SugarTable("SysConfig", "系统配置表")]
[SugarIndex($"index_{nameof(Key)}", nameof(Key), OrderByType.Asc, true)]
public class ConfigEntity : Entity<Guid>, IEnabled, IOrderNum, ISoftDelete, IAuditedObject
{

@ -5,7 +5,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("File", "文件信息表")]
[SugarTable("SysFile", "文件信息表")]
public class FileAggregateRoot : AggregateRoot<Guid>, IAuditedObject
{
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]

@ -10,7 +10,8 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("LoginLog", "登录日志表")]
[SugarTable("SysLoginLog", "登录日志表")]
[SugarIndex($"index_{nameof(LoginUser)}", nameof(LoginUser), OrderByType.Asc)]
public class LoginLogEntity : Entity<Guid>, ICreationAuditedObject
{
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
@ -28,10 +29,10 @@ public class LoginLogEntity : Entity<Guid>, ICreationAuditedObject
public string? LoginLocation { get; set; }
[SugarColumn(ColumnDescription = "Ipv4")]
public string? LoginIPv4 { get; set; }
public string? LoginIpv4 { get; set; }
[SugarColumn(ColumnDescription = "Ipv6")]
public string? LoginIPv6 { get; set; }
public string? LoginIpv6 { get; set; }
[SugarColumn(ColumnDescription = "浏览器")]
public string? Browser { get; set; }
@ -71,8 +72,8 @@ public class LoginLogEntity : Entity<Guid>, ICreationAuditedObject
{
Browser = clientInfo.Device.Family,
Os = clientInfo.OS.ToString(),
LoginIPv4 = ipv4AddrStr,
LoginIPv6 = ipv6AddrStr,
LoginIpv4 = ipv4AddrStr,
LoginIpv6 = ipv6AddrStr,
LoginLocation = $"{location.Country}-{location.Province}-{location.City}"
};

@ -5,7 +5,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Organization", "组织机构表")]
[SugarTable("SysOrganization", "组织机构表")]
public class OrganizationEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]

@ -5,7 +5,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Post", "岗位表")]
[SugarTable("SysPost", "岗位表")]
public class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]

@ -6,7 +6,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Role", "角色表")]
[SugarTable("SysRole", "角色表")]
public class RoleEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]

@ -3,7 +3,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelRoleOrganization", "角色-机构 关系表")]
[SugarTable("SysRelRoleOrganization", "角色-机构 关系表")]
public class RoleOrganizationEntity : Entity<Guid>
{
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }

@ -8,7 +8,8 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("User", "用户表")]
[SugarTable("SysUser", "用户表")]
[SugarIndex($"index_{nameof(Username)}", nameof(Username), OrderByType.Asc)]
public class UserEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IEnabled, IOrderNum
{
#region User

@ -4,7 +4,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("UserMetadata", "用户元数据表")]
[SugarTable("SysUserMetadata", "用户元数据表")]
public class UserMetaEntity : Entity<Guid>, IAuditedObject
{
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }

@ -3,7 +3,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserOrganization", "用户-组织机构 关系表")]
[SugarTable("SysRelUserOrganization", "用户-组织机构 关系表")]
public class UserOrganizationEntity : Entity<Guid>
{
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }

@ -3,7 +3,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserPost","用户-岗位 关系表")]
[SugarTable("SysRelUserPost","用户-岗位 关系表")]
public class UserPostEntity: Entity<Guid>
{
[SugarColumn(IsPrimaryKey = true)]

@ -3,7 +3,7 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserRole", "用户-角色 关系表")]
[SugarTable("SysRelUserRole", "用户-角色 关系表")]
public class UserRoleEntity: Entity<Guid>
{
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]

@ -1,129 +1,78 @@
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dysmsapi20170525;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPin.Framework.Upms.Domain.Repositories;
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.Upms.Domain.Settings;
using NPin.Framework.Upms.Domain.Shared.Consts;
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
using NPin.Framework.Upms.Domain.Shared.Options;
using TencentCloud.Common;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111;
using TencentCloud.Sms.V20210111.Models;
using Volo.Abp.Caching;
using NPin.Framework.Upms.Domain.Sms;
using Volo.Abp.Domain.Services;
namespace NPin.Framework.Upms.Domain.Managers;
public class SmsManager : DomainService, ISms
public class SmsManager : DomainService
{
private ILogger<SmsManager> _logger;
private IConfigRepository _configRepository;
private IDistributedCache<SmsConfigModel> _cache;
private readonly ILogger<SmsManager> _logger;
public SmsManager(ILogger<SmsManager> logger, IConfigRepository configRepository)
{
_logger = logger;
_configRepository = configRepository;
}
private readonly ISettingManager _settingManager;
public async Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam)
{
private readonly IEnumerable<ISms> _smsProviders;
try
{
var smsSettings = SmsOptions.Config[smsType];
if (!smsSettings.Enabled)
public SmsManager(ILogger<SmsManager> logger, ISettingManager settingManager, IEnumerable<ISms> smsProviders)
{
return;
_logger = logger;
_settingManager = settingManager;
_smsProviders = smsProviders;
}
switch (smsSettings.Provider)
public async Task<SmsConfigModel> GetSmsConfigModelAsync()
{
case SmsProviderEnum.Aliyun:
await SendAliyunSmsAsync(smsSettings, phoneNumbers, templateParam);
break;
case SmsProviderEnum.Tencent:
await SendTencentSmsAsync(smsSettings, phoneNumbers, templateParam);
break;
default:
throw new Exception("未实现该服务提供商");
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"短信发送失败: {ex.Message}");
throw new UserFriendlyException($"短信发送失败: {ex.Message}");
}
}
var configJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsConfigModelKey);
var settingsJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsSettingsKey);
var providersJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsProvidersKey);
var templateJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsTemplatesKey);
private async Task SendTencentSmsAsync(SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = SmsClientProvider.CreateClient(TencentOptions, settings);
var ret = JsonConvert.DeserializeObject<SmsConfigModel>(configJson ?? string.Empty) ?? new SmsConfigModel();
var sendSmsRequest = new SendSmsRequest
{
PhoneNumberSet = phoneNumbers.Split(','),
SignName = settings.SignName,
TemplateId = settings.TemplateCode,
TemplateParamSet = templateParam as string[]
};
ret.Settings =
JsonConvert.DeserializeObject<Dictionary<SmsTypeEnum, SmsSettings>>(settingsJson ?? string.Empty) ??
new Dictionary<SmsTypeEnum, SmsSettings>();
var response = await client.SendSms(sendSmsRequest);
}
ret.Providers = JsonConvert.DeserializeObject<List<SmsProvider>>(providersJson ?? string.Empty) ?? [];
ret.Templates = JsonConvert.DeserializeObject<List<SmsTemplate>>(templateJson ?? string.Empty) ?? [];
private async Task SendAliyunSmsAsync(SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = SmsClientProvider.CreateClient(AliyunOptions, settings);
var sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest
{
PhoneNumbers = phoneNumbers,
SignName = settings.SignName,
TemplateCode = settings.TemplateCode,
TemplateParam = JsonConvert.SerializeObject(templateParam)
};
var response = await client.SendSmsAsync(sendSmsRequest);
}
return ret;
}
public static class SmsClientProvider
public async Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam)
{
public static Client CreateClient(AliyunOptions options, SmsSettings settings)
try
{
var config = new Config()
var smsConfig = await GetSmsConfigModelAsync();
if (!smsConfig.Enabled)
{
AccessKeyId = options.AccessKeyId,
AccessKeySecret = options.AccessKeySecret,
Endpoint = settings.Endpoint,
RegionId = settings.RegionId,
};
return new Client(config);
throw new UserFriendlyException("短信服务未启用,无法发送短信。");
}
public static SmsClient CreateClient(TencentOptions options, SmsSettings settings)
{
var cred = new Credential
var settings = smsConfig.GetSetting(smsType);
if (settings is null)
{
SecretId = options.SecretId,
SecretKey = options.SecretKey,
};
throw new UserFriendlyException("未找到对应短信类型,无法发送短信。");
}
var httpProfile = new HttpProfile
var providerConfig = smsConfig.GetProvider(settings);
var provider = _smsProviders.FirstOrDefault(i => i.ProviderType == providerConfig.ProviderType);
if (provider is null)
{
Endpoint = settings.Endpoint,
};
throw new NotImplementedException("未实现该方式的短信控制器");
}
var clientProfile = new ClientProfile()
await provider.SendSmsAsync(smsConfig, settings, phoneNumbers, templateParam);
}
catch (Exception ex)
{
HttpProfile = httpProfile
};
return new SmsClient(cred, settings.RegionId, clientProfile);
_logger.LogError(ex, $"短信发送失败: {ex.Message}");
throw new UserFriendlyException($"短信发送失败: {ex.Message}");
}
}
}

@ -3,6 +3,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Caching.FreeRedis\NPin.Framework.Caching.FreeRedis.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
<ProjectReference Include="..\..\setting-management\NPin.Framework.SettingManagement.Domain\NPin.Framework.SettingManagement.Domain.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>

@ -1,7 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Caching.FreeRedis;
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.SettingManagement.Domain.Options;
using NPin.Framework.Upms.Domain.Authorization;
using NPin.Framework.Upms.Domain.OperLog;
using NPin.Framework.Upms.Domain.Settings;
using NPin.Framework.Upms.Domain.Shared;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.Caching;
@ -12,6 +15,8 @@ namespace NPin.Framework.Upms.Domain;
[DependsOn(
typeof(NPinFrameworkUpmsDomainSharedModule),
typeof(NPinFrameworkCachingFreeRedisModule),
// Settings
typeof(NPinFrameworkSettingManagementDomainModule),
// Abp
typeof(AbpAspNetCoreSignalRModule),
typeof(AbpDddDomainModule),
@ -28,5 +33,8 @@ public class NPinFrameworkUpmsDomainModule : AbpModule
opts.Filters.Add<PermissionGlobalAttribute>();
opts.Filters.Add<OperLogGlobalAttribute>();
});
// 添加Upms模块的设置提供者
Configure<SettingManagementOptions>(opt => { opt.Providers.Add<UpmsSettingManagementProvider>(); });
}
}

@ -3,20 +3,17 @@ using System.Net.Sockets;
using IPTools.Core;
using Microsoft.AspNetCore.Http;
using NPin.Framework.Core.Extensions;
using NPin.Framework.Upms.Domain.Entities;
using NPin.Framework.Upms.Domain.Shared.OperLog;
using SqlSugar;
using UAParser;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.OperLog;
[SugarTable("OperationLog", "操作日志记录表")]
[SugarTable("SysOperationLog", "操作日志记录表")]
public class OperationLogEntity : Entity<Guid>, ICreationAuditedObject
{
[SugarColumn(IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "日志标题")]
public string? Title { get; set; }
@ -76,6 +73,7 @@ public class OperationLogEntity: Entity<Guid>, ICreationAuditedObject
info = IpTool.Search(ipAddr.ToString());
}
}
return new OperationLogEntity
{
OperIPv4 = ipv4AddrStr,

@ -0,0 +1,17 @@
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.SettingManagement.Domain.Store;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Settings;
public class UpmsSettingManagementProvider: SettingManagementProvider, ITransientDependency
{
public const string ProviderName = "Upms";
public override string Name => ProviderName;
public UpmsSettingManagementProvider(ISettingManagementStore settingManagementStore) : base(settingManagementStore)
{
}
}

@ -0,0 +1,23 @@
using NPin.Framework.SettingManagement.Domain;
using Volo.Abp.Settings;
namespace NPin.Framework.Upms.Domain.Settings;
public static class UpmsSettingManagerExtensions
{
public static Task<string?> GetOrNullUpmsAsync(this ISettingManager settingManager, string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, UpmsSettingManagementProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllUpmsAsync(this ISettingManager settingManager, bool fallback = true)
{
return settingManager.GetAllAsync(UpmsSettingManagementProvider.ProviderName, null, fallback);
}
public static Task SetUpmsAsync(this ISettingManager settingManager, string name, string value)
{
return settingManager.SetAsync(name, value, UpmsSettingManagementProvider.ProviderName, null);
}
}

@ -0,0 +1,20 @@
using NPin.Framework.Upms.Domain.Shared.Consts;
using Volo.Abp.Settings;
namespace NPin.Framework.Upms.Domain.Settings;
public class UpmsStaticSettingProvider: SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
DefineSmsSettingDefinitions(context);
}
private void DefineSmsSettingDefinitions(ISettingDefinitionContext context)
{
context.Add(new SettingDefinition(ConfigConst.SmsConfigModelKey));
context.Add(new SettingDefinition(ConfigConst.SmsProvidersKey));
context.Add(new SettingDefinition(ConfigConst.SmsSettingsKey));
context.Add(new SettingDefinition(ConfigConst.SmsTemplatesKey));
}
}

@ -0,0 +1,54 @@
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dysmsapi20170525;
using AlibabaCloud.SDK.Dysmsapi20170525.Models;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Sms.Handler;
public class AliyunSmsHandler : ISms, ISingletonDependency
{
private readonly ILogger<AliyunSmsHandler> _logger;
public AliyunSmsHandler(ILogger<AliyunSmsHandler> logger)
{
_logger = logger;
}
public SmsProviderTypeEnum ProviderType => SmsProviderTypeEnum.Aliyun;
public async Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = CreateClient(config.GetProvider(settings));
var template = config.GetTemplate(settings);
var sendSmsRequest = new SendSmsRequest
{
PhoneNumbers = phoneNumbers,
SignName = template.SignName,
TemplateCode = template.TemplateCode,
TemplateParam = JsonConvert.SerializeObject(templateParam)
};
var response = await client.SendSmsAsync(sendSmsRequest);
// TODO 判断结果
_logger.LogDebug(response.ToString());
}
private Client CreateClient(SmsProvider provider)
{
var config = new Config()
{
AccessKeyId = provider.AccessKeyId,
AccessKeySecret = provider.AccessKeySecret,
Endpoint = provider.Endpoint,
RegionId = provider.Region,
};
return new Client(config);
}
}

@ -0,0 +1,64 @@
using Microsoft.Extensions.Logging;
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
using TencentCloud.Common;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111;
using TencentCloud.Sms.V20210111.Models;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Sms.Handler;
public class TencentSmsHandler : ISms, ISingletonDependency
{
private readonly ILogger<AliyunSmsHandler> _logger;
public TencentSmsHandler(ILogger<AliyunSmsHandler> logger)
{
_logger = logger;
}
public SmsProviderTypeEnum ProviderType => SmsProviderTypeEnum.Tencent;
public async Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = CreateClient(config.GetProvider(settings));
var template = config.GetTemplate(settings);
var sendSmsRequest = new SendSmsRequest
{
PhoneNumberSet = phoneNumbers.Split(','),
SignName = template.SignName,
TemplateId = template.TemplateCode,
TemplateParamSet = templateParam as string[]
};
var response = await client.SendSms(sendSmsRequest);
// TODO 判断结果
_logger.LogDebug(response.ToString());
}
private SmsClient CreateClient(SmsProvider provider)
{
var cred = new Credential
{
SecretId = provider.AccessKeyId,
SecretKey = provider.AccessKeySecret,
};
var httpProfile = new HttpProfile
{
Endpoint = provider.Endpoint,
};
var clientProfile = new ClientProfile()
{
HttpProfile = httpProfile
};
return new SmsClient(cred, provider.Region, clientProfile);
}
}

@ -1,11 +1,17 @@
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
namespace NPin.Framework.Upms.Domain.Managers;
namespace NPin.Framework.Upms.Domain.Sms;
/// <summary>
/// 短信接口
/// 统一短信接口
/// </summary>
public interface ISms
{
Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam);
/// <summary>
/// 短信提供商类型
/// </summary>
SmsProviderTypeEnum ProviderType { get; }
Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers, object templateParam);
}

@ -0,0 +1,46 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.Upms.Domain.Managers;
using NPin.Framework.Upms.Domain.Settings;
using NPin.Framework.Upms.Domain.Shared.Consts;
using NPin.Framework.Upms.Domain.Shared.Model;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore.DataSeeds;
public class SmsConfigDataSeed : IDataSeedContributor, ITransientDependency
{
private readonly ILogger<SmsManager> _logger;
private readonly ISettingManager _settingManager;
public SmsConfigDataSeed(ILogger<SmsManager> logger, ISettingManager settingManager)
{
_logger = logger;
_settingManager = settingManager;
}
public async Task SeedAsync(DataSeedContext context)
{
var configJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsConfigModelKey);
if (!string.IsNullOrEmpty(configJson))
{
return;
}
var configModel = new SmsConfigModel
{
Enabled = false,
Providers = [],
Settings = [],
Templates = []
};
await _settingManager.SetUpmsAsync(ConfigConst.SmsConfigModelKey, JsonConvert.SerializeObject(configModel));
await _settingManager.SetUpmsAsync(ConfigConst.SmsSettingsKey, JsonConvert.SerializeObject(configModel.Settings));
await _settingManager.SetUpmsAsync(ConfigConst.SmsProvidersKey, JsonConvert.SerializeObject(configModel.Providers));
await _settingManager.SetUpmsAsync(ConfigConst.SmsTemplatesKey, JsonConvert.SerializeObject(configModel.Templates));
}
}

@ -4,6 +4,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Mapster\NPin.Framework.Mapster.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore\NPin.Framework.SqlSugarCore.csproj" />
<ProjectReference Include="..\..\setting-management\NPin.Framework.SettingManagement.SqlSugarCore\NPin.Framework.SettingManagement.SqlSugarCore.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj" />
</ItemGroup>

@ -1,11 +1,14 @@
using NPin.Framework.Mapster;
using NPin.Framework.SettingManagement.SqlSugarCore;
using NPin.Framework.SqlSugarCore;
using NPin.Framework.Upms.Domain;
namespace NPin.Framework.Upms.SqlSugarCore;
namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
[DependsOn(
typeof(NPinFrameworkUpmsDomainModule),
// settings
typeof(NPinFrameworkSettingManagementSqlSugarCoreModule),
// framework
typeof(NPinFrameworkMapsterModule),
typeof(NPinFrameworkSqlSugarCoreModule)

@ -4,7 +4,7 @@ using NPin.Framework.Upms.Domain.Shared.Consts;
using SqlSugar;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore;
namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
public class NPinUpmsDbContext : SqlSugarDbContext
{

@ -5,7 +5,7 @@ using NPin.Framework.Upms.Domain.Entities;
using NPin.Framework.Upms.Domain.Repositories;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore;
namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
public class ConfigRepository : SqlSugarRepository<ConfigEntity, Guid>, IConfigRepository, ITransientDependency
{

@ -1,4 +1,4 @@
using NPin.Framework.Upms.SqlSugarCore;
using NPin.Framework.Upms.SqlSugarCore.Repositories;
using Volo.Abp.DependencyInjection;
namespace NPin.SqlSugarCore;

@ -3,7 +3,7 @@ using NPin.Framework.AuditLogging.SqlSugarCore;
using NPin.Framework.Mapster;
using NPin.Framework.SqlSugarCore;
using NPin.Framework.TenantManagement.SqlSugarCore;
using NPin.Framework.Upms.SqlSugarCore;
using NPin.Framework.Upms.SqlSugarCore.Repositories;
namespace NPin.SqlSugarCore;

@ -30,7 +30,7 @@ using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle;
namespace NPin;
namespace NPin.Web;
[DependsOn(
typeof(NPinSqlSugarCoreModule),

@ -1,5 +1,5 @@
using NPin;
using NPin.Web;
using Serilog;
using Serilog.Events;

@ -9,7 +9,16 @@
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:19001"
"applicationUrl": "http://localhost:19000"
},
"Docker": {
"commandName": "Docker",
"launchBrowser": false,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "19000"
},
"publishAllPorts": true
}
}
}

@ -8,8 +8,8 @@
},
//
"App": {
"SelfUrl": "http://*:19001",
"CorsOrigins": "http://localhost:19001;http://localhost:18000"
"SelfUrl": "http://*:19000",
"CorsOrigins": "http://localhost:19000;http://localhost:18000"
},
//
"DbList": [

Loading…
Cancel
Save