Merge branch 'Test.IRC' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.IRC

IRC_NewDev
he 2023-10-12 13:49:21 +08:00
commit 0fdf9a3419
83 changed files with 2211 additions and 1743 deletions

View File

@ -11,25 +11,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Application", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Domain.Share", "IRaCIS.Core.Domain.Share\IRaCIS.Core.Domain.Share.csproj", "{7CBC76F5-3817-46B7-8D9D-79253A89B578}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.JWT.RS256", "ZhiZhunAuthenticationCenter\IRaCIS.JWT.RS256.csproj", "{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Test", "IRaCIS.Core.Test\IRaCIS.Core.Test.csproj", "{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore", "IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj", "{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IRaCIS.AuthenticationCenter", "IRaCIS.AuthenticationCenter", "{481329D6-B8A0-491F-A398-1DF66A0FBB62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.IdentityServer4", "IRaCIS.Core.IdentityServer4\IRaCIS.Core.IdentityServer4.csproj", "{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.IdentityServer4.MVC", "IRaCIS.Core.IdentityServer4.MVC\IRaCIS.Core.IdentityServer4.MVC.csproj", "{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F852ABFB-88AC-48BE-B876-2228BE2373D6}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -52,10 +39,6 @@ Global
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.Build.0 = Release|Any CPU
{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Release|Any CPU.Build.0 = Release|Any CPU
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -68,23 +51,10 @@ Global
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.Build.0 = Release|Any CPU
{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Release|Any CPU.Build.0 = Release|Any CPU
{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39} = {481329D6-B8A0-491F-A398-1DF66A0FBB62}
{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674} = {481329D6-B8A0-491F-A398-1DF66A0FBB62}
{F621ADD6-94E8-4A4B-998E-25B8EF15D39C} = {481329D6-B8A0-491F-A398-1DF66A0FBB62}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BCC2EB19-3914-489B-B1D7-B7303E0218A3}
EndGlobalSection

View File

@ -1,106 +0,0 @@
{
"needAnonymizeTag": [
{ //PatientsName
"Group": "0010",
"Element": "0010",
"ReplaceValue": "",
"Enable": true
},
{ // PatientID
"Group": "0010",
"Element": "0020",
"ReplaceValue": "",
"Enable": true
},
{ // IssuerOfPatientID
"Group": "0010",
"Element": "0021",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsBirthDate
"Group": "0010",
"Element": "0030",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsBirthTime
"Group": "0010",
"Element": "0032",
"ReplaceValue": "",
"Enable": false
},
{ // PatientsSex
"Group": "0010",
"Element": "0040",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientIDs
"Group": "0010",
"Element": "1000",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientNames
"Group": "0010",
"Element": "1001",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientNames
"Group": "0010",
"Element": "1005",
"ReplaceValue": "",
"Enable": true
},
{ // PatientBirthName
"Group": "0010",
"Element": "1005",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsAge
"Group": "0010",
"Element": "1010",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsAddress
"Group": "0010",
"Element": "1040",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsMothersBirthName
"Group": "0010",
"Element": "1060",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2150",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2152",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2154",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0012",
"Element": "0040",
"ReplaceValue": "XXX",
"Enable": true
}
]
}

View File

@ -1,9 +1,6 @@
using System;
using System.Net.Http;
using EasyCaching.Core;
using gRPC.ZHiZHUN.AuthServer.protos;
using Grpc.Net.Client;
using Grpc.Net.Client.Configuration;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Auth;
@ -24,6 +21,13 @@ using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure;
using System.Linq;
using Microsoft.Extensions.Logging;
using MassTransit;
using Microsoft.AspNetCore.Hosting;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core.Auth.Sts;
using Aliyun.Acs.Core;
using IRaCIS.Core.Application.Helper;
using Microsoft.Extensions.Options;
namespace IRaCIS.Api.Controllers
{
@ -203,6 +207,44 @@ namespace IRaCIS.Api.Controllers
}
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS(IOptionsMonitor<AliyunOssOptions> options )
{
var ossOptions = options.CurrentValue;
IClientProfile profile = DefaultProfile.GetProfile(ossOptions.RegionId, ossOptions.AccessKeyId, ossOptions.AccessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
// 创建一个STS请求
AssumeRoleRequest request = new AssumeRoleRequest
{
RoleArn = ossOptions.RoleArn, // 角色ARN需要替换为你的角色ARN
RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
DurationSeconds = 900, // 令牌有效期单位这里设置为1小时
};
AssumeRoleResponse response = client.GetAcsResponse(request);
// 返回STS令牌信息给前端
var stsToken = new
{
AccessKeyId = response.Credentials.AccessKeyId,
AccessKeySecret = response.Credentials.AccessKeySecret,
SecurityToken = response.Credentials.SecurityToken,
Expiration = response.Credentials.Expiration,
Region = ossOptions.Region ,
BucketName = ossOptions.BucketName ,
ViewEndpoint = ossOptions.ViewEndpoint ,
};
return ResponseOutput.Ok(stsToken);
}

View File

@ -1222,6 +1222,59 @@ namespace IRaCIS.Core.API.Controllers
}
public enum UploadFileType
{
DataUpload = 1,
DataDownload = 2,
EmailAttachment = 3,
EmailBodyHtml = 4,
Other = 5
}
/// <summary>
/// 1数据上传 2导出、 3邮件附件 4邮件Html 通过 ----new
/// </summary>
/// <returns></returns>
[HttpPost("SystemFile/Upload")]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task<IResponseOutput> Upload(UploadFileType fileType)
{
IResponseOutput result = null;
switch (fileType)
{
case UploadFileType.DataUpload:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));
break;
case UploadFileType.DataDownload:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));
break;
case UploadFileType.EmailAttachment:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
break;
case UploadFileType.EmailBodyHtml:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
break;
default:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));
break;
}
return result;
}
}
#endregion

View File

@ -66,33 +66,27 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="4.0.2" />
<PackageReference Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageReference Include="EasyCaching.InMemory" Version="1.7.0" />
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.7.0" />
<PackageReference Include="EntityFrameworkCore.Triggered.Extensions" Version="3.2.1" />
<PackageReference Include="Google.Protobuf" Version="3.21.8" />
<PackageReference Include="Grpc.Net.Client" Version="2.49.0" />
<PackageReference Include="Grpc.Tools" Version="2.50.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hangfire.Tags.SqlServer" Version="1.8.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.9.1" />
<PackageReference Include="EasyCaching.Serialization.MessagePack" Version="1.9.1">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.5" />
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.5" />
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
<PackageReference Include="LogDashboard" Version="1.4.8" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.10" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.6.2" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.6.2" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="1.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.1" />
<PackageReference Include="Serilog.Sinks.Email" Version="2.4.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
@ -105,9 +99,6 @@
</ItemGroup>
<ItemGroup>
<Content Update="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\EmailTemplate\AdminAddUser_US.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@ -429,6 +429,12 @@
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.Upload(IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadFileType)">
<summary>
1数据上传 2导出、 3邮件附件 4邮件Html 通过 ----new
</summary>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
<summary>
IPLimit限流 启动服务
@ -484,113 +490,5 @@
<param name="withPrivate"></param>
<returns></returns>
</member>
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection">
<summary>Holder for reflection information generated from Protos/GrpcToken.proto</summary>
</member>
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection.Descriptor">
<summary>File descriptor for Protos/GrpcToken.proto</summary>
</member>
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest">
<summary>
新增用户时需要传递数据消息, 可理解为一个类
</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IdFieldNumber">
<summary>Field number for the "id" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserNameFieldNumber">
<summary>Field number for the "userName" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.RealNameFieldNumber">
<summary>Field number for the "realName" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.ReviewerCodeFieldNumber">
<summary>Field number for the "reviewerCode" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeEnumIntFieldNumber">
<summary>Field number for the "userTypeEnumInt" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeShortNameFieldNumber">
<summary>Field number for the "userTypeShortName" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IsAdminFieldNumber">
<summary>Field number for the "isAdmin" field.</summary>
</member>
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse">
<summary>
新增时返回的消息格式
</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.CodeFieldNumber">
<summary>Field number for the "code" field.</summary>
</member>
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.TokenFieldNumber">
<summary>Field number for the "token" field.</summary>
</member>
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService">
<summary>
service 用标识定义服务的,里面写对应的方法
</summary>
</member>
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.Descriptor">
<summary>Service descriptor</summary>
</member>
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient">
<summary>Client for TokenGrpcService</summary>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.ChannelBase)">
<summary>Creates a new client for TokenGrpcService</summary>
<param name="channel">The channel to use to make remote calls.</param>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.CallInvoker)">
<summary>Creates a new client for TokenGrpcService that uses a custom <c>CallInvoker</c>.</summary>
<param name="callInvoker">The callInvoker to use to make remote calls.</param>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor">
<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.ClientBase.ClientBaseConfiguration)">
<summary>Protected constructor to allow creation of configured clients.</summary>
<param name="configuration">The client configuration.</param>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserToken(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.Metadata,System.Nullable{System.DateTime},System.Threading.CancellationToken)">
<summary>
获取token
</summary>
<param name="request">The request to send to the server.</param>
<param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
<param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
<param name="cancellationToken">An optional token for canceling the call.</param>
<returns>The response received from the server.</returns>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserToken(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.CallOptions)">
<summary>
获取token
</summary>
<param name="request">The request to send to the server.</param>
<param name="options">The options for the call.</param>
<returns>The response received from the server.</returns>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserTokenAsync(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.Metadata,System.Nullable{System.DateTime},System.Threading.CancellationToken)">
<summary>
获取token
</summary>
<param name="request">The request to send to the server.</param>
<param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
<param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
<param name="cancellationToken">An optional token for canceling the call.</param>
<returns>The call object.</returns>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserTokenAsync(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.CallOptions)">
<summary>
获取token
</summary>
<param name="request">The request to send to the server.</param>
<param name="options">The options for the call.</param>
<returns>The call object.</returns>
</member>
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.NewInstance(Grpc.Core.ClientBase.ClientBaseConfiguration)">
<summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
</member>
</members>
</doc>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<variable name="myvar" value="myvalue"/>
<targets>
<target xsi:type="file" name="File" fileName="${basedir}/logs/${shortdate}/${level}.log"
layout="${longdate}||${level}||${logger}||${message}||${exception:format=ToString:innerFormat=ToString:maxInnerExceptionLevel=10:separator=\r\n}||end" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>

View File

@ -53,24 +53,12 @@ namespace IRaCIS.Core.API
})
.Build();
//// Serilog
SerilogExtension.AddSerilogSetup(enviromentName, host.Services);
Log.Logger.Warning($"µ±Ç°»·¾³£º{enviromentName}");
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
//缓存项目的状态 匿名化数据
await InitCache(host);
host.Run();
@ -100,28 +88,7 @@ namespace IRaCIS.Core.API
webBuilder.UseStartup<Startup>();
}).UseSerilog()
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
private static async Task InitCache(IHost host)
{
var _repository = host.Services.GetService(typeof(IRepository)) as IRepository;
//初始化 国际化数据,并且监测国际化文件变更
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_repository);
var _mediator = host.Services.GetService(typeof(IMediator)) as IMediator;
await _mediator.Send(new AnonymizeCacheRequest());
await _mediator.Send(new TrialStateCacheRequest());
}
}
}

View File

@ -45,22 +45,7 @@
"ASPNETCORE_ENVIRONMENT": "Production"
},
"applicationUrl": "http://localhost:6300"
},
"IRaCIS.CertificateApply": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "CertificateApply"
},
"applicationUrl": "http://localhost:6400"
},
"IRaCIS.CenterImageDev": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "CenterImageDev"
},
"applicationUrl": "http://localhost:6500"
}
}
}

View File

@ -24,6 +24,8 @@ using Invio.Extensions.Authentication.JwtBearer;
using Microsoft.AspNetCore.SignalR;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.StaticFiles;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Application.Services.BackGroundJob;
namespace IRaCIS.Core.API
{
@ -91,7 +93,7 @@ namespace IRaCIS.Core.API
services.AddOptions().Configure<SystemEmailSendConfig>( _configuration.GetSection("SystemEmailSendConfig"));
services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
services.AddOptions().Configure<AliyunOssOptions>(_configuration.GetSection("AliyunOSS"));
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
@ -106,17 +108,18 @@ namespace IRaCIS.Core.API
services.AddSwaggerSetup();
//JWT Token 验证
services.AddJWTAuthSetup(_configuration);
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
services.AddMediatR(typeof(ConsistencyVerificationHandler).Assembly);
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
// EasyCaching 缓存
services.AddEasyCachingSetup();
services.AddEasyCachingSetup(_configuration);
//services.AddDistributedMemoryCache();
// hangfire 定时任务框架 有界面,更友好~
//services.AddhangfireSetup(_configuration);
// QuartZ 定时任务框架 使用了hangfire 暂时不用,后续需要可以打开,已经配好
services.AddQuartZSetup(_configuration);
services.AddhangfireSetup(_configuration);
// 保护上传文件
//services.AddStaticFileAuthorizationSetup();
@ -161,7 +164,7 @@ namespace IRaCIS.Core.API
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//本地化
app.UseLocalization();
@ -181,7 +184,7 @@ namespace IRaCIS.Core.API
app.UseLogDashboard("/LogDashboard");
//hangfire
//app.UseHangfireConfig(env);
app.UseHangfireConfig(env);
////暂时废弃
//app.UseHttpReports();
@ -235,6 +238,10 @@ namespace IRaCIS.Core.API
endpoints.MapHub<UploadHub>("/UploadHub");
});
var hangfireJobService = app.ApplicationServices.GetRequiredService<IIRaCISHangfireJob>();
await hangfireJobService.InitHangfireJobTaskAsync();
}
}
}

View File

@ -1,40 +0,0 @@
using Hangfire;
using Hangfire.Dashboard;
using IRaCIS.Application.Services.BackGroundJob;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace IRaCIS.Core.API
{
public static class HangfireConfig
{
public static void UseHangfireConfig(this IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHangfireDashboard("/api/hangfire", new DashboardOptions()
{
//直接访问没有带token 获取不到用户身份信息,所以这种自定义授权暂时没法使用
//Authorization = new[] { new hangfireAuthorizationFilter() }
//本地请求 才能看
Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() }
});
#region hangfire
//// 延迟任务执行 1秒之后执行 有时启动没运行 换成添加到队列中
//BackgroundJob.Schedule<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus(), TimeSpan.FromSeconds(1));
////添加到后台任务队列,
//BackgroundJob.Enqueue<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus());
//周期性任务1天执行一次
RecurringJob.AddOrUpdate<IIRaCISCacheHangfireJob>(t => t.ProjectStartCache(), Cron.Daily);
#endregion
}
}
}

View File

@ -0,0 +1,66 @@
using Hangfire;
using Hangfire.Dashboard;
using Hangfire.Dashboard.BasicAuthorization;
using IRaCIS.Application.Services.BackGroundJob;
using IRaCIS.Core.API.Filter;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace IRaCIS.Core.API
{
public static class HangfireConfig
{
public static void UseHangfireConfig(this IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHangfireDashboard("/back/hangfire", new DashboardOptions()
{
Authorization = new IDashboardAuthorizationFilter[] { /*new hangfireAuthorizationFilter(),*/
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
SslRedirect=false,
RequireSsl=false,
Users=new BasicAuthAuthorizationUser[]{
new BasicAuthAuthorizationUser(){
Login="admin",
PasswordClear="admin",
}
}
})
},
DashboardTitle ="后台任务管理",
//Authorization = new BasicAuthAuthorizationFilter[] {
// new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
// SslRedirect=false,
// RequireSsl=false,
// Users=new BasicAuthAuthorizationUser[]{
// new BasicAuthAuthorizationUser(){
// Login="admin",
// PasswordClear="test",
// }
// }
// })
//}
});
}
}
}

View File

@ -31,10 +31,6 @@ namespace IRaCIS.Core.API
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
//containerBuilder.RegisterType<Mapper>().As<IMapper>().InstancePerLifetimeScope();
//containerBuilder.RegisterGeneric(typeof(EFUnitOfWork<>))
// .As(typeof(IEFUnitOfWork<>)).InstancePerLifetimeScope();//注册仓储
#endregion
@ -50,8 +46,7 @@ namespace IRaCIS.Core.API
#endregion
//containerBuilder.RegisterType<BaseService>().As<IBaseService>().PropertiesAutowired().InstancePerLifetimeScope();
//containerBuilder.RegisterType<DictionaryService>().As<IDictionaryService>().InstancePerLifetimeScope();
@ -59,22 +54,13 @@ namespace IRaCIS.Core.API
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
.PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors();
//Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore");
//containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces();
containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
//containerBuilder.RegisterType<Dictionary>().InstancePerLifetimeScope();
//Autofac 注册拦截器 需要注意的是生成api上服务上的动态代理AOP失效 间接掉用不影响
//containerBuilder.RegisterType<TrialStatusAutofacAOP>();
//containerBuilder.RegisterType<UserAddAOP>();
//containerBuilder.RegisterType<QANoticeAOP>();
//containerBuilder.RegisterType<LogService>().As<ILogService>().SingleInstance();
//注册hangfire任务 依赖注入
//注册hangfire任务 依赖注入
containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();

View File

@ -1,8 +1,12 @@
using IRaCIS.Core.Application.Triggers;
using Hangfire.SqlServer;
using IRaCIS.Core.Application.Triggers;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using Medallion.Threading.SqlServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
namespace IRaCIS.Core.API
{
@ -55,6 +59,13 @@ namespace IRaCIS.Core.API
});
//注意区分 easy caching 也有 IDistributedLockProvider
services.AddSingleton<IDistributedLockProvider>(sp =>
{
//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
});
//services.AddAssemblyTriggers(typeof(SubjectVisitImageDateTrigger).Assembly);
}

View File

@ -1,17 +1,26 @@
using EasyCaching.Core;
using EasyCaching.Core.Configurations;
using EasyCaching.Interceptor.Castle;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.API
{
public static class EasyCachingSetup
public static class EasyCachingSetup
{
public static void AddEasyCachingSetup(this IServiceCollection services)
public static void AddEasyCachingSetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddEasyCaching(options =>
{
options.UseInMemory();
//options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName);
});
//services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName);
services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
}
}

View File

@ -1,81 +0,0 @@
//using System;
//using Microsoft.Extensions.DependencyInjection;
//using StackExchange.Profiling.Storage;
//namespace IRaCIS.Core.API
//{
// public class MiniProfilerConfigure
// {
// public static void ConfigureMiniProfiler(IServiceCollection services)
// {
// services.AddMiniProfiler(options =>
// {
// // All of this is optional. You can simply call .AddMiniProfiler() for all defaults
// // (Optional) Path to use for profiler URLs, default is /mini-profiler-resources
// options.RouteBasePath = "/profiler";
// //// (Optional) Control storage
// //// (default is 30 minutes in MemoryCacheStorage)
// (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
// //// (Optional) Control which SQL formatter to use, InlineFormatter is the default
// //options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
// //// (Optional) To control authorization, you can use the Func<HttpRequest, bool> options:
// //// (default is everyone can access profilers)
// //options.ResultsAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
// //options.ResultsListAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
// //// Or, there are async versions available:
// //options.ResultsAuthorizeAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfiler;
// //options.ResultsAuthorizeListAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfilerLists;
// //// (Optional) To control which requests are profiled, use the Func<HttpRequest, bool> option:
// //// (default is everything should be profiled)
// //options.ShouldProfile = request => MyShouldThisBeProfiledFunction(request);
// //// (Optional) Profiles are stored under a user ID, function to get it:
// //// (default is null, since above methods don't use it by default)
// //options.UserIdProvider = request => MyGetUserIdFunction(request);
// //// (Optional) Swap out the entire profiler provider, if you want
// //// (default handles async and works fine for almost all applications)
// //options.ProfilerProvider = new MyProfilerProvider();
// //// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking.
// //// (defaults to true, and connection opening/closing is tracked)
// //options.TrackConnectionOpenClose = true;
// //// (Optional) Use something other than the "light" color scheme.
// //// (defaults to "light")
// //options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto;
// //// The below are newer options, available in .NET Core 3.0 and above:
// //// (Optional) You can disable MVC filter profiling
// //// (defaults to true, and filters are profiled)
// //options.EnableMvcFilterProfiling = true;
// //// ...or only save filters that take over a certain millisecond duration (including their children)
// //// (defaults to null, and all filters are profiled)
// //// options.MvcFilterMinimumSaveMs = 1.0m;
// //// (Optional) You can disable MVC view profiling
// //// (defaults to true, and views are profiled)
// //options.EnableMvcViewProfiling = true;
// //// ...or only save views that take over a certain millisecond duration (including their children)
// //// (defaults to null, and all views are profiled)
// //// options.MvcViewMinimumSaveMs = 1.0m;
// //// (Optional) listen to any errors that occur within MiniProfiler itself
// //// options.OnInternalError = e => MyExceptionLogger(e);
// //// (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage
// //// It has a lot of overhead vs. normal profiling and should only be used with that in mind
// //// (defaults to false, debug/heavy mode is off)
// ////options.EnableDebugMode = true;
// });
// //.AddEntityFramework();
// }
// }
//}

View File

@ -1,45 +0,0 @@

using IRaCIS.Application.Services.BackGroundJob;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Quartz;
namespace IRaCIS.Core.API
{
public static class QuartZSetup
{
public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<CacheTrialStatusQuartZJob>();
services.AddQuartz(q =>
{
// base quartz scheduler, job and trigger configuration
// as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
q.UseMicrosoftDependencyInjectionJobFactory();
// 基本Quartz调度器、作业和触发器配置
var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
.WithDescription("Trial regular work")
);
q.AddTrigger(t => t
.WithIdentity("TrialStatusTrigger")
.ForJob(jobKey)
.WithCronSchedule("0 0 * * * ?")
.WithDescription("My regular trial work trigger")
);
});
// ASP.NET Core hosting
services.AddQuartzHostedService(options =>
{
// when shutting down we want jobs to complete gracefully
options.WaitForJobsToComplete = true;
});
}
}
}

View File

@ -21,7 +21,7 @@ namespace IRaCIS.Core.API
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
.Enrich.WithClientIp()
.Enrich.WithClientAgent()
.Enrich.FromLogContext()
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型

View File

@ -1,55 +0,0 @@
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.API
{
public class JsonPatchDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
var schemas = swaggerDoc.Components.Schemas.ToList();
foreach (var item in schemas)
{
if (item.Key.StartsWith("Operation") || item.Key.StartsWith("JsonPatchDocument"))
swaggerDoc.Components.Schemas.Remove(item.Key);
}
swaggerDoc.Components.Schemas.Add("Operation", new OpenApiSchema
{
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
{
{ "op", new OpenApiSchema { Type = "string" } },
{"value", new OpenApiSchema{ Type = "object", Nullable = true } },
{ "path", new OpenApiSchema { Type = "string" } }
}
});
swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema
{
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Operation" }
},
Description = "Array of operations to perform"
});
foreach (var path in swaggerDoc.Paths.SelectMany(p => p.Value.Operations)
.Where(p => p.Key == Microsoft.OpenApi.Models.OperationType.Patch))
{
foreach (var item in path.Value.RequestBody.Content.Where(c => c.Key != "application/json-patch+json"))
path.Value.RequestBody.Content.Remove(item.Key);
var response = path.Value.RequestBody.Content.SingleOrDefault(c => c.Key == "application/json-patch+json");
response.Value.Schema = new OpenApiSchema
{
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" }
};
}
}
}
}

View File

@ -18,7 +18,6 @@ namespace IRaCIS.Core.API
{
public static void AddSwaggerSetup(this IServiceCollection services)
{
services.AddSwaggerExamplesFromAssemblyOf<JsonPatchUserRequestExample>();
services.AddSwaggerGen(options =>
{
@ -63,7 +62,6 @@ namespace IRaCIS.Core.API
// 在header中添加token传递到后台
options.OperationFilter<SecurityRequirementsOperationFilter>();
options.DocumentFilter<JsonPatchDocumentFilter>();
// 添加登录按钮
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()

View File

@ -1,13 +1,12 @@
using Hangfire;
using Hangfire.SqlServer;
using Hangfire.Tags.SqlServer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace IRaCIS.Core.API
{
public static class hangfireSetup
public static class hangfireSetup
{
public static void AddhangfireSetup(this IServiceCollection services, IConfiguration configuration)
{
@ -15,24 +14,29 @@ namespace IRaCIS.Core.API
services.AddHangfire(hangFireConfig =>
{
//hangFireConfig.UseInMemoryStorage();
//指定存储介质
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
{
SchemaName = "hangfire",
SchemaName = "dbo",
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
});
hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer
//hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer
//.UseHangfireHttpJob();
});
services.AddHangfireServer();
services.AddHangfireServer(option =>
{
option.Queues = new[] { "immediately_once", "default", "sys_init", "not_immediately_once" };
});
}
}

View File

@ -1,35 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=CenterImage_Test;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
"AuthorizationCode": "SHzyyl2021"
}
}

View File

@ -1,33 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=IRaCIS_Certificate;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true",
"Hangfire": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Hangfire_IRaCIS;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
"AuthorizationCode": "SHzyyl2021"
}
}

View File

@ -13,10 +13,14 @@
},
"AliyunOSS": {
"endpoint": "https://zyypacs-code.oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "mpXG7Nu6zTpsDrI1",
"accessKeySecret": "yNINcEb099SkNfF6vYKaoP8TZNI3xZ",
"bucketName": "zyypacs-code"
"RegionId": "cn-shanghai",
"Endpoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"AccessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"BucketName": "zy-sir-test-store",
"RoleArn": "acs:ram::1899121822495495:role/oss-upload",
"ViewEndpoint": "https://zy-sir-test-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai"
},
"BasicSystemConfig": {
@ -30,7 +34,7 @@
"LoginMaxFailCount": 5,
"LoginFailLockMinutes":1
"LoginFailLockMinutes": 1
},
"SystemEmailSendConfig": {
@ -38,7 +42,9 @@
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
"AuthorizationCode": "SHzyyl2021"
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://test.extimaging.com/login"
}
}

View File

@ -35,7 +35,8 @@
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "IRC@extimaging.com",
"FromName": "IRC",
"AuthorizationCode": "ExtImg@2022"
"AuthorizationCode": "ExtImg@2022",
"SiteUrl": "http://irc.extimaging.com/login"
}

View File

@ -27,7 +27,8 @@
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "uat@extimaging.com",
"FromName": "UAT_IRC",
"AuthorizationCode": "SHzyyl2021"
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://uat.extimaging.com/login"
}

View File

@ -55,6 +55,26 @@
"EnableReadDeepClone": true,
"EnableWriteDeepClone": false
}
},
"redis": {
"MaxRdSecond": 120,
"EnableLogging": false,
"LockMs": 5000,
"SleepMs": 300,
"dbconfig": {
"Password": "xc@123456",
"IsSsl": false,
"SslHost": null,
"ConnectionTimeout": 5000,
"AllowAdmin": true,
"Endpoints": [
{
"Host": "47.117.164.182",
"Port": 6379
}
],
"Database": 0
}
}
},
"IRaCISImageStore": {

View File

@ -1,72 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyCaching.Core;
using IRaCIS.Core.Domain;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using Microsoft.Extensions.Logging;
using Quartz;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Application.Services.BackGroundJob
{
public class CacheTrialStatusQuartZJob: IJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<CacheTrialStatusQuartZJob> _logger;
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
public CacheTrialStatusQuartZJob(IRepository<Trial> trialRepository, IEasyCachingProvider provider,ILogger<CacheTrialStatusQuartZJob> logger, IRepository<SystemAnonymization> systemAnonymizationRepository)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_systemAnonymizationRepository = systemAnonymizationRepository;
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogInformation($"开始执行QuartZ定时任务作业");
try
{
await MemoryCacheTrialStatus();
await MemoryCacheAnonymizeData();
}
catch (Exception e)
{
_logger.LogError($" 查询和缓存过程出现异常"+e.Message);
}
_logger.LogInformation("QuartZ定时任务作业结束");
}
public async Task MemoryCacheTrialStatus()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
public async Task MemoryCacheAnonymizeData()
{
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
}
}
}

View File

@ -0,0 +1,213 @@
using EasyCaching.Core;
using Hangfire;
using Hangfire.Storage;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace IRaCIS.Application.Services.BackGroundJob
{
public interface IIRaCISHangfireJob
{
Task MemoryCacheTrialStatusAsync();
Task InitHangfireJobTaskAsync();
}
public class IRaCISCHangfireJob : IIRaCISHangfireJob
{
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<IRaCISCHangfireJob> _logger;
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<Internationalization> _internationalizationRepository;
public IRaCISCHangfireJob(IRepository<Trial> trialRepository, ILogger<IRaCISCHangfireJob> logger, IEasyCachingProvider provider, IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<Internationalization> internationalizationRepository, IRepository<SystemAnonymization> systemAnonymizationRepository)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_internationalizationRepository = internationalizationRepository;
_systemAnonymizationRepository = systemAnonymizationRepository;
}
public async Task InitHangfireJobTaskAsync()
{
_logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~");
//项目状态 立即加载到缓存中
await MemoryCacheTrialStatusAsync();
await MemoryCacheAnonymizeData();
//创建项目缓存 定时任务
HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
//初始化
await InitInternationlizationDataAndWatchJsonFileAsync();
//创建邮件定时任务
await InitSysAndTrialCronJobAsync();
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
}
/// <summary>
/// 缓存项目状态
/// </summary>
/// <returns></returns>
public async Task MemoryCacheTrialStatusAsync()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
public async Task MemoryCacheAnonymizeData()
{
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
}
#region 国际化 初始化
public async Task InitInternationlizationDataAndWatchJsonFileAsync()
{
//查询数据库的数据
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new
{
t.Code,
t.Value,
t.ValueCN
}).ToListAsync();
//组织成json 文件
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
//本地静态文件国际化需要
foreach (var tojsonItem in toJsonList)
{
StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value;
StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN;
}
File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic));
File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic));
//监测Json文件变更 实时刷新数据
WatchJsonFile(usJsonPath);
WatchJsonFile(cnJsonPath);
}
public void WatchJsonFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new BusinessValidationFailedException(StaticData.International("IRaCISCHangfireJob_FileNotFound"));
}
FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath));
watcher.Changed += (sender, e) => LoadJsonFile(filePath);
watcher.EnableRaisingEvents = true;
}
private void LoadJsonFile(string filePath)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath);
IConfigurationRoot enConfiguration = builder.Build();
foreach (IConfigurationSection section in enConfiguration.GetChildren())
{
if (filePath.Contains(StaticData.En_US_Json))
{
StaticData.En_US_Dic[section.Key] = section.Value;
}
else
{
StaticData.Zh_CN_Dic[section.Key] = section.Value;
}
}
}
#endregion
public async Task InitSysAndTrialCronJobAsync()
{
//var deleteJobIdList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr != StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
// .Select(t => t.TrialId + "_" + t.Id)
// .ToListAsync();
//foreach (var jobId in deleteJobIdList)
//{
// HangfireJobHelper.RemoveCronJob(jobId);
//}
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
.ToListAsync();
foreach (var task in taskInfoList)
{
//利用主键作为任务Id
var jobId = $"{task.TrialId}_{task.Id}";
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, task.TrialId, task.BusinessScenarioEnum, task.EmailCron);
}
var addOrUpdateJobIdList = taskInfoList.Select(t => $"{t.TrialId}_{t.Id}").ToList();
var list = JobStorage.Current.GetConnection().GetRecurringJobs().ToList();
//项目定时任务都在default 队列
//var dbJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Where(t => t.Queue == "default").Select(t => t.Id).ToList();
//var deleteList= dbJobIdList.Except(addOrUpdateJobIdList).ToList();
// foreach (var jobId in deleteList)
// {
// HangfireJobHelper.RemoveCronJob(jobId);
// }
}
}
}

View File

@ -1,99 +0,0 @@
using EasyCaching.Core;
using IRaCIS.Core.Domain.Share;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Application.Services.BackGroundJob
{
public interface IIRaCISCacheHangfireJob
{
Task ProjectStartCache();
Task MemoryCacheTrialStatus();
Task MemoryCacheAnonymizeData();
Task CacheUserTypePermission(Guid? cacheUserTypeId);
}
public class IRaCISCacheHangfireJob: IIRaCISCacheHangfireJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<IRaCISCacheHangfireJob> _logger;
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
private readonly IRepository<UserTypeMenu> _userTypeMenuRepository;
public IRaCISCacheHangfireJob(IRepository<Trial> trialRepository,
IRepository<SystemAnonymization> systemAnonymizationRepository, IRepository<UserTypeMenu> userTypeMenuRepository,
IEasyCachingProvider provider,ILogger<IRaCISCacheHangfireJob> logger)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_systemAnonymizationRepository = systemAnonymizationRepository;
_userTypeMenuRepository = userTypeMenuRepository;
}
public async Task ProjectStartCache()
{
_logger.LogInformation("hangfire 定时缓存项目状态任务开始~");
try
{
await MemoryCacheTrialStatus();
await MemoryCacheAnonymizeData();
await CacheUserTypePermission();
}
catch (Exception e)
{
_logger.LogError("hangfire 定时任务执行失败" + e.Message);
}
_logger.LogInformation("hangfire 定时任务执行结束");
}
public async Task MemoryCacheTrialStatus()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
public async Task MemoryCacheAnonymizeData()
{
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
}
public async Task CacheUserTypePermission(Guid? cacheUserTypeId=null)
{
var permissionList = await _userTypeMenuRepository.Where(t => t.Menu.MenuType == "F")
.WhereIf(cacheUserTypeId != null, t => t.UserTypeId == cacheUserTypeId.Value).Select(t => new { t.UserTypeId, t.Menu.PermissionStr }).ToListAsync();
foreach (var userTypeGroup in permissionList.GroupBy(t => t.UserTypeId))
{
_provider.Set($"{StaticData.CacheKey.UserTypeId}_{userTypeGroup.Key}", userTypeGroup.Select(t => t.PermissionStr).ToList(), TimeSpan.FromDays(7));
}
}
}
}

View File

@ -116,6 +116,51 @@ public static class FileStoreHelper
return physicalFilePath;
}
#region 修改后留存
public static (string PhysicalPath, string RelativePath) GetSystemFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName)
{
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
//文件类型路径处理
var uploadFolderPath = Path.Combine(rootPath, StaticData.Folder.SystemDataFolder, templateFolderName);
if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
var (trustedFileNameForFileStorage, fileRealName) = FileStoreHelper.GetStoreFileName(fileName);
var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.SystemDataFolder}/{templateFolderName}/{trustedFileNameForFileStorage}";
var serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
return (serverFilePath, relativePath);
}
public static (string PhysicalPath, string RelativePath) GetOtherFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName)
{
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
//文件类型路径处理
var uploadFolderPath = Path.Combine(rootPath, StaticData.Folder.OtherDataFolder, templateFolderName);
if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
var (trustedFileNameForFileStorage, fileRealName) = FileStoreHelper.GetStoreFileName(fileName);
var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.OtherDataFolder}/{templateFolderName}/{trustedFileNameForFileStorage}";
var serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
return (serverFilePath, relativePath);
}
#endregion
/// <summary>
///
/// </summary>

View File

@ -0,0 +1,92 @@
using Hangfire;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class HangfireJobHelper
{
//public static void AddOrUpdateCronJob(string jobId, string queueName, Expression<Action> methodCall, string cron)
//{
// RecurringJob.AddOrUpdate(jobId, queueName, methodCall, cron);
//}
//添加 或者更新定时任务 Id 要唯一标识一个定义任务
public static void AddOrUpdateCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron, string queueName = "default")
{
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron);
}
public static void AddOrUpdateInitCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron)
{
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron);
}
public static void RemoveCronJob(string jobId)
{
RecurringJob.RemoveIfExists(jobId);
}
public static void ImmediatelyOnceOnlyJob(Expression<Action> methodCall)
{
BackgroundJob.Enqueue("immediately_once", methodCall);
}
public static void ImmediatelyOnceOnlyJob<T>(Expression<Action<T>> methodCall)
{
BackgroundJob.Enqueue<T>("immediately_once", methodCall);
}
public static void NotImmediatelyOnceOnlyJob(Expression<Action> methodCall, TimeSpan timeSpan)
{
BackgroundJob.Schedule("not_immediately_once", methodCall, timeSpan);
}
public static void NotImmediatelyOnceOnlyJob<T>(Expression<Action<T>> methodCall, TimeSpan timeSpan)
{
BackgroundJob.Schedule<T>("not_immediately_once", methodCall, timeSpan);
}
public static void AddOrUpdateTrialCronJob (string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron)
{
switch (businessScenario)
{
case EmailBusinessScenario.QCTask:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron);
break;
case EmailBusinessScenario.QCQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron);
break;
case EmailBusinessScenario.ImageQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron);
break;
default:
break;
}
}
}
}

View File

@ -0,0 +1,120 @@
using Aliyun.OSS;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NPOI.HPSF;
using SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public class AliyunOssOptions
{
public string RegionId { get; set; }
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string EndPoint { get; set; }
public string BucketName { get; set; }
public string RoleArn { get;set; }
public string Region { get; set; }
public string ViewEndpoint { get; set; }
}
public interface IOSSService
{
}
public class OSSService : IOSSService
{
public AliyunOssOptions _OSSConfig { get; set; }
public OssClient _ossClient { get; set; }
public OSSService(IOptionsMonitor<AliyunOssOptions> options)
{
var ossOptions = options.CurrentValue;
_OSSConfig = new AliyunOssOptions()
{
RegionId = ossOptions.RegionId,
AccessKeyId = ossOptions.AccessKeyId,
AccessKeySecret = ossOptions.AccessKeySecret,
EndPoint = ossOptions.EndPoint,
BucketName = ossOptions.BucketName,
RoleArn = ossOptions.RoleArn,
Region = ossOptions.Region,
ViewEndpoint = ossOptions.ViewEndpoint
};
_ossClient = new OssClient(_OSSConfig.EndPoint, _OSSConfig.AccessKeyId, _OSSConfig.AccessKeySecret);
}
public string UploadToOSS(string localFilePath, string oosFolderPath)
{
var localFileName = Path.GetFileName(localFilePath);
var ossRelativePath = oosFolderPath + "/" + localFileName;
try
{
// 上传文件
var result = _ossClient.PutObject(_OSSConfig.BucketName, ossRelativePath, localFilePath);
return ossRelativePath;
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss上传失败" + ex.Message);
}
}
public void DownLoadFromOSS(string ossRelativePath, string localFilePath)
{
try
{
var result = _ossClient.GetObject(_OSSConfig.BucketName, ossRelativePath);
// 将下载的文件流保存到本地文件
using (var fs = File.OpenWrite(localFilePath))
{
result.Content.CopyTo(fs);
fs.Close();
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
}
}
}
}

View File

@ -64,48 +64,44 @@
<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageReference Include="EntityFrameworkCore.Projectables" Version="3.0.4" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.2" />
<PackageReference Include="FreeSpire.Doc" Version="11.6.0" />
<PackageReference Include="Hangfire.Core" Version="1.8.5" />
<PackageReference Include="AutoMapper.Collection.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="BeetleX.BNR" Version="1.0.1" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
<PackageReference Include="EasyCaching.Interceptor.AspectCore" Version="1.7.0" />
<PackageReference Include="EasyCaching.Redis" Version="1.9.1" />
<PackageReference Include="EasyCaching.InMemory" Version="1.9.1" />
<PackageReference Include="ExcelDataReader" Version="3.6.0" />
<PackageReference Include="ExcelDataReader.DataSet" Version="3.6.0" />
<PackageReference Include="DistributedLock.Redis" Version="1.0.2" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.3" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.0" />
<PackageReference Include="fo-dicom.Codecs" Version="5.1.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Magicodes.IE.Core" Version="2.7.4.5" />
<PackageReference Include="Magicodes.IE.Csv" Version="2.7.4.5">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="fo-dicom.Drawing" Version="4.0.8" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.0.3" />
<PackageReference Include="FreeSpire.Doc" Version="10.8.0" />
<PackageReference Include="Hangfire" Version="1.7.31">
<PackageReference Include="Magicodes.IE.Excel" Version="2.7.4.5">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Magicodes.IE.Core" Version="2.7.4.2" />
<PackageReference Include="Magicodes.IE.Csv" Version="2.7.4.2">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Magicodes.IE.Excel" Version="2.7.4.2">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Magicodes.IE.Excel.AspNetCore" Version="2.7.4.2" />
<PackageReference Include="MailKit" Version="3.4.2" />
<PackageReference Include="MediatR" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="MimeKit" Version="3.4.2" />
<PackageReference Include="MiniExcel" Version="1.30.1" />
<PackageReference Include="MiniWord" Version="0.6.1" />
<PackageReference Include="Magicodes.IE.Excel.AspNetCore" Version="2.7.4.5" />
<PackageReference Include="MailKit" Version="4.2.0" />
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="MimeKit" Version="4.2.0" />
<PackageReference Include="MiniExcel" Version="1.31.2" />
<PackageReference Include="MiniWord" Version="0.7.0" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.0.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="NPOI" Version="2.6.0" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.0" />
<PackageReference Include="Quartz" Version="3.5.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.5" />
<PackageReference Include="WinSCP" Version="5.21.5" />
<PackageReference Include="NPOI" Version="2.6.2" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.11" />
<PackageReference Include="WinSCP" Version="6.1.2" />
</ItemGroup>
<ItemGroup>

View File

@ -685,6 +685,27 @@
PublishLogService
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialImageQCTaskEmailAsync(System.Guid)">
<summary>
影像质控
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialQCQuestionEmailAsync(System.Guid)">
<summary>
QC质疑
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialImageQuestionAsync(System.Guid)">
<summary>
影像质疑
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService">
<summary>
TrialEmailNoticeConfigService
@ -706,7 +727,7 @@
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.SyncSystemEmainCofigDocListAsync(System.Guid)">
<summary>
同步系统配置的文档到想项目中
同步系统配置的文档到想项目中 ---废弃
</summary>
<param name="trialId"></param>
<returns></returns>
@ -756,6 +777,27 @@
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.GetTrialUserIdSelectList(System.Guid)">
<summary>
黑名单用户Id 列表
</summary>
<param name="trialEmailNoticeConfigId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.GetSysEmailNoticeConfigList(IRaCIS.Core.Application.Contracts.EmailNoticeConfigQuery)">
<summary>
获取系统 邮件配置 勾选列表
</summary>
<param name="queryEmailNoticeConfig"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.BatchAddSysEmailConfig(System.Collections.Generic.List{IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig})">
<summary>
批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系
</summary>
<param name="batchAddList"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.Preview(System.Guid)">
<summary> 指定资源Id渲染Dicom检查的Jpeg预览图像 </summary>
<param name="studyId"> Dicom检查的Id </param>
@ -8929,6 +8971,27 @@
<member name="T:IRaCIS.Core.Application.ViewModel.TrialEmailNoticeConfigQuery">
<summary>TrialEmailNoticeConfigQuery 列表查询参数模型</summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.BusinessModuleEnum">
<summary> 业务模块 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.BusinessLevelEnum">
<summary> 业务层级 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailTypeEnum">
<summary> 邮件类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailUrgentEnum">
<summary> 邮件加急类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailCron">
<summary> 定时周期 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailTopic">
<summary> 邮件主题 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.AttachPath">
<summary> 附件 /// </summary>
</member>
<member name="T:IRaCIS.Core.Application.ViewModel.TrialEmailNoticeConfigAddOrEdit">
<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
</member>
@ -9823,6 +9886,24 @@
是否区分标准
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.BusinessModuleEnum">
<summary> 业务模块 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.BusinessLevelEnum">
<summary> 业务层级 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailTypeEnum">
<summary> 邮件类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailUrgentEnum">
<summary> 邮件加急类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailCron">
<summary> 定时周期 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailTopic">
<summary> 邮件主题 /// </summary>
</member>
<member name="T:IRaCIS.Core.Application.Contracts.SystemBasicDataView">
<summary> SystemBasicDataView 列表视图模型 </summary>
</member>
@ -10274,11 +10355,6 @@
<member name="T:IRaCIS.Core.Application.Contracts.TrialSiteUserSurveyAddOrEdit">
<summary> TrialSiteUserSurveyAddOrEdit 列表查询参数模型</summary>
</member>
<member name="T:IRaCIS.Core.Application.Contracts.JsonPatchUserRequestExample">
<summary>
实测 标注在服务方法上 没用
</summary>
</member>
<member name="T:IRaCIS.Core.Application.Contracts.TrialSiteEquipmentSurveyService">
<summary>
TrialSiteEquipmentSurveyService
@ -11851,6 +11927,12 @@
构造函数注入
</summary>
</member>
<member name="M:IRaCIS.Application.Services.BackGroundJob.IRaCISCHangfireJob.MemoryCacheTrialStatusAsync">
<summary>
缓存项目状态
</summary>
<returns></returns>
</member>
<member name="T:IRaCIS.Application.Services.BusinessFilter.UnifiedApiResultFilter">
<summary>
统一返回前端数据包装之前在控制器包装现在修改为动态Api 在ResultFilter这里包装减少重复冗余代码

View File

@ -13,9 +13,9 @@ using IRaCIS.Core.Domain.Share;
using System.Linq.Expressions;
using IRaCIS.Core.Infra.EFCore.Common;
using System.Linq;
using Nito.AsyncEx;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Service
{
@ -31,16 +31,17 @@ namespace IRaCIS.Core.Application.Service
private readonly IRepository<SubjectUser> _subjectUserRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<Enroll> _enrollRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private readonly AsyncLock _mutex = new AsyncLock();
public TaskConsistentRuleService(IRepository<VisitTask> visitTaskRepository, IRepository<Enroll> enrollRepository, IRepository<TaskConsistentRule> taskConsistentRuleRepository, IRepository<SubjectUser> subjectUserRepository, IRepository<Subject> subjectRepository)
public TaskConsistentRuleService(IRepository<VisitTask> visitTaskRepository, IRepository<Enroll> enrollRepository, IRepository<TaskConsistentRule> taskConsistentRuleRepository, IRepository<SubjectUser> subjectUserRepository, IRepository<Subject> subjectRepository, IDistributedLockProvider distributedLockProvider)
{
_taskConsistentRuleRepository = taskConsistentRuleRepository;
_visitTaskRepository = visitTaskRepository;
_subjectUserRepository = subjectUserRepository;
_subjectRepository = subjectRepository;
_enrollRepository = enrollRepository;
_distributedLockProvider = distributedLockProvider;
}
/// <summary>
@ -142,7 +143,9 @@ namespace IRaCIS.Core.Application.Service
//var list = query.OrderByDescending(t => t.IsHaveGeneratedTask).ToList();
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode");
using (await @lock.AcquireAsync())
{
int maxCodeInt = 0;
@ -293,7 +296,9 @@ namespace IRaCIS.Core.Application.Service
var configDoctorUserIdList = await doctorUserIdQuery.ToListAsync();
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode");
using (await @lock.AcquireAsync())
{
int maxCodeInt = 0;

View File

@ -35,7 +35,7 @@ namespace IRaCIS.Core.Application.ViewModel
{
public CriterionType? CriterionTypeEnum { get; set; }
public CommonDocumentFileType? FileTypeEnum { get; set; }
public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; }
public EmailBusinessScenario? BusinessScenarioEnum { get; set; }
public string Name { get; set; } = String.Empty;
@ -55,7 +55,7 @@ namespace IRaCIS.Core.Application.ViewModel
public CriterionType? CriterionTypeEnum { get; set; }
public CommonDocumentFileType FileTypeEnum { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
//public Guid FileTypeId { get; set; }

View File

@ -3,10 +3,16 @@
// 生成时间 2022-02-15 11:55:57
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
namespace IRaCIS.Core.Application.Contracts
{
public class TrialSelectEmailNoticeConfigView : EmailNoticeConfigView
{
public bool IsHaveSelected { get; set; }
}
/// <summary> EmailNoticeConfigView 列表视图模型 </summary>
public class EmailNoticeConfigView : EmailNoticeConfigAddOrEdit
{
@ -19,6 +25,12 @@ namespace IRaCIS.Core.Application.Contracts
public List<EmailUserTypeDto> EmailNoticeUserList { get; set; }
public new List<UserTypeEnum> ToUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList();
public new List<UserTypeEnum> CopyUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList();
//[JsonIgnore]
//public SystemBasicDataSelect Scenario { get; set; }
////public Guid? ScenarioParentId => Scenario.ParentId;
@ -28,17 +40,29 @@ namespace IRaCIS.Core.Application.Contracts
}
public class EmailUserTypeDto
{
public UserTypeEnum UserType { get; set; }
public EmailUserType EmailUserType { get; set; }
}
///<summary>EmailNoticeConfigQuery 列表查询参数模型</summary>
public class EmailNoticeConfigQuery:PageInput
public class EmailNoticeConfigQuery : PageInput
{
//public Guid? ScenarioId { get; set; }
public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; }
public EmailBusinessScenario? BusinessScenarioEnum { get; set; }
public bool? IsReturnRequired { get; set; }
public bool? IsUrgent { get; set; }
public bool? IsEnable { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
public Guid? TrialId { get; set; }
public bool? IsDistinguishCriteria { get; set; }
}
///<summary> EmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
@ -47,31 +71,66 @@ namespace IRaCIS.Core.Application.Contracts
public Guid? Id { get; set; }
public string Code { get; set; } = String.Empty;
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
/// <summary>
/// 是否区分标准
/// </summary>
public bool IsDistinguishCriteria { get; set; }
//public string AuthorizationCode { get; set; } = String.Empty;
//public Guid ScenarioId { get; set; }
//public string Title { get; set; } = String.Empty;
//public string Body { get; set; } = String.Empty;
//public string FromEmail { get; set; } = String.Empty;
//public string ReceiveEmail { get; set; } = String.Empty;
//public string CopyEmail { get; set; } = String.Empty;
public bool IsReturnRequired { get; set; }
public bool IsUrgent { get; set; }
public bool IsEnable { get; set; }
public bool IsAutoSend { get; set; }
public bool IsDeleted { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
public string Description { get; set; } = string.Empty;
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
public string AttachName { get; set; }
public string AttachNameCN { get; set; }
public List<UserTypeEnum> ToUserTypeList { get; set; }
public List<UserTypeEnum> CopyUserTypeList { get; set; }
}
}

View File

@ -259,7 +259,7 @@ namespace IRaCIS.Application.Services
public async Task<Dictionary<string, List<BasicDicSelectCopy>>> GetBasicDataSelect(string[] searchArray)
{
var searchList = await _dicRepository.Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelectCopy>(_mapper.ConfigurationProvider).ToListAsync();
var searchList = await _dicRepository.Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelectCopy>(_mapper.ConfigurationProvider,new { isEn_Us = _userInfo.IsEn_Us}).ToListAsync();
return searchList.GroupBy(t => t.ParentCode).ToDictionary(g => g.Key, g => g.OrderBy(t => t.ShowOrder).ToList());

View File

@ -17,19 +17,22 @@ namespace IRaCIS.Core.Application.Contracts
public class EmailNoticeConfigService : BaseService, IEmailNoticeConfigService
{
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigrepository;
private readonly IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository;
public EmailNoticeConfigService(IRepository<EmailNoticeConfig> repository)
public EmailNoticeConfigService(IRepository<EmailNoticeConfig> repository, IRepository<EmailNoticeUserType> emailNoticeUserTypeRepository)
{
_emailNoticeConfigrepository = repository;
_emailNoticeUserTypeRepository = emailNoticeUserTypeRepository;
}
[HttpPost]
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig)
{
var emailNoticeConfigQueryable = _emailNoticeConfigrepository
.WhereIf(queryEmailNoticeConfig.IsDistinguishCriteria != null, t => t.IsDistinguishCriteria == queryEmailNoticeConfig.IsDistinguishCriteria)
.WhereIf(queryEmailNoticeConfig.CriterionTypeEnum != null, t => t.CriterionTypeEnum == queryEmailNoticeConfig.CriterionTypeEnum)
.WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum)
.WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired)
.WhereIf(queryEmailNoticeConfig.IsUrgent != null, t => t.IsUrgent == queryEmailNoticeConfig.IsUrgent)
.WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable)
.ProjectTo<EmailNoticeConfigView>(_mapper.ConfigurationProvider);
@ -39,10 +42,55 @@ namespace IRaCIS.Core.Application.Contracts
public async Task<IResponseOutput> AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig)
{
var entity = await _emailNoticeConfigrepository.InsertOrUpdateAsync(addOrEditEmailNoticeConfig, true);
if (addOrEditEmailNoticeConfig.Id == null)
{
var entity = _mapper.Map<EmailNoticeConfig>(addOrEditEmailNoticeConfig);
foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList)
{
entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item });
}
foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList)
{
entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item });
}
await _emailNoticeConfigrepository.AddAsync(entity, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
else
{
var emailNoticeConfigId = addOrEditEmailNoticeConfig.Id;
await _emailNoticeUserTypeRepository.BatchDeleteNoTrackingAsync(t => t.EmailNoticeConfigId == emailNoticeConfigId);
foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList)
{
await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item, EmailNoticeConfigId = (Guid)emailNoticeConfigId });
}
foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList)
{
await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item, EmailNoticeConfigId = (Guid)emailNoticeConfigId });
}
var entity = await _emailNoticeConfigrepository.UpdateFromDTOAsync(addOrEditEmailNoticeConfig, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
return ResponseOutput.Ok(entity.Id.ToString());
}

View File

@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Application.Auth;
using AutoMapper;
using IRaCIS.Application.Contracts;
using Nito.AsyncEx;
using Microsoft.Extensions.Options;
using Medallion.Threading;
namespace IRaCIS.Application.Services
{
@ -54,8 +54,7 @@ namespace IRaCIS.Application.Services
private readonly IRepository<UserType> _userTypeRepository;
private readonly IRepository<Doctor> _doctorTypeRepository;
private readonly AsyncLock _mutex = new AsyncLock();
private readonly IDistributedLockProvider _distributedLockProvider;
private readonly SystemEmailSendConfig _systemEmailConfig;
@ -69,7 +68,7 @@ namespace IRaCIS.Application.Services
IRepository<Trial> trialRepository,
IRepository<UserType> userTypeRepository,
IRepository<Doctor> doctorTypeRepository,
IMapper mapper, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig)
IMapper mapper, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig, IDistributedLockProvider distributedLockProvider)
{
_systemEmailConfig = systemEmailConfig.CurrentValue;
_verificationCodeRepository = verificationCodeRepository;
@ -85,7 +84,7 @@ namespace IRaCIS.Application.Services
_userTypeRepository = userTypeRepository;
_doctorTypeRepository = doctorTypeRepository;
_distributedLockProvider = distributedLockProvider;
}
//重置邮箱
@ -606,7 +605,9 @@ namespace IRaCIS.Application.Services
var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer);
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"UserCode");
using (await @lock.AcquireAsync())
{
var isDoctorHaveAccount = await _userRepository.AnyAsync(t => t.DoctorId == doctorId);

View File

@ -20,7 +20,13 @@ namespace IRaCIS.Core.Application.Service
CreateMap<FrontAuditConfig, FrontAuditConfigAddOrEdit>().ReverseMap();
CreateMap<EmailNoticeConfigAddOrEdit, EmailNoticeConfig>().ReverseMap();
CreateMap<EmailNoticeConfig, EmailNoticeConfigView>();
var trialId = Guid.Empty;
CreateMap<EmailNoticeConfig, TrialSelectEmailNoticeConfigView>().IncludeBase<EmailNoticeConfig, EmailNoticeConfigView>()
.ForMember(o => o.IsHaveSelected, t => t.MapFrom(u => u.TrialEmailNoticeConfigList.Any(c => c.TrialId == trialId && c.SysEmailNoticeConfigId == u.Id)))
;
CreateMap<EmailNoticeConfig, EmailNoticeConfigView>()
.ForMember(t => t.EmailNoticeUserList, u => u.MapFrom(c => c.EmailNoticeUserTypeList));
CreateMap<SystemBasicData, SystemBasicDataView>();
@ -45,7 +51,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<Dictionary, BasicDicSelectCopy>()
.ForMember(o => o.ParentChildCodeEnum, t => t.MapFrom(u => u.Parent.ChildCodeEnum))
.ForMember(o => o.Value, t => t.MapFrom(u => u.MappedValue))
.ForMember(o => o.Value, t => t.MapFrom(u => isEn_Us? u.Value : u.ValueCN ))
.ForMember(o => o.ParentCode, t => t.MapFrom(u => u.Parent.Code));
CreateMap<Dictionary, BasicDicSelect>()

View File

@ -36,7 +36,7 @@ namespace IRaCIS.Core.Application.ViewModel
}
public class EmailUserInfoDto
public class EmailUserInfoDto
{
public Guid TrialEmailNoticeConfigId { get; set; }
@ -77,7 +77,7 @@ namespace IRaCIS.Core.Application.ViewModel
/// <summary>
/// SMTP端口
/// </summary>
public int? EmailSMTPServerPort { get; set; }
public int EmailSMTPServerPort { get; set; }
/// <summary>
/// 是否配置过邮箱
@ -87,7 +87,7 @@ namespace IRaCIS.Core.Application.ViewModel
public class SetTrialEmailInDto : GetTrialEmailSetOutDto
{
}
public class GetTrialEmailSetInDto
{
@ -100,7 +100,7 @@ namespace IRaCIS.Core.Application.ViewModel
[NotDefault]
public Guid TrialId { get; set; }
public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; }
public EmailBusinessScenario? BusinessScenarioEnum { get; set; }
//public CriterionType? CriterionTypeEnum { get; set; }
@ -117,51 +117,98 @@ namespace IRaCIS.Core.Application.ViewModel
public Guid TrialReadingCriterionId { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
}
///<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
public class TrialEmailNoticeConfigAddOrEdit
public class BatchAddTrialEmailNoticeConfig
{
public Guid? Id { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
public string Code { get; set; } = string.Empty;
public Guid? TrialReadingCriterionId { get; set; }
public Guid TrialId { get; set; }
public string AuthorizationCode { get; set; } = string.Empty;
public string SMTPServerAddress { get; set; } = string.Empty;
public int SMTPServerPort { get; set; }
public CriterionType CriterionTypeEnum { get; set; }
public string FromName { get; set; } = string.Empty;
public string FromEmail { get; set; } = string.Empty;
public CriterionType? CriterionTypeEnum { get; set; }
public List<UserTypeEnum>? ToUserTypeList { get; set; }
public List<UserTypeEnum> ToUserTypeList { get; set; }
public List<UserTypeEnum> CopyUserTypeList { get; set; }
public bool IsUrgent { get; set; }
public bool IsEnable { get; set; }
public bool IsAutoSend { get; set; }
public bool IsReturnRequired { get; set; }
public string FilePath { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; } = string.Empty;
public string AttachNameCN { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
}
///<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
public class TrialEmailNoticeConfigAddOrEdit : BatchAddTrialEmailNoticeConfig
{
public Guid? TrialReadingCriterionId { get; set; }
public string AuthorizationCode { get; set; } = string.Empty;
public string SMTPServerAddress { get; set; } = string.Empty;
public int SMTPServerPort { get; set; }
public string FromName { get; set; } = string.Empty;
public string FromEmail { get; set; } = string.Empty;
public List<Guid> BlackUserIdList { get; set; }
}

View File

@ -0,0 +1,403 @@
using DocumentFormat.OpenXml.EMMA;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MailKit;
using Microsoft.Extensions.Options;
using Microsoft.VisualBasic;
using MimeKit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service
{
public interface IEmailSendService
{
Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm);
Task SendTrialImageQCTaskEmailAsync(Guid trialId);
Task SendTrialQCQuestionEmailAsync(Guid trialId);
Task SendTrialImageQuestionAsync(Guid trialId);
}
public class EmailSendService : BaseService, IEmailSendService
{
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IDictionaryService _dictionaryService;
private readonly IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig;
public readonly static string EmailNamePlaceholder = "EmailNamePlaceholder";
public EmailSendService(IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<EmailNoticeConfig> emailNoticeConfigRepository, IRepository<Trial> trialRepository, IOptionsMonitor<SystemEmailSendConfig> systemEmailSendConfig, IDictionaryService dictionaryService)
{
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_emailNoticeConfigRepository = emailNoticeConfigRepository;
_trialRepository = trialRepository;
_SystemEmailSendConfig = systemEmailSendConfig;
_dictionaryService = dictionaryService;
}
//入组确认/PD确认
public async Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm)
{
EmailBusinessScenario businessScenarioEnum;
bool? result = null;
if (isEnrollment != null && isPDConfirm == null)
{
businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed;
result = isEnrollment;
}
else
{
businessScenarioEnum = EmailBusinessScenario.PDConfirmed;
result = isPDConfirm;
}
var taskInfo = await _repository.Where<VisitTask>(t => t.Id == visitTaskId).Select(t => new
{
t.Subject.SiteId,
t.Trial.ResearchProgramNo,
t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
t.Trial.Sponsor.SponsorName,
t.SourceSubjectVisit.VisitName,
t.TrialId,
}).FirstNotNullAsync();
var isEn_us = _userInfo.IsEn_Us;
var resultStr = isEn_us ? (result == true ? "Yes" : "No") : (result == true ? "是" : "否");
if (isEnrollment == true)
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, resultStr);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.SiteId);
}
else
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName, resultStr);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.SiteId);
}
}
/// <summary>
/// 影像质控
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialImageQCTaskEmailAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = await _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
//找到 该项目的IQC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
var userIdList = userList.Select(t => t.UserId).ToList();
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository.Where(t => t.Id == trialId)
.Where(t => t.QCProcessEnum != TrialQCProcess.NotAudit)
.Select(t => new
{
//待领取量
ToBeClaimedCount = t.SubjectVisitList.Where(u => u.SubmitState == SubmitStateEnum.Submitted && u.CurrentActionUserId == null && (u.PreliminaryAuditUserId == null || (u.PreliminaryAuditUserId != userId && u.ReviewAuditUserId == null))).Count(),
//待审核通过统计从已领取到QC提交之间的 已领取 待审核 审核中 (审核完成 领取人就会清理 所以只用查询当前领取人是自己的就好了)
ToBeReviewedCount = t.SubjectVisitList.Where(u => u.CurrentActionUserId == userId).Count()
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人 有待领取的或者有待审核的才发邮件
if (sendStat != null && (sendStat.ToBeClaimedCount > 0 || sendStat.ToBeReviewedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false, userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCTask, topicAndHtmlFunc);
}
}
}
/// <summary>
/// QC质疑
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialQCQuestionEmailAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr, t.DeclarationTypeEnumList }).FirstOrDefault();
//找到 该项目的IQC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository
.Where(t => t.Id == trialId)
.Select(t => new
{
ReUploadTobeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList)
.Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && u.ReuploadEnum == QCChanllengeReuploadEnum.CRCRequestReupload).Count(),
//质疑待处理 发送邮件的时候 需要减去ReUploadTobeDealedCount
ToBeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList)
.Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Count(),
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人
if (sendStat != null && (sendStat.ToBeDealedCount > 0 || sendStat.ReUploadTobeDealedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false, userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCQuestion, topicAndHtmlFunc);
}
}
}
/// <summary>
/// 影像质疑
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialImageQuestionAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstOrDefault();
//找到 该项目的CRC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository.Where(t => t.Id == trialId)
.Select(t => new
{
//质疑待处理
ToBeDealedCount = t.SubjectVisitList.Where(t => t.TrialSite.CRCUserList.Any(t => t.UserId == userId)).SelectMany(c => c.QCChallengeList)
.Where(u => u.IsClosed == false && (u.LatestReplyUser.UserTypeEnum == UserTypeEnum.IQC || u.LatestReplyUserId == null)).Count(),
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人
if (sendStat != null && (sendStat.ToBeDealedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.ImageQuestion, topicAndHtmlFunc);
}
}
}
public async Task SendTrialEmailAsync(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? siteId = null, Guid? trialReadingCriterionId = null)
{
//找到配置
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false)
{
return;
}
else
{
var sendEmailConfig = new SMTPEmailConfig();
var (topicStr, htmlBodyStr, isEn_us, onlyToUserId) = topicAndHtmlFunc(trialEmailConfig);
sendEmailConfig.TopicDescription = topicStr;
sendEmailConfig.HtmlBodyStr = htmlBodyStr;
var blackUserIdList = trialEmailConfig.TrialEmailBlackUserList.Select(t => t.UserId).ToList();
var toUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(c => c.UserType).ToList();
var copyUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(c => c.UserType).ToList();
var allUserTypeEnumList = toUserTypeEnumList.Union(copyUserTypeEnumList).Distinct().ToList();
var allUserList = await _repository.Where<TrialUser>(t => t.TrialId == trialId && allUserTypeEnumList.Contains(t.User.UserTypeEnum)).Select(t => new { t.UserId, t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToListAsync();
var toUserList = allUserList.Where(t => toUserTypeEnumList.Contains(t.UserTypeEnum))
.ToList();
//收件人 有CRC CRA CRC CRA的账户要按照中心发送
if (siteId == null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA) && onlyToUserId == null)
{
throw new BusinessValidationFailedException("当前场景收件人包含CRC CRA,但是没有siteId,请联系后端开发");
}
if (siteId != null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA))
{
var curentSiteUserIdList = _repository.Where<TrialSiteUser>(t => t.TrialId == trialId && t.SiteId == siteId).Select(t => t.UserId).ToList();
toUserList = toUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList();
}
//去除黑名单
toUserList = toUserList.Where(t => !blackUserIdList.Contains(t.UserId)).ToList();
var copyUserList = allUserList.Where(t => copyUserTypeEnumList.Contains(t.UserTypeEnum))
.Where(t => !blackUserIdList.Contains(t.UserId)).ToList();
if (siteId != null && copyUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA))
{
var curentSiteUserIdList = _repository.Where<TrialSiteUser>(t => t.TrialId == trialId && t.SiteId == siteId).Select(t => t.UserId).ToList();
copyUserList = copyUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList();
}
if (onlyToUserId != null)
{
toUserList = toUserList.Where(t => t.UserId == onlyToUserId).ToList();
}
else
{
sendEmailConfig.HtmlBodyStr = htmlBodyStr.Replace(EmailNamePlaceholder, string.Join(isEn_us ? ", " : "、", toUserList.Select(t => t.FullName).ToList()));
}
if (toUserList.Count() == 0)
{
//---没有收件人,无法发送邮件
throw new BusinessValidationFailedException(_localizer["TrialEmailN_NoRecipient"]);
}
if (trialEmailConfig.FromEmail.Contains("@") && !string.IsNullOrEmpty(trialEmailConfig.FromEmail))
{
sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(trialEmailConfig.FromName, trialEmailConfig.FromEmail);
sendEmailConfig.AuthorizationCode = trialEmailConfig.AuthorizationCode;
sendEmailConfig.UserName = trialEmailConfig.FromEmail;
sendEmailConfig.Host = trialEmailConfig.SMTPServerAddress;
sendEmailConfig.Port = trialEmailConfig.SMTPServerPort;
}
else
{
//---项目发件邮箱配置有误,请核实
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidEmailConfig"]);
}
foreach (var item in toUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
foreach (var item in copyUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
await SendEmailHelper.SendEmailAsync(sendEmailConfig);
}
}
}
}

View File

@ -170,7 +170,7 @@ namespace IRaCIS.Core.Application.Services
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
Name = sysDoc.Name,
Path = sysDoc.Path,
FileType = sysDoc.FileType.MappedValue,
FileType = _userInfo.IsEn_Us? sysDoc.FileType.Value: sysDoc.FileType.ValueCN,
UpdateTime = sysDoc.UpdateTime,
FullFilePath = sysDoc.Path ,

View File

@ -60,7 +60,7 @@ namespace IRaCIS.Core.Application.Services
var trialDocumentQueryable = _trialDocumentRepository.AsQueryable(true).Where(t => t.TrialId == queryTrialDocument.TrialId)
.WhereIf(!string.IsNullOrEmpty(queryTrialDocument.Name), t => t.Name.Contains(queryTrialDocument.Name))
.WhereIf(queryTrialDocument.FileTypeId != null, t => t.FileTypeId == queryTrialDocument.FileTypeId)
.ProjectTo<TrialDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken });
.ProjectTo<TrialDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, isEn_Us=_userInfo.IsEn_Us });
return await trialDocumentQueryable.ToPagedListAsync(queryTrialDocument.PageIndex, queryTrialDocument.PageSize, queryTrialDocument.SortField, queryTrialDocument.Asc);
}
@ -187,7 +187,7 @@ namespace IRaCIS.Core.Application.Services
Name = needConfirmedUserType.SystemDocument.Name,
Path = needConfirmedUserType.SystemDocument.Path,
FileTypeId = needConfirmedUserType.SystemDocument.FileTypeId,
FileType = needConfirmedUserType.SystemDocument.FileType.MappedValue,
FileType = _userInfo.IsEn_Us? needConfirmedUserType.SystemDocument.FileType.Value: needConfirmedUserType.SystemDocument.FileType.ValueCN,
UpdateTime = needConfirmedUserType.SystemDocument.UpdateTime,
FullFilePath = needConfirmedUserType.SystemDocument.Path ,
@ -219,7 +219,7 @@ namespace IRaCIS.Core.Application.Services
Name = trialDoc.Name,
Path = trialDoc.Path,
FileTypeId = trialDoc.FileTypeId,
FileType = trialDoc.FileType.MappedValue,
FileType = _userInfo.IsEn_Us ? trialDoc.FileType.Value: trialDoc.FileType.ValueCN,
UpdateTime = trialDoc.UpdateTime,
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
@ -333,7 +333,7 @@ namespace IRaCIS.Core.Application.Services
Name = trialDocumentNeedConfirmedUserType.TrialDocument.Name,
Path = trialDocumentNeedConfirmedUserType.TrialDocument.Path,
FileTypeId = trialDocumentNeedConfirmedUserType.TrialDocument.FileTypeId,
FileType = trialDocumentNeedConfirmedUserType.TrialDocument.FileType.MappedValue,
FileType = _userInfo.IsEn_Us ? trialDocumentNeedConfirmedUserType.TrialDocument.FileType.Value : trialDocumentNeedConfirmedUserType.TrialDocument.FileType.ValueCN,
UpdateTime = trialDocumentNeedConfirmedUserType.TrialDocument.UpdateTime,
@ -367,7 +367,7 @@ namespace IRaCIS.Core.Application.Services
SignViewMinimumMinutes = needConfirmEdUserType.SystemDocument.SignViewMinimumMinutes,
Name = needConfirmEdUserType.SystemDocument.Name,
Path = needConfirmEdUserType.SystemDocument.Path,
FileType = needConfirmEdUserType.SystemDocument.FileType.MappedValue,
FileType = _userInfo.IsEn_Us ? needConfirmEdUserType.SystemDocument.FileType.Value : needConfirmEdUserType.SystemDocument.FileType.ValueCN,
FileTypeId = needConfirmEdUserType.SystemDocument.FileTypeId,
UpdateTime = needConfirmEdUserType.SystemDocument.UpdateTime,

View File

@ -32,30 +32,41 @@ namespace IRaCIS.Core.Application.Service
{
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<TrialEmailBlackUser> _trialEmailBlackUserRepository;
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<TaskMedicalReview> _taskMedicalReviewRepository;
private readonly IRepository<VisitTask> _visitTaskRepository;
private readonly IRepository<TrialUser> _trialUserRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
public IRepository<VisitTask> _visitTaskRepository { get; }
public IRepository<TrialUser> _trialUserRepository { get; }
public IRepository<Subject> _subjectRepository { get; }
public IRepository<SubjectVisit> _subjectVisitRepository { get; }
public TrialEmailNoticeConfigService(IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<VisitTask> visitTaskRepository,
public TrialEmailNoticeConfigService(
IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository,
IRepository<VisitTask> visitTaskRepository,
IRepository<Trial> trialRepository,
IRepository<TrialUser> trialUserRepository, IRepository<TaskMedicalReview> taskMedicalReviewRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository)
IRepository<TrialUser> trialUserRepository,
IRepository<TaskMedicalReview> taskMedicalReviewRepository,
IRepository<Subject> subjectRepository,
IRepository<SubjectVisit> subjectVisitRepository,
IRepository<TrialEmailBlackUser> trialEmailBlackUserRepository,
IRepository<EmailNoticeConfig> emailNoticeConfigRepository
)
{
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_visitTaskRepository = visitTaskRepository;
this._trialRepository = trialRepository;
_trialRepository = trialRepository;
_trialUserRepository = trialUserRepository;
_taskMedicalReviewRepository = taskMedicalReviewRepository;
_subjectRepository = subjectRepository;
_subjectVisitRepository = subjectVisitRepository;
_trialEmailBlackUserRepository = trialEmailBlackUserRepository;
_emailNoticeConfigRepository = emailNoticeConfigRepository;
}
/// <summary>
@ -66,7 +77,7 @@ namespace IRaCIS.Core.Application.Service
[HttpPost]
public async Task<GetTrialEmailSetOutDto> GetTrialEmail(GetTrialEmailSetInDto inDto)
{
return await _trialRepository.Where(x => x.Id == inDto.TrialId).Select(x => new GetTrialEmailSetOutDto()
return await _trialRepository.Where(x => x.Id == inDto.TrialId, ignoreQueryFilters: true).Select(x => new GetTrialEmailSetOutDto()
{
TrialId = inDto.TrialId,
EmailAuthorizationCode = x.EmailAuthorizationCode,
@ -76,7 +87,7 @@ namespace IRaCIS.Core.Application.Service
IsConfigureEmail = x.IsConfigureEmail,
EmailSMTPServerPort = x.EmailSMTPServerPort
}).FirstNotNullAsync();
}).FirstOrDefaultAsync();
}
/// <summary>
@ -94,7 +105,7 @@ namespace IRaCIS.Core.Application.Service
FromEmail = inDto.EmailFromEmail,
FromName = inDto.EmailFromName,
SMTPServerAddress = inDto.EmailSMTPServerAddress,
SMTPServerPort = inDto.EmailSMTPServerPort.Value,
SMTPServerPort = inDto.EmailSMTPServerPort,
TrialId = inDto.TrialId,
});
@ -117,7 +128,7 @@ namespace IRaCIS.Core.Application.Service
FromEmail = inDto.EmailFromEmail,
FromName = inDto.EmailFromName,
SMTPServerAddress = inDto.EmailSMTPServerAddress,
SMTPServerPort = inDto.EmailSMTPServerPort.Value,
SMTPServerPort = inDto.EmailSMTPServerPort,
});
await _trialRepository.SaveChangesAsync();
@ -125,7 +136,7 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 同步系统配置的文档到想项目中
/// 同步系统配置的文档到想项目中 ---废弃
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
@ -139,7 +150,7 @@ namespace IRaCIS.Core.Application.Service
{
//只要有系统标准的文档 说明同步过了
var trialDocCount = _trialEmailNoticeConfigRepository.Where(t =>/* t.CriterionTypeEnum == criterionTypeEnum &&*/ t.TrialId == trialId && t.TrialReadingCriterionId != null).Count();
var trialDocCount = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId).Count();
if (trialDocCount == 0)
{
@ -148,7 +159,10 @@ namespace IRaCIS.Core.Application.Service
var confirmedCriterionTypeList = list.Select(t => (CriterionType?)t.CriterionType).ToList();
var docmentList = _repository.Where<CommonDocument>(t => confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum }).ToList();
var docmentList = _repository.Where<TrialEmailNoticeConfig>(t => t.BusinessScenarioEnum == EmailBusinessScenario.EnrollConfirmed || t.BusinessScenarioEnum == EmailBusinessScenario.PDConfirmed)
//.Where(t => (confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)) || t.CriterionTypeEnum == null).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum })
.ToList();
foreach (var item in docmentList)
@ -157,8 +171,8 @@ namespace IRaCIS.Core.Application.Service
{
TrialId = trialId,
TrialReadingCriterionId = list.Where(t => t.CriterionType == item.CriterionTypeEnum).FirstOrDefault()?.TrialReadingCriterionId,
FileName = item.Name,
FilePath = item.Path,
//FileName = item.Name,
//FilePath = item.Path,
BusinessScenarioEnum = item.BusinessScenarioEnum,
Code = item.Code
});
@ -176,6 +190,7 @@ namespace IRaCIS.Core.Application.Service
private async Task<bool> DealMedicalReviewTasKGenerateAndIsSendAsync(Guid trialId, bool? isHandSend, string pdAnswer, List<Guid> taskIdList, List<Guid> minUserIdList)
{
@ -241,7 +256,7 @@ namespace IRaCIS.Core.Application.Service
public async Task<string> BaseBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? isHandSend, EmailStoreSendMode emailStoreMode, string sendFileRelativePath)
{
CommonDocumentBusinessScenario? businessScenarioEnum = null;
EmailBusinessScenario? businessScenarioEnum = null;
#region 任务关联的项目配置 标准信息及配置subject 信息
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new
@ -309,7 +324,7 @@ namespace IRaCIS.Core.Application.Service
//入组确认场景
if (taskInfo.IsEnrollmentConfirm == true && taskInfo.IsEnrollementQualificationConfirm == true && taskInfo.IsBaseline == true)
{
businessScenarioEnum = CommonDocumentBusinessScenario.EnrollConfirmed;
businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed;
}
@ -318,7 +333,7 @@ namespace IRaCIS.Core.Application.Service
(taskInfo.PDState == PDStateEnum.PDProgress && taskInfo.SourceSubjectVisitId != null) ||
(taskInfo.SouceReadModuleId != null && taskInfo.MoudulePDState == PDStateEnum.PDProgress))
{
businessScenarioEnum = CommonDocumentBusinessScenario.PDConfirmed;
businessScenarioEnum = EmailBusinessScenario.PDConfirmed;
}
else
{
@ -344,7 +359,7 @@ namespace IRaCIS.Core.Application.Service
.Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync();
if (emailConfig == null || (emailConfig.IsAutoSend == false && isHandSend==null))
if (emailConfig == null || (emailConfig.IsAutoSend == false && isHandSend == null))
{
//throw new BusinessValidationFailedException("找不到该项目标准场景下邮件的配置");
@ -418,7 +433,7 @@ namespace IRaCIS.Core.Application.Service
#region 确保 邮件Html存在
//邮件附件
var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, emailConfig.FilePath);
var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, _userInfo.IsEn_Us ? emailConfig.AttachPath : emailConfig.AttachCNPath);
if (!File.Exists(path))
{
@ -431,7 +446,7 @@ namespace IRaCIS.Core.Application.Service
+ Path.DirectorySeparatorChar.ToString()
+ "EmailTemplate"
+ Path.DirectorySeparatorChar.ToString()
//+ "SubjectEnrollConfirmOrPDProgress.html";
//+ "SubjectEnrollConfirmOrPDProgress.html";
+ (_userInfo.IsEn_Us ? "SubjectEnrollConfirmOrPDProgress_US.html" : "SubjectEnrollConfirmOrPDProgress.html");
#endregion
@ -439,7 +454,7 @@ namespace IRaCIS.Core.Application.Service
#region 不同场景 Tile 设置
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_EnrollmentConfirmation", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
@ -454,7 +469,7 @@ namespace IRaCIS.Core.Application.Service
);
}
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_PDReport", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
@ -464,7 +479,7 @@ namespace IRaCIS.Core.Application.Service
sendEmailConfig.HtmlBodyStr = string.Format(templateInfo,
//--- 附件为疾病进展确认报告,请查收
//--- 附件为疾病进展确认报告,请查收
_localizer["TrialEmailN_SubjectDiseaseProgression"]
);
}
@ -486,7 +501,7 @@ namespace IRaCIS.Core.Application.Service
//入组确认 根据每个标准配置的是否自动发送,发送邮件与否
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
if (await _repository.Where<ReadingTableQuestionAnswer>().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() &&
x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion))
@ -531,7 +546,7 @@ namespace IRaCIS.Core.Application.Service
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
@ -629,7 +644,7 @@ namespace IRaCIS.Core.Application.Service
}
else
{
//---发送PD 进展邮件中发现任务数据有问题!
//---发送PD 进展邮件中发现任务数据有问题!
throw new BusinessValidationFailedException(_localizer["TrialEmailN_PDProgressEmailTask"]);
}
@ -639,13 +654,13 @@ namespace IRaCIS.Core.Application.Service
else
{
//---双重有序阅片 没有定义该仲裁规则处理逻辑,请联系业务和后台开发核查!
//---双重有序阅片 没有定义该仲裁规则处理逻辑,请联系业务和后台开发核查!
throw new BusinessValidationFailedException(_localizer["TrialEmailN_DoubleBlindedError"]);
}
}
//屏蔽单重阅片添加
else
{
@ -661,7 +676,7 @@ namespace IRaCIS.Core.Application.Service
// if (taskInfo.ArbitrationRule != ArbitrationRule.None)
// {
//---单重有序阅片配置有误(不应该有仲裁对象配置),请核查!
//---单重有序阅片配置有误(不应该有仲裁对象配置),请核查!
// throw new BusinessValidationFailedException(_localizer["TrialEmailN_SingleBlindedSet"]);
// }
@ -687,7 +702,7 @@ namespace IRaCIS.Core.Application.Service
// }
// else
// {
//---单重有序阅片 该类型的任务不应进入此处逻辑,请联系后台开发核查!
//---单重有序阅片 该类型的任务不应进入此处逻辑,请联系后台开发核查!
// throw new BusinessValidationFailedException(_localizer["TrialEmailN_SingleBlindedSequenced"]);
// }
@ -697,7 +712,7 @@ namespace IRaCIS.Core.Application.Service
//}
//else
//{
//---有序阅片配置有误(应为单重或者双重阅片),请核查!
//---有序阅片配置有误(应为单重或者双重阅片),请核查!
// throw new BusinessValidationFailedException(_localizer["TrialEmailN_BlindedSequencedReading"]);
//}
@ -788,7 +803,7 @@ namespace IRaCIS.Core.Application.Service
//先预先生成了邮件,发送预先生成的邮件
sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig()
{
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf",
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf",
FileStream = File.OpenRead(phyPath),
});
@ -812,7 +827,7 @@ namespace IRaCIS.Core.Application.Service
};
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetSubjectEnrollConfirmOrPDEmailPath(_hostEnvironment, Path.GetFileName(path), taskInfo.TrialId, taskInfo.SiteId, taskInfo.SubjectId,true);
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetSubjectEnrollConfirmOrPDEmailPath(_hostEnvironment, Path.GetFileName(path), taskInfo.TrialId, taskInfo.SiteId, taskInfo.SubjectId, true);
if (emailStoreMode == EmailStoreSendMode.StoreLocalSend || emailStoreMode == EmailStoreSendMode.OnlyStoreLocalNotSentEmail)
{
@ -823,7 +838,7 @@ namespace IRaCIS.Core.Application.Service
MiniSoftware.MiniWord.SaveAsByTemplate(wordMemoryStream, path, value);
document.LoadFromStream(wordMemoryStream,FileFormat.Docx);
document.LoadFromStream(wordMemoryStream, FileFormat.Docx);
document.SaveToFile(serverFilePath, FileFormat.PDF);
@ -856,7 +871,7 @@ namespace IRaCIS.Core.Application.Service
sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig()
{
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf",
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf",
FileStream = pdfMemoryStream
});
@ -900,19 +915,19 @@ namespace IRaCIS.Core.Application.Service
//找到入组确认 或者Pd 进展 已生成任务的 访视
var subjectVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId & t.CheckState == CheckStateEnum.CVPassed && (t.IsEnrollmentConfirm == true || t.PDState == PDStateEnum.PDProgress)).ToListAsync();
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
if (trialConfig.IsEnrollementQualificationConfirm == false)
{
//---项目未配置入组确认!
//---项目未配置入组确认!
return ResponseOutput.NotOk(_localizer["TrialEmailN_InCons"]);
}
var exisitBaseline = subjectVisitList.FirstOrDefault(t => t.IsEnrollmentConfirm);
if (exisitBaseline == null)
{
//---不存在配置了入组确认的并且生成任务的基线访视
//---不存在配置了入组确认的并且生成任务的基线访视
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoBaseLine"]);
}
else
@ -933,7 +948,7 @@ namespace IRaCIS.Core.Application.Service
if (task == null)
{
//---做入组确认的阅片人基线任务没有阅片完!
//---做入组确认的阅片人基线任务没有阅片完!
return ResponseOutput.NotOk(_localizer["TrialEmailN_IncompBase"]);
}
else
@ -942,7 +957,7 @@ namespace IRaCIS.Core.Application.Service
if (string.IsNullOrEmpty(filePath))
{
//---邮件手动生成失败,请联系开发核实该场景失败原因
//---邮件手动生成失败,请联系开发核实该场景失败原因
return ResponseOutput.NotOk(_localizer["TrialEmailN_EmailFail"]);
}
else
@ -956,7 +971,7 @@ namespace IRaCIS.Core.Application.Service
}
else
{
//---当前未有阅片人读完基线任务!
//---当前未有阅片人读完基线任务!
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoReader"]);
}
@ -967,12 +982,12 @@ namespace IRaCIS.Core.Application.Service
}
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
if (trialConfig.IsPDProgressView == false)
{
//---项目未配置PD进展
//---项目未配置PD进展
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoPDConfig"]);
}
@ -982,7 +997,7 @@ namespace IRaCIS.Core.Application.Service
if (pdSubjectVisitIdList.Count == 0)
{
//---不存在配置了PD进展的并且生成任务的访视
//---不存在配置了PD进展的并且生成任务的访视
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoPDTasks"]);
}
@ -1027,7 +1042,7 @@ namespace IRaCIS.Core.Application.Service
}
else
{
//---当前受试者最新PD访视阅片任务完成状态不符合发送条件
//---当前受试者最新PD访视阅片任务完成状态不符合发送条件
return ResponseOutput.NotOk(_localizer["TrialEmailN_PDNotFinished"]);
}
@ -1040,7 +1055,7 @@ namespace IRaCIS.Core.Application.Service
if (existReadModule == null)
{
//---项目配置了阅片期仲裁但是当前受试者最新PD访视没有影像学阅片期
//---项目配置了阅片期仲裁但是当前受试者最新PD访视没有影像学阅片期
return ResponseOutput.NotOk(_localizer["TrialEmailN_PDNoImaging"]);
}
else
@ -1075,7 +1090,7 @@ namespace IRaCIS.Core.Application.Service
else
{
//---当前受试者最新PD访视阅片期任务完成状态不符合发送条件
//---当前受试者最新PD访视阅片期任务完成状态不符合发送条件
return ResponseOutput.NotOk(_localizer["TrialEmailN_PDPhaseNotFinished"]);
}
}
@ -1084,7 +1099,7 @@ namespace IRaCIS.Core.Application.Service
}
else
{
//---未定义该仲裁规则发送业务逻辑!
//---未定义该仲裁规则发送业务逻辑!
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoRuleDefined"]);
}
}
@ -1143,7 +1158,7 @@ namespace IRaCIS.Core.Application.Service
else
{
//---当前项目配置,不满足双重有序阅片,不满足发送条件!
//---当前项目配置,不满足双重有序阅片,不满足发送条件!
return ResponseOutput.NotOk(_localizer["TrialEmailN_NoDoubleOrder"]);
}
@ -1233,7 +1248,7 @@ namespace IRaCIS.Core.Application.Service
//}
else
{
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]);
}
@ -1273,7 +1288,7 @@ namespace IRaCIS.Core.Application.Service
//}
else
{
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]);
}
@ -1311,7 +1326,7 @@ namespace IRaCIS.Core.Application.Service
case CriterionType.IMWG2016:
default:
//---该标准任务还未定义PD获取逻辑联系业务和后台开发协商后补充
//---该标准任务还未定义PD获取逻辑联系业务和后台开发协商后补充
throw new BusinessValidationFailedException(_localizer["TrialEmailN_PDLogicNotDefined"]);
}
@ -1335,19 +1350,127 @@ namespace IRaCIS.Core.Application.Service
var query = _trialUserRepository.Where(t => t.TrialId == trialId, false, true).IgnoreQueryFilters().Select(t => t.User.UserTypeRole).Distinct()
.ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
.ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
return await query.ToListAsync();
}
/// <summary>
/// 黑名单用户Id 列表
/// </summary>
/// <param name="trialEmailNoticeConfigId"></param>
/// <returns></returns>
public async Task<List<TrialSelectUser>> GetTrialUserIdSelectList(Guid trialEmailNoticeConfigId)
{
var trialEmailNoticeConfig = await _trialEmailNoticeConfigRepository.Where(t => t.Id == trialEmailNoticeConfigId).Include(t => t.TrialEmailNoticeUserList).FirstNotNullAsync();
var trialId = trialEmailNoticeConfig.TrialId;
var userTypeList = trialEmailNoticeConfig.TrialEmailNoticeUserList.Select(t => t.UserType).ToList();
var query = _trialUserRepository.Where(t => t.TrialId == trialId && userTypeList.Contains(t.User.UserTypeEnum), false, true).IgnoreQueryFilters()
.Select(t => new TrialSelectUser()
{
UserId = t.UserId,
UserName = t.User.UserName,
RealName = t.User.FullName,
UserTypeEnum = t.User.UserTypeEnum
}).Distinct();
return await query.ToListAsync();
}
/// <summary>
/// 获取系统 邮件配置 勾选列表
/// </summary>
/// <param name="queryEmailNoticeConfig"></param>
/// <returns></returns>
public async Task<PageOutput<TrialSelectEmailNoticeConfigView>> GetSysEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig)
{
var emailNoticeConfigQueryable = _emailNoticeConfigRepository
.WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum)
.WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired)
.WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable)
.ProjectTo<TrialSelectEmailNoticeConfigView>(_mapper.ConfigurationProvider, new { trialId = queryEmailNoticeConfig.TrialId });
return await emailNoticeConfigQueryable.ToPagedListAsync(queryEmailNoticeConfig.PageIndex, queryEmailNoticeConfig.PageSize, queryEmailNoticeConfig.SortField, queryEmailNoticeConfig.Asc);
}
/// <summary>
/// 批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系
/// </summary>
/// <param name="batchAddList"></param>
/// <returns></returns>
public async Task<IResponseOutput> BatchAddSysEmailConfig(List<BatchAddTrialEmailNoticeConfig> batchAddList)
{
var first = batchAddList.First();
var trialId = first.TrialId;
var emailConfig = await _trialRepository.Where(t => t.Id == trialId).Select(x => new
{
TrialId = x.Id,
EmailAuthorizationCode = x.EmailAuthorizationCode,
EmailSMTPServerAddress = x.EmailSMTPServerAddress,
EmailFromEmail = x.EmailFromEmail,
EmailFromName = x.EmailFromName,
IsConfigureEmail = x.IsConfigureEmail,
EmailSMTPServerPort = x.EmailSMTPServerPort
}).FirstNotNullAsync();
var list = await _repository.Where<ReadingQuestionCriterionTrial>(t => t.TrialId == trialId && t.IsConfirm).Select(t => new { t.CriterionType, TrialReadingCriterionId = t.Id }).ToListAsync();
var addList = _mapper.Map<List<TrialEmailNoticeConfig>>(batchAddList);
foreach (var item in addList)
{
item.SysEmailNoticeConfigId = item.Id;
item.Id = Guid.Empty;
item.AuthorizationCode = emailConfig.EmailAuthorizationCode;
item.FromEmail = emailConfig.EmailFromEmail;
item.SMTPServerAddress = emailConfig.EmailSMTPServerAddress;
item.FromName = emailConfig.EmailFromName;
item.SMTPServerPort = emailConfig.EmailSMTPServerPort;
item.IsAutoSend = false;
item.IsEnable = false;
item.TrialReadingCriterionId = list.FirstOrDefault(t => t.CriterionType == item.CriterionTypeEnum)?.TrialReadingCriterionId;
item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId)
.SelectMany(t => t.ToUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = t }));
item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId)
.SelectMany(t => t.CopyUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = t }));
await _trialEmailNoticeConfigRepository.AddAsync(item);
}
await _trialEmailNoticeConfigRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpPost]
public async Task<List<TrialEmailNoticeConfigView>> GetTrialEmailNoticeConfigList(TrialEmailNoticeConfigQuery inQuery)
{
await SyncSystemEmainCofigDocListAsync(inQuery.TrialId);
//await SyncSystemEmainCofigDocListAsync(inQuery.TrialId);
var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.IsDistinguishCriteria == false, t => t.TrialReadingCriterionId == null)
.WhereIf(inQuery.IsDistinguishCriteria == true, t => t.CriterionTypeEnum != null)
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
.WhereIf(inQuery.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == inQuery.BusinessScenarioEnum)
.ProjectTo<TrialEmailNoticeConfigView>(_mapper.ConfigurationProvider);
@ -1355,6 +1478,7 @@ namespace IRaCIS.Core.Application.Service
return await trialEmailNoticeConfigQueryable.ToListAsync();
}
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> AddOrUpdateTrialEmailNoticeConfig(TrialEmailNoticeConfigAddOrEdit addOrEditTrialEmailNoticeConfig)
{
@ -1379,6 +1503,10 @@ namespace IRaCIS.Core.Application.Service
}
foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList)
{
entity.TrialEmailBlackUserList.Add(new TrialEmailBlackUser() { UserId = userid });
}
await _trialEmailNoticeConfigRepository.AddAsync(entity, true);
@ -1387,10 +1515,10 @@ namespace IRaCIS.Core.Application.Service
}
else
{
var id = (Guid)addOrEditTrialEmailNoticeConfig.Id;
await _repository.BatchDeleteAsync<TrialEmailNoticeUser>(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id);
var entity = (await _trialEmailNoticeConfigRepository.Where(t => t.Id == addOrEditTrialEmailNoticeConfig.Id, true, true).Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync()).IfNullThrowException();
await _repository.BatchDeleteAsync<TrialEmailBlackUser>(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id);
List<TrialEmailNoticeUser> trialEmailNoticeUsers = new List<TrialEmailNoticeUser>();
@ -1398,31 +1526,51 @@ namespace IRaCIS.Core.Application.Service
foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserTypeList)
{
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = entity.Id });
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = id });
}
foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserTypeList)
{
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = entity.Id });
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = id });
}
await _repository.AddRangeAsync(trialEmailNoticeUsers);
foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList)
{
await _trialEmailBlackUserRepository.AddAsync(new TrialEmailBlackUser() { UserId = userid, TrialEmailNoticeConfigId = id });
}
await _trialEmailNoticeConfigRepository.UpdateFromDTOAsync(addOrEditTrialEmailNoticeConfig);
await _trialEmailNoticeConfigRepository.SaveChangesAsync();
var jobId = $"{addOrEditTrialEmailNoticeConfig.TrialId}_{id}";
if (addOrEditTrialEmailNoticeConfig.IsAutoSend)
{
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, addOrEditTrialEmailNoticeConfig.TrialId, addOrEditTrialEmailNoticeConfig.BusinessScenarioEnum, addOrEditTrialEmailNoticeConfig.EmailCron);
}
else
{
HangfireJobHelper.RemoveCronJob(jobId);
}
return ResponseOutput.Ok();
}
}
private async Task TestEmailConfigAsync(TrialEmailNoticeConfigAddOrEdit config)
{
if (!config.FromEmail.Contains("@") || string.IsNullOrEmpty(config.FromEmail))
{
@ -1449,7 +1597,7 @@ namespace IRaCIS.Core.Application.Service
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidSenderEmailConfig"] + ex.Message);
}
#region 人员还未加入,可以先配置邮件 历史废弃
@ -1522,6 +1670,11 @@ namespace IRaCIS.Core.Application.Service
[HttpDelete("{trialEmailNoticeConfigId:guid}")]
public async Task<IResponseOutput> DeleteTrialEmailNoticeConfig(Guid trialEmailNoticeConfigId)
{
var trialId = await _trialEmailNoticeConfigRepository.Where(t => t.Id == trialEmailNoticeConfigId).Select(t => t.TrialId).FirstOrDefaultAsync();
var jobId = $"{trialId}_{trialEmailNoticeConfigId}";
HangfireJobHelper.RemoveCronJob(jobId);
var success = await _trialEmailNoticeConfigRepository.DeleteFromQueryAsync(t => t.Id == trialEmailNoticeConfigId, true);
return ResponseOutput.Ok();

View File

@ -14,12 +14,13 @@ namespace IRaCIS.Core.Application.Service
var userId = Guid.Empty;
var token = string.Empty;
var isEn_Us = false;
CreateMap<SystemDocument, SystemDocumentView>()
.ForMember(d => d.FileType, u => u.MapFrom(s => s.FileType.Value))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path));
CreateMap<TrialDocument, TrialDocumentView>()
.ForMember(d => d.FileType, u => u.MapFrom(s => s.FileType.MappedValue))
.ForMember(d => d.FileType, u => u.MapFrom(s => isEn_Us ? s.FileType.Value : s.FileType.ValueCN ))
.ForMember(d => d.IsSomeUserSigned, u => u.MapFrom(s => s.TrialDocConfirmedUserList.Any(t=>t.ConfirmTime!=null)))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path ));

View File

@ -1,6 +1,4 @@
using Dicom;
using Dicom.Imaging.Codec;
using EasyCaching.Core;
using EasyCaching.Core;
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Domain.Share;
using System.Text;
@ -8,10 +6,13 @@ using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using FellowOakDicom;
using FellowOakDicom.Imaging.Codec;
namespace IRaCIS.Core.Application.Services
{
public class DicomArchiveService :BaseService, IDicomArchiveService
public class DicomArchiveService : BaseService, IDicomArchiveService
{
private readonly IRepository<DicomStudy> _studyRepository;
private readonly IRepository<DicomSeries> _seriesRepository;
@ -21,7 +22,7 @@ namespace IRaCIS.Core.Application.Services
private readonly IWebHostEnvironment _hostEnvironment;
private static object lockCodeGenerate = new object();
private readonly IDistributedLockProvider _distributedLockProvider;
private List<Guid> _instanceIdList = new List<Guid>();
@ -31,8 +32,9 @@ namespace IRaCIS.Core.Application.Services
IRepository<DicomInstance> instanceRepository,
IWebHostEnvironment hostEnvironment,
IRepository<Dictionary> dictionaryRepository,
IEasyCachingProvider provider)
IEasyCachingProvider provider, IDistributedLockProvider distributedLockProvider)
{
_distributedLockProvider = distributedLockProvider;
_hostEnvironment = hostEnvironment;
_studyRepository = studyRepository;
@ -50,7 +52,7 @@ namespace IRaCIS.Core.Application.Services
return success;
}
public async Task<(Guid StudyId, string StudyCode)> ArchiveDicomStreamAsync(Stream dicomStream,
@ -129,7 +131,7 @@ namespace IRaCIS.Core.Application.Services
DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd);
DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries,out bool isInstanceNeedAdd);
DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries, out bool isInstanceNeedAdd);
dicomSeries.DicomStudy = dicomStudy;
@ -183,7 +185,7 @@ namespace IRaCIS.Core.Application.Services
//正常保存 不做处理
await dicomFile.SaveAsync(physicalPath);
}
else
else
{
//RLELossless 保存
await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(physicalPath); //RLELossless
@ -235,7 +237,7 @@ namespace IRaCIS.Core.Application.Services
{
modalityForEdit = "PET";
}
if(modality== "PT、CT")
if (modality == "PT、CT")
{
modalityForEdit = "PET-CT";
}
@ -282,9 +284,10 @@ namespace IRaCIS.Core.Application.Services
dicomStudy.PatientBirthDate = $"{dicomStudy.PatientBirthDate[0]}{dicomStudy.PatientBirthDate[1]}{dicomStudy.PatientBirthDate[2]}{dicomStudy.PatientBirthDate[3]}-{dicomStudy.PatientBirthDate[4]}{dicomStudy.PatientBirthDate[5]}-{dicomStudy.PatientBirthDate[6]}{dicomStudy.PatientBirthDate[7]}";
}
lock (lockCodeGenerate)
{
var @lock = _distributedLockProvider.CreateLock($"StudyCode");
using (@lock.Acquire())
{
//查询数据库获取最大的Code 没有记录则为0
var dbStudyCodeIntMax = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.Code).DefaultIfEmpty().Max();
@ -298,9 +301,9 @@ namespace IRaCIS.Core.Application.Services
dicomStudy.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy));
_provider.Set<int>($"{addtionalInfo.TrialId}_{StaticData.CacheKey.StudyMaxCode}", dicomStudy.Code, TimeSpan.FromMinutes(30));
}
#region Setting Code old
//var studyCode = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.StudyCode).OrderByDescending(c => c).FirstOrDefault();
@ -468,7 +471,7 @@ namespace IRaCIS.Core.Application.Services
_instanceIdList.Add(instanceId);
}
return dicomInstance;
}

View File

@ -14,16 +14,13 @@ using IRaCIS.Core.Application.MediatR.Handlers;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System.Threading;
using Nito.AsyncEx;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
[ApiExplorerSettings(GroupName = "Image")]
public class StudyService : BaseService, IStudyService
{
private static object lockObj = new object();
private static readonly AsyncLock _mutex = new AsyncLock();
private static readonly AsyncLock _mutex2 = new AsyncLock();
private readonly IEasyCachingProvider _provider;
@ -35,12 +32,12 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IRepository<StudyMonitor> _studyMonitorRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
public StudyService(IEasyCachingProvider provider
, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<DicomInstance> dicomInstanceRepository,
IRepository<DicomSeries> dicomSeriesRepository, IRepository<DicomStudy> dicomstudyRepository, IRepository<Dictionary> dictionaryRepository, IRepository<StudyMonitor> studyMonitorRepository)
IRepository<DicomSeries> dicomSeriesRepository, IRepository<DicomStudy> dicomstudyRepository, IRepository<Dictionary> dictionaryRepository, IRepository<StudyMonitor> studyMonitorRepository, IDistributedLockProvider distributedLockProvider)
{
_provider = provider;
_subjectVisitRepository = subjectVisitRepository;
@ -49,6 +46,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
_dicomstudyRepository = dicomstudyRepository;
_dictionaryRepository = dictionaryRepository;
_studyMonitorRepository = studyMonitorRepository;
_distributedLockProvider = distributedLockProvider;
}
@ -160,7 +158,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
var study = _mapper.Map<DicomStudy>(incommand.Study);
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"StudyCode");
using (await @lock.AcquireAsync())
{
//查询数据库获取最大的Code 没有记录则为0
var dbStudyCodeIntMax = _dicomstudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();
@ -306,11 +306,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
using (await _mutex2.LockAsync())
var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");
using (await @lock2.AcquireAsync())
{
await _dicomInstanceRepository.SaveChangesAsync();
}
}
catch (Exception ex)
@ -826,22 +826,22 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
result.StudyInstanceUid = studyInstanceUid;
var @lock = _distributedLockProvider.CreateLock($"StudyUpload");
if (result.AllowReUpload || result.AllowUpload)
using (@lock.Acquire())
{
lock (lockObj)
if (result.AllowReUpload || result.AllowUpload)
{
_provider.Set($"StudyUid_{trialId}_{studyInstanceUid}", _userInfo.Id, TimeSpan.FromSeconds(30));
}
}
else
{
lock (lockObj)
else
{
_provider.Remove($"StudyUid_{trialId}_{studyInstanceUid}");
}
}
return result;
}

View File

@ -3,7 +3,7 @@ using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Domain.Share;
using Nito.AsyncEx;
using Medallion.Threading;
namespace IRaCIS.Application.Services
{
@ -12,13 +12,13 @@ namespace IRaCIS.Application.Services
{
private readonly IRepository<Site> _siteRepository;
private readonly IRepository<TrialSiteUser> _trialSiteUserRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private readonly AsyncLock _mutex = new AsyncLock();
public SiteService(IRepository<Site> siteRepository, IRepository<TrialSiteUser> trialSiteUserRepository)
public SiteService(IRepository<Site> siteRepository, IRepository<TrialSiteUser> trialSiteUserRepository, IDistributedLockProvider distributedLockProvider)
{
_siteRepository = siteRepository;
this._trialSiteUserRepository = trialSiteUserRepository;
_trialSiteUserRepository = trialSiteUserRepository;
_distributedLockProvider = distributedLockProvider;
}
/// <summary> 分页获取研究中心列表 </summary>
@ -58,7 +58,9 @@ namespace IRaCIS.Application.Services
VerifyMsg = _localizer["Site_DupName"]
};
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"SiteAdd");
using (await @lock.AcquireAsync())
{
if (siteCommand.Id == null)
{

View File

@ -12,7 +12,7 @@ namespace IRaCIS.Core.Application.Contracts
public UserTypeEnum UserTypeEnum { get; set; }
public List<UserTypeGroupInfo> UserTypeGroupList { get; set; } = new List<UserTypeGroupInfo>();
public new List<Guid> UserTypeGroupIdList => UserTypeGroupList.Select(t=>t.DictionaryId).ToList();
public new List<Guid> UserTypeGroupIdList => UserTypeGroupList.Select(t => t.DictionaryId).ToList();
}
@ -22,7 +22,7 @@ namespace IRaCIS.Core.Application.Contracts
public Guid DictionaryId { get; set; }
public string GroupName { get; set; }=string.Empty;
public string GroupName { get; set; } = string.Empty;
public string GroupNameCN { get; set; } = string.Empty;
}
@ -36,7 +36,7 @@ namespace IRaCIS.Core.Application.Contracts
}
public class UserTypeMenuAddOrEdit: UserTypeRoleAddOrEdit
public class UserTypeMenuAddOrEdit : UserTypeRoleAddOrEdit
{
public UserTypeEnum UserTypeEnum { get; set; }
@ -64,6 +64,16 @@ namespace IRaCIS.Core.Application.Contracts
}
public class TrialSelectUser
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public string RealName { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
}
public class TrialUserType
{

View File

@ -12,6 +12,7 @@ using IRaCIS.Core.Infra.Common.Cache;
using Microsoft.Identity.Client;
using static IRaCIS.Core.Domain.Share.StaticData;
using IRaCIS.Core.Application.ViewModel;
using Medallion.Threading;
namespace IRaCIS.Application.Services
{
@ -25,7 +26,7 @@ namespace IRaCIS.Application.Services
private readonly IRepository<TrialUser> _userTrialRepository;
private readonly IRepository<UserLog> _userLogRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private readonly IMemoryCache _cache;
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
@ -40,7 +41,8 @@ namespace IRaCIS.Application.Services
IRepository<TrialUser> userTrialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig,
IRepository<UserLog> userLogRepository
)
,
IDistributedLockProvider distributedLockProvider)
{
_userLogRepository = userLogRepository;
@ -52,6 +54,7 @@ namespace IRaCIS.Application.Services
_doctorRepository = doctorRepository;
_userTrialRepository = userTrialRepository;
_userLogRepository = userLogRepository;
_distributedLockProvider = distributedLockProvider;
}
@ -504,29 +507,32 @@ namespace IRaCIS.Application.Services
var saveItem = _mapper.Map<User>(userAddModel);
saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
var @lock = _distributedLockProvider.CreateLock($"UserAccount");
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User));
if (saveItem.IsZhiZhun)
using (await @lock.AcquireAsync())
{
saveItem.OrganizationName = AppSettings.DefaultInternalOrganizationName;
saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User));
if (saveItem.IsZhiZhun)
{
saveItem.OrganizationName = AppSettings.DefaultInternalOrganizationName;
}
saveItem.Password = MD5Helper.Md5("123456");
await _userRepository.AddAsync(saveItem);
var success = await _userRepository.SaveChangesAsync();
}
saveItem.Password = MD5Helper.Md5("123456");
await _userRepository.AddAsync(saveItem);
var success = await _userRepository.SaveChangesAsync();
await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.BaseUrl, userAddModel.RouteUrl);
return ResponseOutput.Result(success, new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode });
return ResponseOutput.Ok( new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode });
}

View File

@ -5,10 +5,10 @@
//--------------------------------------------------------------------
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Filter;
using Nito.AsyncEx;
using System.ComponentModel.DataAnnotations;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Contracts
{
@ -20,19 +20,19 @@ namespace IRaCIS.Core.Application.Contracts
{
private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
private readonly IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository;
private readonly AsyncLock _mutex = new AsyncLock();
private readonly IDistributedLockProvider _distributedLockProvider;
private readonly QCCommon _qCCommon;
public NoneDicomStudyService(IRepository<NoneDicomStudy> noneDicomStudyRepository,
QCCommon qCCommon,
IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository)
IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository, IDistributedLockProvider distributedLockProvider)
{
_qCCommon = qCCommon;
_noneDicomStudyRepository = noneDicomStudyRepository;
_noneDicomStudyFileRepository = noneDicomStudyFileRepository;
_distributedLockProvider = distributedLockProvider;
}
@ -62,7 +62,9 @@ namespace IRaCIS.Core.Application.Contracts
}
NoneDicomStudy? optEntity = null;
using (await _mutex.LockAsync())
var @lock = _distributedLockProvider.CreateLock($"NoneDicomCode");
using (await @lock.AcquireAsync())
{
if (addOrEditNoneDicomStudy.Id == Guid.Empty || addOrEditNoneDicomStudy.Id == null)
{

View File

@ -10,13 +10,13 @@ using WinSCP;
using Newtonsoft.Json;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using Nito.AsyncEx;
using System.ComponentModel.DataAnnotations;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Application.Service;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Image.QA
{
@ -35,8 +35,7 @@ namespace IRaCIS.Core.Application.Image.QA
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<VisitTask> _visitTaskRepository;
private readonly IVisitTaskHelpeService _IVisitTaskHelpeService;
private readonly AsyncLock _mutex = new AsyncLock();
private readonly IDistributedLockProvider _distributedLockProvider;
public QCOperationService(IRepository<SubjectVisit> subjectVisitRepository,
IRepository<QCChallenge> qcChallengeRepository,
@ -48,7 +47,8 @@ namespace IRaCIS.Core.Application.Image.QA
IRepository<ReadingClinicalData> readingClinicalDataRepository,
IRepository<QCChallengeDialog> qCChallengeDialogrepository,
IRepository<CheckChallengeDialog> checkChallengeDialogrepository,
IVisitTaskHelpeService visitTaskHelpeService
IVisitTaskHelpeService visitTaskHelpeService,
IDistributedLockProvider distributedLockProvider
)
{
_subjectVisitRepository = subjectVisitRepository;
@ -62,6 +62,7 @@ namespace IRaCIS.Core.Application.Image.QA
_trialRepository = trialRepository;
this._visitTaskRepository = visitTaskRepository;
_IVisitTaskHelpeService = visitTaskHelpeService;
_distributedLockProvider = distributedLockProvider;
}
#region QC质疑 以及回复 关闭
@ -108,9 +109,9 @@ namespace IRaCIS.Core.Application.Image.QA
var trialConfig = (await _trialRepository.Where(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }).FirstOrDefaultAsync()).IfNullThrowException();
var @lock = _distributedLockProvider.CreateLock($"QCChallengeCode");
using (await _mutex.LockAsync())
using (await @lock.AcquireAsync())
{
//获取编号
var code = _qcChallengeRepository.Where(t => t.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();

View File

@ -262,7 +262,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public string ImagePath { get; set; } = string.Empty;
public List<ImageInfo> FileList { get; set; } = new List<ImageInfo>();
public List<Domain.Models.OSSImageInfo> FileList { get; set; } = new List<Domain.Models.OSSImageInfo>();
}
@ -310,7 +310,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public List<ImageInfo> FileList { get; set; } = new List<ImageInfo>();
public List<OSSImageInfo> FileList { get; set; } = new List<OSSImageInfo>();
@ -451,7 +451,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public Guid TaskMedicalReviewId { get; set; }
public List<ImageInfo> FileList { get; set; } = new List<ImageInfo>();
public List<OSSImageInfo> FileList { get; set; } = new List<OSSImageInfo>();
/// <summary>
@ -498,7 +498,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public string Questioning { get; set; } = string.Empty;
public List<ImageInfo> FileList { get; set; } = new List<ImageInfo>();
public List<OSSImageInfo> FileList { get; set; } = new List<OSSImageInfo>();
/// <summary>
/// 审核建议

View File

@ -1,51 +0,0 @@
using Microsoft.AspNetCore.JsonPatch.Operations;
using Swashbuckle.AspNetCore.Filters;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary>
/// 实测 标注在服务方法上 没用
/// </summary>
public class JsonPatchUserRequestExample : IExamplesProvider<object>
{
public Operation[] GetExamples()
{
return new[]
{
new Operation
{
op = "replace",
path = "/name",
value = "Gordon"
},
new Operation
{
op = "replace",
path = "/surname",
value = "Freeman"
}
};
}
object IExamplesProvider<object>.GetExamples()
{
return new[]
{
new Operation
{
op = "replace",
path = "/name",
value = "Gordon"
},
new Operation
{
op = "replace",
path = "/surname",
value = "Freeman"
}
};
}
}
}

View File

@ -15,6 +15,7 @@ using MailKit.Security;
using MimeKit;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Filter;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Contracts
{
@ -32,24 +33,25 @@ namespace IRaCIS.Core.Application.Contracts
private readonly IRepository<TrialUser> _trialUserRepository;
private readonly ITokenService _tokenService;
private readonly IMailVerificationService _mailVerificationService;
private readonly IDistributedLockProvider _distributedLockProvider;
public TrialSiteSurveyService(IRepository<TrialSiteSurvey> trialSiteSurveyRepository, IRepository<TrialUser> trialUserRepository, IRepository<TrialSiteUserSurvey> trialSiteUserSurveyRepository,
IRepository<User> userRepository, IRepository<TrialSite> trialSiteRepository,
IRepository<Doctor> doctorRepository,
ITokenService tokenService,
IMailVerificationService mailVerificationService)
IMailVerificationService mailVerificationService, IDistributedLockProvider distributedLockProvider)
{
_trialSiteSurveyRepository = trialSiteSurveyRepository;
_trialSiteUserSurveyRepository = trialSiteUserSurveyRepository;
_userRepository = userRepository;
_trialUserRepository = trialUserRepository;
_trialSiteRepository = trialSiteRepository;
this._doctorRepository = doctorRepository;
_doctorRepository = doctorRepository;
_tokenService = tokenService;
_mailVerificationService = mailVerificationService;
_distributedLockProvider = distributedLockProvider;
}
private object lockObj { get; set; } = new object();
/// <summary>
/// 发送验证码
@ -801,7 +803,9 @@ namespace IRaCIS.Core.Application.Contracts
if (sysUserInfo == null)
{
lock (lockObj)
var @lock = _distributedLockProvider.CreateLock($"UserCode");
using (await @lock.AcquireAsync())
{
var saveItem = _mapper.Map<User>(item);
@ -902,118 +906,7 @@ namespace IRaCIS.Core.Application.Contracts
#region 废弃
//Site 调研邀请
public async Task<IResponseOutput> SendInviteEmail(InviteEmailCommand inviteEmailCommand)
{
var trialInfo = await _repository.FirstOrDefaultAsync<Trial>(t => t.Id == inviteEmailCommand.TrialId);
foreach (var item in inviteEmailCommand.UserList)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com"));
//收件地址
messageToSend.To.Add(new MailboxAddress(String.Empty, item.Email));
//主题
//$"[来自展影IRC] [{trialInfo.ResearchProgramNo}] 邀请信";
messageToSend.Subject = _localizer["TrialSiteSurvey_IRCInvitation", trialInfo.ResearchProgramNo];
var builder = new BodyBuilder();
//找下系统中是否存在该用户类型的 并且邮箱 或者手机的账户
var sysUserInfo = await _userRepository.Where(t => t.UserTypeId == item.UserTypeId && t.EMail == item.Email).Include(t => t.UserTypeRole).FirstOrDefaultAsync();
//int verificationCode = new Random().Next(100000, 1000000);
//var baseApiUrl = baseUrl.Remove(baseUrl.IndexOf("#")) + "api";
if (sysUserInfo == null)
{
lock (lockObj)
{
var saveItem = _mapper.Map<User>(item);
saveItem.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); ;
saveItem.UserName = saveItem.UserCode;
saveItem.UserTypeEnum = _repository.Where<UserType>(t => t.Id == saveItem.UserTypeId).Select(t => t.UserTypeEnum).First();
//saveItem.Password = MD5Helper.Md5(verificationCode.ToString());
_ = _repository.AddAsync(saveItem).Result;
_ = _repository.SaveChangesAsync().Result;
sysUserInfo = saveItem;
}
}
builder.HtmlBody = @$"<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
{sysUserInfo.LastName + "/" + sysUserInfo.FirstName}:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{_localizer["TrialSiteSurvey_IRCInvitationContent", trialInfo.ResearchProgramNo]}
</div>
<a href=' {inviteEmailCommand.RouteUrl + "?Id=" + item.Id + "&IsExternalUser=0"}' style='margin-left:60px;font-size:14px;text-decoration: none;display: inline-block;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;'>
</a>
</div>
</div>
</body>";
messageToSend.Body = builder.ToMessageBody();
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
smtp.MessageSent += (sender, args) =>
{
_ = _trialSiteUserSurveyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new TrialSiteUserSurvey() { IsGenerateSuccess = true, InviteState = TrialSiteUserStateEnum.HasSend, ConfirmTime = null, RejectReason = String.Empty, SystemUserId = sysUserInfo.Id, ExpireTime = DateTime.Now.AddDays(7) }).Result;
};
await smtp.ConnectAsync("smtp.163.com", 465, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH");
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
return ResponseOutput.Ok();
}
#endregion

View File

@ -16,6 +16,7 @@ using Panda.DynamicWebApi.Attributes;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Application.Services;
using IRaCIS.Core.Application.Filter;
using Medallion.Threading;
namespace IRaCIS.Core.Application.Service
{
@ -31,10 +32,11 @@ namespace IRaCIS.Core.Application.Service
private readonly IRepository<TrialSiteUserSurvey> _trialSiteSurveyUserRepository;
private readonly IRepository<TrialSiteUser> _trialSiteUserRepository;
private readonly IMailVerificationService _mailVerificationService;
private readonly IDistributedLockProvider _distributedLockProvider;
public TrialExternalUserService(IRepository<TrialExternalUser> trialExternalUseRepository, IRepository<User> userRepository, IRepository<TrialUser> trialUserRepository,
IRepository<TrialSiteUserSurvey> trialSiteSurveyUserRepository, IRepository<TrialSiteUser> trialSiteUserRepository,
IMailVerificationService mailVerificationService)
IMailVerificationService mailVerificationService, IDistributedLockProvider distributedLockProvider)
{
_trialExternalUseRepository = trialExternalUseRepository;
_userRepository = userRepository;
@ -43,6 +45,7 @@ namespace IRaCIS.Core.Application.Service
_trialSiteUserRepository = trialSiteUserRepository;
_mailVerificationService = mailVerificationService;
_distributedLockProvider = distributedLockProvider;
}
@ -75,121 +78,125 @@ namespace IRaCIS.Core.Application.Service
if (addOrEditTrialExternalUser.Id == null)
{
var existSysUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId);
var @lock = _distributedLockProvider.CreateLock($"UserCode");
if (existSysUser != null)
using (await @lock.AcquireAsync())
{
if (existSysUser.LastName != addOrEditTrialExternalUser.LastName || existSysUser.FirstName != addOrEditTrialExternalUser.FirstName)
var existSysUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId);
if (existSysUser != null)
{
//$"该用户在系统中的用户名为:{existSysUser.LastName + " / " + existSysUser.FirstName} 电话:{existSysUser.Phone},与填写信息存在不一致项, 请将界面信息修改为与系统一致,再进行保存",
return ResponseOutput.NotOk(_localizer["TrialExternalUser_Inconsistency", existSysUser.LastName + " / " + existSysUser.FirstName, existSysUser.Phone], new { existSysUser.LastName, existSysUser.FirstName, existSysUser.Phone, existSysUser.IsZhiZhun, existSysUser.IsTestUser }, ApiResponseCodeEnum.NeedTips);
if (existSysUser.LastName != addOrEditTrialExternalUser.LastName || existSysUser.FirstName != addOrEditTrialExternalUser.FirstName)
{
//$"该用户在系统中的用户名为:{existSysUser.LastName + " / " + existSysUser.FirstName} 电话:{existSysUser.Phone},与填写信息存在不一致项, 请将界面信息修改为与系统一致,再进行保存",
return ResponseOutput.NotOk(_localizer["TrialExternalUser_Inconsistency", existSysUser.LastName + " / " + existSysUser.FirstName, existSysUser.Phone], new { existSysUser.LastName, existSysUser.FirstName, existSysUser.Phone, existSysUser.IsZhiZhun, existSysUser.IsTestUser }, ApiResponseCodeEnum.NeedTips);
}
}
}
//处理 生成账户
//处理 生成账户
if (await _trialExternalUseRepository.AnyAsync(t =>
t.Email == addOrEditTrialExternalUser.Email &&
t.UserTypeId == addOrEditTrialExternalUser.UserTypeId && t.TrialId == addOrEditTrialExternalUser.TrialId))
{
//---系统已经存在与列表中填写的邮箱和用户类型相同的账户,请确认。
return ResponseOutput.NotOk(_localizer["TrialExternalUser_EmailTypeDuplicate"]);
}
if (await _trialExternalUseRepository.AnyAsync(t =>
t.Email == addOrEditTrialExternalUser.Email &&
t.UserTypeId == addOrEditTrialExternalUser.UserTypeId && t.TrialId == addOrEditTrialExternalUser.TrialId))
{
//---系统已经存在与列表中填写的邮箱和用户类型相同的账户,请确认。
return ResponseOutput.NotOk(_localizer["TrialExternalUser_EmailTypeDuplicate"]);
}
var addEntity = _mapper.Map<TrialExternalUser>(addOrEditTrialExternalUser);
var addEntity = _mapper.Map<TrialExternalUser>(addOrEditTrialExternalUser);
await _trialExternalUseRepository.AddAsync(addEntity);
await _trialExternalUseRepository.AddAsync(addEntity);
var existUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId);
var trialType = await _repository.Where<Trial>(t => t.Id == addOrEditTrialExternalUser.TrialId).Select(t => t.TrialType).FirstOrDefaultAsync();
var existUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId);
var trialType = await _repository.Where<Trial>(t => t.Id == addOrEditTrialExternalUser.TrialId).Select(t => t.TrialType).FirstOrDefaultAsync();
if (existUser != null)
{
addEntity.IsSystemUser = true;
addEntity.SystemUserId = existUser.Id;
if (existUser != null)
{
addEntity.IsSystemUser = true;
addEntity.SystemUserId = existUser.Id;
}
else
{
}
else
{
//生成账户 并插入
//生成账户 并插入
var generateUser = _mapper.Map<User>(addOrEditTrialExternalUser);
var generateUser = _mapper.Map<User>(addOrEditTrialExternalUser);
if (trialType == TrialType.NoneOfficial)
{
generateUser.IsTestUser = true;
}
// 外部人员生成账号 都是外部的
generateUser.IsZhiZhun = false;
generateUser.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;
generateUser.UserCode = AppSettings.GetCodeStr(generateUser.Code, nameof(User));
generateUser.UserName = generateUser.UserCode;
generateUser.UserTypeEnum = _repository.Where<UserType>(t => t.Id == generateUser.UserTypeId).Select(t => t.UserTypeEnum).First();
generateUser.Password = MD5Helper.Md5("123456");
generateUser.Status = UserStateEnum.Disable;
var newAddUser = await _repository.AddAsync(generateUser);
addEntity.IsSystemUser = false;
addEntity.SystemUserId = newAddUser.Id;
existUser = newAddUser;
}
#region 验证用户 能否加入
if (trialType == TrialType.OfficialTrial || trialType == TrialType.Training)
{
if (existUser.IsTestUser)
{
//---正式类型 、培训类型的项目 不允许加入测试用户
throw new BusinessValidationFailedException(_localizer["TrialExternalUser_TestUserNotAllowed"]);
}
}
if (trialType == TrialType.NoneOfficial)
{
generateUser.IsTestUser = true;
if (existUser.IsTestUser == false)
{
//---测试项目 不允许加入正式用户
throw new BusinessValidationFailedException(_localizer["TrialExternalUser_FormalUserNotAllowed"]);
}
}
// 外部人员生成账号 都是外部的
generateUser.IsZhiZhun = false;
generateUser.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;
#endregion
generateUser.UserCode = AppSettings.GetCodeStr(generateUser.Code, nameof(User));
generateUser.UserName = generateUser.UserCode;
generateUser.UserTypeEnum = _repository.Where<UserType>(t => t.Id == generateUser.UserTypeId).Select(t => t.UserTypeEnum).First();
generateUser.Password = MD5Helper.Md5("123456");
generateUser.Status = UserStateEnum.Disable;
var newAddUser = await _repository.AddAsync(generateUser);
await _trialExternalUseRepository.SaveChangesAsync();
addEntity.IsSystemUser = false;
addEntity.SystemUserId = newAddUser.Id;
existUser = newAddUser;
}
#region 验证用户 能否加入
if (trialType == TrialType.OfficialTrial || trialType == TrialType.Training)
{
if (existUser.IsTestUser)
//添加的时候就发邮件 现在省略
if (addOrEditTrialExternalUser.IsSendEmail)
{
//---正式类型 、培训类型的项目 不允许加入测试用户
throw new BusinessValidationFailedException(_localizer["TrialExternalUser_TestUserNotAllowed"]);
}
}
if (trialType == TrialType.NoneOfficial)
{
if (existUser.IsTestUser == false )
{
//---测试项目 不允许加入正式用户
throw new BusinessValidationFailedException(_localizer["TrialExternalUser_FormalUserNotAllowed"]);
}
}
#endregion
await _trialExternalUseRepository.SaveChangesAsync();
//添加的时候就发邮件 现在省略
if (addOrEditTrialExternalUser.IsSendEmail)
{
await SendExternalUserJoinEmail(new TrialExternalUserSendEmail()
{
BaseUrl = addOrEditTrialExternalUser.BaseUrl,
RouteUrl = addOrEditTrialExternalUser.RouteUrl,
TrialId = addOrEditTrialExternalUser.TrialId,
SendUsers = new List<UserEmail>()
await SendExternalUserJoinEmail(new TrialExternalUserSendEmail()
{
BaseUrl = addOrEditTrialExternalUser.BaseUrl,
RouteUrl = addOrEditTrialExternalUser.RouteUrl,
TrialId = addOrEditTrialExternalUser.TrialId,
SendUsers = new List<UserEmail>()
{
new UserEmail()
{
@ -199,12 +206,13 @@ namespace IRaCIS.Core.Application.Service
SystemUserId=addEntity.SystemUserId
}
}
});
});
}
return ResponseOutput.Ok(addEntity.Id.ToString());
}
return ResponseOutput.Ok(addEntity.Id.ToString());
}
else
{

View File

@ -92,7 +92,7 @@ namespace IRaCIS.Application.Services
.WhereIf(multiCriteriaSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Criterion) == multiCriteriaSelectCount)
.WhereIf(multiReviewTypeSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.ReviewType) == multiReviewTypeSelectCount)
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false)
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id });
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id , isEn_Us= _userInfo.IsEn_Us });
return await query.ToPagedListAsync(searchParam.PageIndex, searchParam.PageSize, string.IsNullOrWhiteSpace(searchParam.SortField) ? "CreateTime" : searchParam.SortField, searchParam.Asc);
@ -118,7 +118,7 @@ namespace IRaCIS.Application.Services
[HttpGet("{projectId:guid}")]
public async Task<TrialDetailDTO> GetTrialInfoAndLockState(Guid projectId)
{
return (await _trialRepository.Where(o => o.Id == projectId).IgnoreQueryFilters().ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
return (await _trialRepository.Where(o => o.Id == projectId).IgnoreQueryFilters().ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new {isEn_Us = _userInfo.IsEn_Us }).FirstOrDefaultAsync()).IfNullThrowException();
}
@ -609,7 +609,7 @@ namespace IRaCIS.Application.Services
.WhereIf(param.Status == 8, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.InviteIntoGroup))
.WhereIf(param.Status == 10, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.DoctorReading))
.WhereIf(param.Status == 14, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.Finished))
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id });
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id, isEn_Us = _userInfo.IsEn_Us });
return await query.ToPagedListAsync(param.PageIndex, param.PageSize, string.IsNullOrWhiteSpace(param.SortField) ? "CreateTime" : param.SortField, param.Asc);
@ -644,7 +644,7 @@ namespace IRaCIS.Application.Services
.WhereIf(!string.IsNullOrEmpty(searchModel.Code), o => o.TrialCode.Contains(searchModel.Code))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.Indication), o => o.Indication.Contains(searchModel.Indication))
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id))
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id });
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id ,isEn_Us = _userInfo.IsEn_Us });
return await query.ToPagedListAsync(searchModel.PageIndex, searchModel.PageSize, string.IsNullOrWhiteSpace(searchModel.SortField) ? "CreateTime" : searchModel.SortField, searchModel.Asc);

View File

@ -65,16 +65,17 @@ namespace IRaCIS.Core.Application.Service
var userId = Guid.Empty;
var userTypeEnumInt = 0;
var isEn_Us = false;
CreateMap<Trial, TrialDetailDTO>()
.ForMember(x=>x.CriterionList,y=>y.MapFrom(z=>z.ReadingQuestionCriterionTrialList.Where(n=>n.IsConfirm).Select(m=>m.CriterionName)))
.ForMember(d => d.DictionaryList, u => u.MapFrom(s => s.TrialDicList.Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)))
//.ForMember(d => d.Code, u => u.MapFrom(s => s.TrialCode))
.ForMember(d => d.Sponsor, u => u.MapFrom(s => s.Sponsor.SponsorName))
.ForMember(d => d.Phase, u => u.MapFrom(s => s.Phase.MappedValue))
.ForMember(d => d.Phase, u => u.MapFrom(s => isEn_Us? s.Phase.Value: s.Phase.ValueCN))
//.ForMember(d => d.DeclarationType, u => u.MapFrom(s => s.DeclarationType.MappedValue))
.ForMember(d => d.IndicationType, u => u.MapFrom(s => s.IndicationType.MappedValue))
.ForMember(d => d.IndicationType, u => u.MapFrom(s => isEn_Us ? s.IndicationType.Value:s.IndicationType.ValueCN))
.ForMember(d => d.CRO, u => u.MapFrom(s => s.CRO.CROName))
.ForMember(d => d.ReviewMode, u => u.MapFrom(s => s.ReviewMode.MappedValue))
.ForMember(d => d.ReviewMode, u => u.MapFrom(s => isEn_Us ? s.ReviewMode.Value:s.ReviewMode.ValueCN))
//.ForMember(d => d.ReviewType, u => u.MapFrom(s => s.ReviewType.Value))
.ForMember(d => d.IsLocked, u => u.MapFrom(s => s.WorkloadList.Any(u => u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm)))
//.ForMember(d => d.SiteCount, u => u.MapFrom(s => userTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator ? s.TrialSiteUserList.Count(k => k.UserId == userId) : s.TrialSiteList.Count()))
@ -111,7 +112,6 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.HospitalName, u => u.MapFrom(s => s.Hospital.HospitalName));
//trial site 选择列表 subjectVisit pannel 模式添加的时候
var isEn_Us = false;
CreateMap<Site, TrialSiteScreeningDTO>()
.ForMember(d => d.IsSelect, u => u.MapFrom(s => s.TrialSiteList.Any(k => k.TrialId == trialId)))

View File

@ -3,13 +3,17 @@ using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using System.Linq.Expressions;
using System.Reflection.Metadata;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@ -20,6 +24,8 @@ namespace IRaCIS.Application.Services
[ApiExplorerSettings(GroupName = "Institution")]
public class TestService : BaseService
{
public static int IntValue = 100;
private readonly IRepository<Dictionary> _dicRepository;
private readonly IRepository<Trial> _trialRepository;
@ -30,10 +36,13 @@ namespace IRaCIS.Application.Services
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _basicConfig;
private readonly IRepository<VisitTask> _visitTaskRepositoryy;
private readonly IDistributedLockProvider _distributedLockProvider;
public TestService(IRepository<Dictionary> dicRepository, IRepository<Trial> trialRepository/*, IDistributedCache cache*/
private readonly ILogger<TestService> _logger;
, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig, IOptionsMonitor<ServiceVerifyConfigOption> basicConfig, IRepository<VisitTask> visitTaskRepository)
public TestService(IRepository<Dictionary> dicRepository, IRepository<Trial> trialRepository,ILogger<TestService> logger
, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig, IOptionsMonitor<ServiceVerifyConfigOption> basicConfig, IRepository<VisitTask> visitTaskRepository, IDistributedLockProvider distributedLockProvider)
{
_visitTaskRepositoryy = visitTaskRepository;
@ -42,11 +51,35 @@ namespace IRaCIS.Application.Services
_dicRepository = dicRepository;
_trialRepository = trialRepository;
_distributedLockProvider= distributedLockProvider;
_logger= logger;
//_cache = cache;
}
[AllowAnonymous]
public async Task<IResponseOutput> TestDistributedLock( )
{
Console.WriteLine($"我进来了当前值是:" + IntValue);
_logger.LogWarning($"我进来了当前值是:" + IntValue);
var @lock = _distributedLockProvider.CreateLock($"UserAccount");
using (await @lock.AcquireAsync())
{
await Task.Delay(4);
IntValue--;
_logger.LogWarning( IntValue.ToString());
Console.WriteLine(IntValue);
}
return ResponseOutput.Ok(IntValue);
}
[AllowAnonymous]
public async Task<IResponseOutput> InternationazitionInit()

View File

@ -34,7 +34,7 @@ namespace IRaCIS.Core.Domain.Share
}
public enum CommonDocumentBusinessScenario
public enum EmailBusinessScenario
{
EnrollConfirmed = 1,
@ -44,6 +44,12 @@ namespace IRaCIS.Core.Domain.Share
Trial=3,
Reviewer=4,
QCTask = 5,
QCQuestion = 6,
ImageQuestion = 7
}

View File

@ -178,7 +178,7 @@ namespace IRaCIS.Core.Domain.Models
/// 文件
/// </summary>
[NotMapped]
public List<ImageInfo> FileList
public List<OSSImageInfo> FileList
{
get
{
@ -186,13 +186,13 @@ namespace IRaCIS.Core.Domain.Models
try
{
var result= JsonConvert.DeserializeObject<List<ImageInfo>>(this.ImagePath);
return result==null?new List<ImageInfo>() : result;
var result= JsonConvert.DeserializeObject<List<OSSImageInfo>>(this.ImagePath);
return result==null?new List<OSSImageInfo>() : result;
}
catch (Exception)
{
return new List<ImageInfo>();
return new List<OSSImageInfo>();
}
}
@ -210,7 +210,7 @@ namespace IRaCIS.Core.Domain.Models
#region 文件对象
public class ImageInfo
public class OSSImageInfo
{
public string FileName { get; set; }

View File

@ -72,7 +72,7 @@ namespace IRaCIS.Core.Domain.Models
public CriterionType? CriterionTypeEnum { get; set; }
public CommonDocumentFileType FileTypeEnum { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
//[Required]

View File

@ -59,9 +59,6 @@ namespace IRaCIS.Core.Domain.Models
public List<Dictionary> ChildList { get; set; } = new List<Dictionary>();
[NotMapped]
public string MappedValue { get; set; }
[Projectable]
public string TranslateValue( string value, string valueCN,bool isCN) => isCN?valueCN:value;

View File

@ -16,11 +16,59 @@ namespace IRaCIS.Core.Domain.Models
///EmailNoticeConfig
///</summary>
[Table("EmailNoticeConfig")]
public class EmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd,ISoftDelete
public class EmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd, ISoftDelete
{
[JsonIgnore]
public List<TrialEmailNoticeConfig> TrialEmailNoticeConfigList { get; set; }
[JsonIgnore]
public List<EmailNoticeUserType> EmailNoticeUserTypeList { get; set; } = new List<EmailNoticeUserType>();
public string Code { get; set; } = String.Empty;
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
/// <summary> 标准类型 /// </summary>
public CriterionType? CriterionTypeEnum { get; set; }
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; } = string.Empty;
public string AttachNameCN { get; set; } = string.Empty;
/// <summary>
/// 是否区分标准
@ -34,10 +82,6 @@ namespace IRaCIS.Core.Domain.Models
[Required]
public bool IsReturnRequired { get; set; }
[Required]
public bool IsUrgent { get; set; }
public bool IsAutoSend { get; set; }
public bool IsEnable { get; set; }
@ -61,14 +105,21 @@ namespace IRaCIS.Core.Domain.Models
public Guid? DeleteUserId { get; set; }
}
[Table("EmailNoticeUserType")]
public class EmailNoticeUserType : Entity
{
[JsonIgnore]
public EmailNoticeConfig EmailNoticeConfig { get; set; }
public Guid EmailNoticeConfigId { get; set; }
public UserTypeEnum UserType { get; set; }
public EmailUserType EmailUserType { get; set; }
}
}

View File

@ -12,93 +12,138 @@ using System.Linq;
namespace IRaCIS.Core.Domain.Models
{
///<summary>
///TrialEmailNoticeConfig
///</summary>
[Table("TrialEmailNoticeConfig")]
public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd
{
///<summary>
///TrialEmailNoticeConfig
///</summary>
[Table("TrialEmailNoticeConfig")]
public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd, ISoftDelete
{
[JsonIgnore]
[Required]
public Guid TrialId { get; set; }
public string SMTPServerAddress { get; set; } = string.Empty;
public int SMTPServerPort { get; set; }
[Required]
public string AuthorizationCode { get; set; } = string.Empty;
public string FromName { get; set; } = string.Empty;
public List<TrialEmailNoticeUser> TrialEmailNoticeUserList { get; set; } = new List<TrialEmailNoticeUser>();
//[Required]
//public string ReceiveEmailsStr { get; set; } = string.Empty;
//public string CopyEmailsStr { get; set; } = string.Empty;
//[NotMapped]
//public List<string> ReceiveEmailList => ReceiveEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t => !string.IsNullOrEmpty(t)).Select(t=>t.Trim()).ToList();
//[NotMapped]
//public List<string> CopyEmailList => CopyEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t=> !string.IsNullOrEmpty(t)).Select(t => t.Trim()).ToList();
public string FromEmail { get; set; } = string.Empty;
[Required]
public bool IsUrgent { get; set; }
[Required]
public string Code { get; set; } = string.Empty;
[Required]
public bool IsReturnRequired { get; set; }
[Required]
public bool IsAutoSend { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
public Guid? TrialReadingCriterionId { get; set; }
[ForeignKey("TrialReadingCriterionId")]
[JsonIgnore]
public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; }
public Trial Trial { get; set; }
[Required]
public string FilePath { get; set; } = string.Empty;
[Required]
public string FileName { get; set; } = string.Empty;
[Required]
public Guid CreateUserId { get; set; }
[Required]
public DateTime CreateTime { get; set; }
[Required]
public Guid UpdateUserId { get; set; }
[Required]
public DateTime UpdateTime { get; set; }
public Guid TrialId { get; set; }
}
public string SMTPServerAddress { get; set; } = string.Empty;
}
public int SMTPServerPort { get; set; }
[Required]
public string AuthorizationCode { get; set; } = string.Empty;
public string FromName { get; set; } = string.Empty;
public string FromEmail { get; set; } = string.Empty;
[JsonIgnore]
public List<TrialEmailNoticeUser> TrialEmailNoticeUserList { get; set; } = new List<TrialEmailNoticeUser>();
public List<TrialEmailBlackUser> TrialEmailBlackUserList { get; set; } = new List<TrialEmailBlackUser>();
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; }
public string AttachNameCN { get; set; }
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
[JsonIgnore]
public EmailNoticeConfig SysEmailNoticeConfig { get; set; }
public Guid? SysEmailNoticeConfigId { get; set; }
[Required]
public string Code { get; set; } = string.Empty;
[Required]
public bool IsReturnRequired { get; set; }
[Required]
public bool IsAutoSend { get; set; }
public bool IsEnable { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
public Guid? TrialReadingCriterionId { get; set; }
[ForeignKey("TrialReadingCriterionId")]
[JsonIgnore]
public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; }
[Required]
public Guid CreateUserId { get; set; }
[Required]
public DateTime CreateTime { get; set; }
[Required]
public Guid UpdateUserId { get; set; }
[Required]
public DateTime UpdateTime { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletedTime { get; set; }
public Guid? DeleteUserId { get; set; }
}
public class TrialEmailBlackUser : Entity
{
[JsonIgnore]
public TrialEmailNoticeConfig TrialEmailNoticeConfig { get; set; }
[JsonIgnore]
public User User { get; set; }
public Guid TrialEmailNoticeConfigId { get; set; }
public Guid UserId { get; set; }
}
}

View File

@ -9,11 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EntityFrameworkCore.Projectables" Version="2.3.0" />
<PackageReference Include="EntityFrameworkCore.Projectables.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.10" />
<PackageReference Include="NewId" Version="3.0.3" />
<PackageReference Include="EntityFrameworkCore.Projectables.Abstractions" Version="3.0.4" />
</ItemGroup>
<ItemGroup>

View File

@ -113,7 +113,7 @@ namespace IRaCIS.Core.Domain.Models
/// 文件
/// </summary>
[NotMapped]
public List<ImageInfo> FileList
public List<OSSImageInfo> FileList
{
get
{
@ -121,13 +121,13 @@ namespace IRaCIS.Core.Domain.Models
try
{
var result = JsonConvert.DeserializeObject<List<ImageInfo>>(this.ImagePath);
return result == null ? new List<ImageInfo>() : result;
var result = JsonConvert.DeserializeObject<List<OSSImageInfo>>(this.ImagePath);
return result == null ? new List<OSSImageInfo>() : result;
}
catch (Exception)
{
return new List<ImageInfo>();
return new List<OSSImageInfo>();
}
}

View File

@ -383,7 +383,7 @@ namespace IRaCIS.Core.Domain.Models
/// <summary>
/// SMTP端口
/// </summary>
public int? EmailSMTPServerPort { get; set; }
public int EmailSMTPServerPort { get; set; }
/// <summary>
/// 是否配置过邮箱

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using IRaCIS.Core.Domain.Share;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace IRaCIS.Core.Domain.Models
{

View File

@ -34,7 +34,9 @@ namespace IRaCIS.Core.Domain.Share
public string FromName { get; set; }
public string AuthorizationCode { get; set; }
public string AuthorizationCode { get; set; }
public string SiteUrl { get; set; }
}

View File

@ -78,7 +78,7 @@ public static class StaticData
public static readonly string Resources = "Resources";
public static readonly string IRaCISDataFolder = "IRaCISData";
public static readonly string OtherDataFolder = "OtherData";
public static readonly string TrialDataFolder = "TrialData";
public static readonly string SystemDataFolder = "SystemData";
@ -87,6 +87,11 @@ public static class StaticData
public static readonly string SignDocumentFolder = "SignDocument";
public static readonly string DataTemplate = "DataTemplate";
public static readonly string EmailTemplate = "EmailTemplate";
public static readonly string CommonFile = "CommonFile";
public static readonly string TempFile = "TempFile";
public static readonly string NoticeAttachment = "NoticeAttachment";

View File

@ -123,14 +123,14 @@ namespace IRaCIS.Core.Infra.EFCore
modelBuilder.Entity<Dictionary>().HasMany(t => t.ChildList).WithOne(t => t.Parent);
modelBuilder.Entity<SubjectUser>().HasMany(t => t.EarlierSubjectUserList).WithOne(t => t.OrignalSubjectUser);
if (_userInfo.IsEn_Us)
{
modelBuilder.Entity<Dictionary>().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.Value));
}
else
{
modelBuilder.Entity<Dictionary>().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.ValueCN));
}
//if (_userInfo.IsEn_Us)
//{
// modelBuilder.Entity<Dictionary>().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.Value));
//}
//else
//{
// modelBuilder.Entity<Dictionary>().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.ValueCN));
//}
//遍历实体模型手动配置
@ -513,7 +513,8 @@ namespace IRaCIS.Core.Infra.EFCore
public virtual DbSet<UserLog> UserLog { get; set; }
public virtual DbSet<EmailNoticeUserType> EmailNoticeUserType { get; set; }
public virtual DbSet<TrialEmailBlackUser> TrialEmailBlackUser { get; set; }
#region 废弃

View File

@ -1,27 +0,0 @@
using IRaCIS.Core.Domain.Models;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Infra.EFCore.EntityConfigration
{
//public class ClinicalFromConfigration : IEntityTypeConfiguration<ClinicalForm>
//{
// public void Configure(EntityTypeBuilder<ClinicalForm> builder)
// {
// builder
// .HasOne(s => s.ReadingClinicalData)
// .WithMany(c => c.ClinicalFormList)
// .HasForeignKey(s => new { s.SubjectId, s.ReadingId })
// .HasPrincipalKey(c => new { c.SubjectId, c.ReadingId });
// }
//}
}

View File

@ -26,31 +26,17 @@ namespace IRaCIS.Core.Infra.EFCore.EntityConfigration
}
//public class DoctorTaskConfigration : IEntityTypeConfiguration<VisitTask>
//{
// public void Configure(EntityTypeBuilder<VisitTask> builder)
// {
// builder
// .HasOne(dd => dd.DoctorUser)
// .WithMany(p => p.VisitTaskList)
// .HasForeignKey(dd => dd.DoctorUserId);
// }
//}
public class DictionaryConfigration : IEntityTypeConfiguration<Dictionary>
{
public void Configure(EntityTypeBuilder<Dictionary> builder)
{
builder.Property(e => e.MappedValue).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
builder.Property(e => e.MappedValue).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
//builder.Property(e => e.MappedValue).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
// builder.Property(e => e.MappedValue).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
}
}

View File

@ -17,13 +17,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="EFCore.BulkExtensions" Version="6.5.6" />
<PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="6.0.3.1" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.1" />
<PackageReference Include="EFCore.BulkExtensions" Version="7.1.6" />
<PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="6.0.3.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.12" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="NewId" Version="4.0.1" />
</ItemGroup>
</Project>

View File

@ -1,158 +0,0 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace IRaCIS.Core.Infrastructure.Extention
{
public static class HttpContextExtension
{
public static T GetService<T>(this HttpContext context) where T : class
{
return context.RequestServices.GetService(typeof(T)) as T;
}
public static string GetUserIp(this HttpContext context)
{
string realIP = null;
string forwarded = null;
string remoteIpAddress = context.Connection.RemoteIpAddress.ToString();
if (context.Request.Headers.ContainsKey("X-Real-IP"))
{
realIP = context.Request.Headers["X-Real-IP"].ToString();
if (realIP != remoteIpAddress)
{
remoteIpAddress = realIP;
}
}
if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
{
forwarded = context.Request.Headers["X-Forwarded-For"].ToString();
if (forwarded != remoteIpAddress)
{
remoteIpAddress = forwarded;
}
}
return remoteIpAddress;
}
/// <summary>
/// 获取Request值
/// </summary>
/// <param name="context"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static string Request(this HttpContext context, string parameter)
{
try
{
if (context == null)
return null;
if (context.Request.Method == "POST")
return context.Request.Form[parameter].ToString();
else
return context.Request.Query[parameter].ToString();
}
catch (System.Exception ex)
{
Console.Write(ex.Message + ex.InnerException);
return context.RequestString(parameter);
}
}
public static T Request<T>(this HttpContext context, string parameter) where T : class
{
return context.RequestString(parameter)?.DeserializeObject<T>();
}
public static string RequestString(this HttpContext context, string parameter)
{
string requestParam = context.GetRequestParameters();
if (string.IsNullOrEmpty(requestParam)) return null;
Dictionary<string, object> keyValues = requestParam.DeserializeObject<Dictionary<string, object>>();
if (keyValues == null || keyValues.Count == 0) return null;
if (keyValues.TryGetValue(parameter, out object value))
{
if (value == null) return null;
if (value.GetType() == typeof(string))
{
return value?.ToString();
}
return value.Serialize();
}
return null;
}
/// <summary>
/// 是否为ajax请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool IsAjaxRequest(this HttpContext context)
{
return context.Request("X-Requested-With") == "XMLHttpRequest"
|| (context.Request.Headers != null
&& context.Request.Headers["X-Requested-With"] == "XMLHttpRequest");
}
public static UserAgent GetAgentType(this HttpContext context)
{
string agent = context.Request.Headers["User-Agent"].ToString().ToLower();
if (agent.Contains("ios") || agent.Contains("ipod") || agent.Contains("ipad"))
{
return UserAgent.IOS;
}
if (agent.Contains("windows"))
{
return UserAgent.Windows;
}
return UserAgent.Android;
}
/// <summary>
/// 获取请求的参数
/// net core 2.0已增加回读方法 context.Request.EnableRewind();
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string GetRequestParameters(this HttpContext context)
{
if (context.Request.Body == null || !context.Request.Body.CanRead || !context.Request.Body.CanSeek)
return null;
if (context.Request.Body.Length == 0)
return null;
if (context.Request.Body.Position > 0)
context.Request.Body.Position = 0;
string prarameters = null;
var bodyStream = context.Request.Body;
using (var buffer = new MemoryStream())
{
bodyStream.CopyToAsync(buffer);
buffer.Position = 0L;
bodyStream.Position = 0L;
using (var reader = new StreamReader(buffer, Encoding.UTF8))
{
buffer.Seek(0, SeekOrigin.Begin);
prarameters = reader.ReadToEnd();
}
}
return prarameters;
}
}
public enum UserAgent
{
IOS = 0,
Android = 1,
Windows = 2,
Linux
}
}

View File

@ -1,43 +0,0 @@
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
namespace IRaCIS.Core.Infrastructure
{
public class IPHelper
{
/// <summary>
/// 是否为ip
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool IsIP(string ip)
{
return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
}
public static string GetIP(HttpRequest request)
{
if (request == null)
{
return "";
}
string ip = request.Headers["X-Real-IP"].FirstOrDefault();
if (string.IsNullOrEmpty(ip))
{
ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
}
if (string.IsNullOrEmpty(ip))
{
ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString();
}
if (string.IsNullOrEmpty(ip) || !IsIP(ip))
{
ip = "127.0.0.1";
}
return ip;
}
}
}

View File

@ -9,13 +9,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.0" />
<PackageReference Include="CSRedisCore" Version="3.8.669" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10" />
<PackageReference Include="SharpCompress" Version="0.32.2" />
<PackageReference Include="SharpZipLib" Version="1.4.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.20" />
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="CSRedisCore" Version="3.8.671" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.12" />
<PackageReference Include="SharpCompress" Version="0.34.1" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.5" />
</ItemGroup>

View File

@ -169,7 +169,7 @@ namespace IRaCIS.Core.Infrastructure.Extention
public static IResponseOutput<string> DBNotExistIfNUll(object businessObject)
{
return new ResponseOutput<string>().NotOk("The business object{businessObject.GetType().Name} does not exist in the database, or was deleted by someone else, or an incorrect parameter query caused");
return new ResponseOutput<string>().NotOk($"The business object{businessObject.GetType().Name} does not exist in the database, or was deleted by someone else, or an incorrect parameter query caused");
}

View File

@ -15,7 +15,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="coverlet.collector" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>