Refactored Case Status automation and shared Case functionality:
* Extracted Case Notification and HTTP Web Hook functionality into a shared Jube.Case library for use across Jube.App and Jube.Engine. * Added the new Jube.Case library to the Jube.App Docker Compose configuration. * Cleaned up classes moved to Jube.Case, converting to static classes or methods where appropriate. * Implemented Case Status automation within the asynchronous background Case Creation process, including upward status classification.
This commit is contained in:
@@ -16,6 +16,7 @@ namespace Jube.App.Controllers.Helper
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Case;
|
||||
using Code;
|
||||
using Data.Context;
|
||||
using Data.Repository;
|
||||
@@ -115,10 +116,9 @@ namespace Jube.App.Controllers.Helper
|
||||
return Ok(model);
|
||||
}
|
||||
|
||||
var sendHttpEndpoint = new SendHttpEndpoint();
|
||||
if (caseWorkflowMacro.HttpEndpointTypeId != null)
|
||||
{
|
||||
await sendHttpEndpoint.SendAsync(caseWorkflowMacro.HttpEndpoint,
|
||||
await SendHttpEndpoint.SendAsync(caseWorkflowMacro.HttpEndpoint,
|
||||
caseWorkflowMacro.HttpEndpointTypeId.Value
|
||||
, values);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Jube.App.Controllers.Repository
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Case;
|
||||
using Code;
|
||||
using Data.Context;
|
||||
using Data.Poco;
|
||||
@@ -412,10 +413,9 @@ namespace Jube.App.Controllers.Repository
|
||||
|
||||
if (caseWorkflowStatus.EnableHttpEndpoint == 1)
|
||||
{
|
||||
var sendHttpEndpoint = new SendHttpEndpoint();
|
||||
if (caseWorkflowStatus.HttpEndpointTypeId != null)
|
||||
{
|
||||
await sendHttpEndpoint.SendAsync(caseWorkflowStatus.HttpEndpoint,
|
||||
await SendHttpEndpoint.SendAsync(caseWorkflowStatus.HttpEndpoint,
|
||||
caseWorkflowStatus.HttpEndpointTypeId.Value
|
||||
, values);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Jube.App.Controllers.Repository
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Case;
|
||||
using Code;
|
||||
using Data.Context;
|
||||
using Data.Poco;
|
||||
@@ -141,10 +142,9 @@ namespace Jube.App.Controllers.Repository
|
||||
return Ok(await repository.InsertAsync(mapper.Map<CaseNote>(model), token));
|
||||
}
|
||||
|
||||
var sendHttpEndpoint = new SendHttpEndpoint();
|
||||
if (caseWorkflowAction.HttpEndpointTypeId != null)
|
||||
{
|
||||
await sendHttpEndpoint.SendAsync(caseWorkflowAction.HttpEndpoint,
|
||||
await SendHttpEndpoint.SendAsync(caseWorkflowAction.HttpEndpoint,
|
||||
caseWorkflowAction.HttpEndpointTypeId.Value
|
||||
, values);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Jube.App.Controllers.Repository
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Case;
|
||||
using Code;
|
||||
using Data.Context;
|
||||
using Data.Poco;
|
||||
@@ -175,10 +176,9 @@ namespace Jube.App.Controllers.Repository
|
||||
return Ok(entry);
|
||||
}
|
||||
|
||||
var sendHttpEndpoint = new SendHttpEndpoint();
|
||||
if (caseWorkflowForm.HttpEndpointTypeId != null)
|
||||
{
|
||||
await sendHttpEndpoint.SendAsync(caseWorkflowForm.HttpEndpoint,
|
||||
await SendHttpEndpoint.SendAsync(caseWorkflowForm.HttpEndpoint,
|
||||
caseWorkflowForm.HttpEndpointTypeId.Value
|
||||
, values);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ COPY ["Accord.Genetic/Accord.Genetic.csproj", "Accord.Genetic/"]
|
||||
COPY ["Accord.MachineLearning/Accord.MachineLearning.csproj", "Accord.MachineLearning/"]
|
||||
COPY ["Accord.Neuro/Accord.Neuro.csproj", "Accord.Neuro/"]
|
||||
COPY ["Jube.Parser/Jube.Parser.csproj", "Jube.Parser/"]
|
||||
COPY ["Jube.Case/Jube.Case.csproj", "Jube.Case/"]
|
||||
COPY ["Jube.Migrations/Jube.Migrations.csproj", "Jube.Migrations/"]
|
||||
COPY ["Jube.Service/Jube.Service.csproj", "Jube.Service/"]
|
||||
COPY ["Jube.Validations/Jube.Validations.csproj", "Jube.Validations/"]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jube.DynamicEnvironment\Jube.DynamicEnvironment.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net">
|
||||
<HintPath>..\..\..\.nuget\packages\log4net\2.0.14\lib\netstandard2.0\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -11,37 +11,23 @@
|
||||
* see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Jube.App.Code
|
||||
namespace Jube.Case
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicEnvironment;
|
||||
using log4net;
|
||||
|
||||
public class Notification
|
||||
public class Notification(ILog log, DynamicEnvironment dynamicEnvironment)
|
||||
{
|
||||
private readonly DynamicEnvironment dynamicEnvironment;
|
||||
private readonly ILog log;
|
||||
|
||||
public Notification(ILog log, DynamicEnvironment dynamicEnvironment)
|
||||
{
|
||||
this.dynamicEnvironment = dynamicEnvironment;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public async Task SendAsync(int notificationType, string notificationDestination, string notificationSubject,
|
||||
string notificationBody, Dictionary<string, string> values, CancellationToken token = default
|
||||
)
|
||||
{
|
||||
var notificationTokenization = new Tokenisation();
|
||||
|
||||
var replacedNotificationDestination = notificationDestination;
|
||||
if (!String.IsNullOrEmpty(replacedNotificationDestination))
|
||||
{
|
||||
var notificationDestinationTokens =
|
||||
notificationTokenization.ReturnTokens(replacedNotificationDestination);
|
||||
Tokenisation.ReturnTokens(replacedNotificationDestination);
|
||||
|
||||
foreach (var notificationToken in notificationDestinationTokens)
|
||||
{
|
||||
if (!values.TryGetValue(notificationToken, out var value))
|
||||
@@ -59,7 +45,7 @@ namespace Jube.App.Code
|
||||
var replacedNotificationSubject = notificationSubject;
|
||||
if (!String.IsNullOrEmpty(replacedNotificationSubject))
|
||||
{
|
||||
var notificationSubjectTokens = notificationTokenization.ReturnTokens(replacedNotificationSubject);
|
||||
var notificationSubjectTokens = Tokenisation.ReturnTokens(replacedNotificationSubject);
|
||||
foreach (var notificationToken in notificationSubjectTokens)
|
||||
{
|
||||
if (!values.TryGetValue(notificationToken, out var value))
|
||||
@@ -76,7 +62,8 @@ namespace Jube.App.Code
|
||||
var replacedNotificationBody = notificationBody;
|
||||
if (!String.IsNullOrEmpty(replacedNotificationBody))
|
||||
{
|
||||
var notificationBodyTokens = notificationTokenization.ReturnTokens(replacedNotificationBody);
|
||||
var notificationBodyTokens = Tokenisation.ReturnTokens(replacedNotificationBody);
|
||||
|
||||
foreach (var notificationToken in notificationBodyTokens)
|
||||
{
|
||||
if (!values.TryGetValue(notificationToken, out var value))
|
||||
@@ -11,26 +11,21 @@
|
||||
* see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Jube.App.Code
|
||||
namespace Jube.Case
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public class SendHttpEndpoint
|
||||
public static class SendHttpEndpoint
|
||||
{
|
||||
public async Task SendAsync(string httpEndpoint, byte httpEndpointTypeId, Dictionary<string, string> values)
|
||||
public static async Task SendAsync(string httpEndpoint, byte httpEndpointTypeId, Dictionary<string, string> values)
|
||||
{
|
||||
if (String.IsNullOrEmpty(httpEndpoint))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenization = new Tokenisation();
|
||||
var urlTokens = tokenization.ReturnTokens(httpEndpoint);
|
||||
var urlTokens = Tokenisation.ReturnTokens(httpEndpoint);
|
||||
|
||||
var replacedUrl = httpEndpoint;
|
||||
foreach (var token in urlTokens)
|
||||
@@ -11,26 +11,16 @@
|
||||
* see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Jube.App.Code
|
||||
namespace Jube.Case
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Web;
|
||||
using DynamicEnvironment;
|
||||
using log4net;
|
||||
|
||||
public class SendMail
|
||||
public class SendMail(DynamicEnvironment dynamicEnvironment, ILog log)
|
||||
{
|
||||
private readonly DynamicEnvironment dynamicEnvironment;
|
||||
private readonly ILog log;
|
||||
|
||||
public SendMail(DynamicEnvironment dynamicEnvironment, ILog log)
|
||||
{
|
||||
this.dynamicEnvironment = dynamicEnvironment;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public void Send(string toEmail, string subject, string body)
|
||||
{
|
||||
try
|
||||
@@ -11,27 +11,15 @@
|
||||
* see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Jube.App.Code
|
||||
namespace Jube.Case
|
||||
{
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using DynamicEnvironment;
|
||||
using log4net;
|
||||
|
||||
public class SendSms
|
||||
public class SendSms(DynamicEnvironment dynamicEnvironment, ILog log)
|
||||
{
|
||||
private static readonly HttpClient HttpClient = new HttpClient();
|
||||
private readonly DynamicEnvironment dynamicEnvironment;
|
||||
private readonly ILog log;
|
||||
|
||||
public SendSms(DynamicEnvironment dynamicEnvironment, ILog log)
|
||||
{
|
||||
this.dynamicEnvironment = dynamicEnvironment;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public async Task SendAsync(string notificationDestination, string notificationBody, CancellationToken token = default)
|
||||
{
|
||||
@@ -11,14 +11,13 @@
|
||||
* see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Jube.App.Code
|
||||
namespace Jube.Case
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public class Tokenisation
|
||||
public static class Tokenisation
|
||||
{
|
||||
public List<string> ReturnTokens(string message)
|
||||
public static List<string> ReturnTokens(string message)
|
||||
{
|
||||
var matches = Regex.Matches(message, @"\[@(.*?)\]");
|
||||
var returnList = new List<string>();
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace Jube.Engine.BackgroundTasks.TaskStarters.Case
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Data.Context;
|
||||
@@ -9,7 +10,9 @@ namespace Jube.Engine.BackgroundTasks.TaskStarters.Case
|
||||
using Data.Repository;
|
||||
using DynamicEnvironment;
|
||||
using EntityAnalysisModelInvoke.Models.CaseManagement;
|
||||
using Jube.Case;
|
||||
using log4net;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
public static class CaseProcessing
|
||||
{
|
||||
@@ -77,20 +80,27 @@ namespace Jube.Engine.BackgroundTasks.TaskStarters.Case
|
||||
|
||||
var existing = await query.ExecuteAsync(model.CaseWorkflowGuid, model.CaseKey, model.CaseKeyValue, token).ConfigureAwait(false);
|
||||
|
||||
var repositoryCasesWorkflowsStatus =
|
||||
new CaseWorkflowStatusRepository(dbContext, createCase.TenantRegistryId);
|
||||
|
||||
CaseWorkflowStatus finalCasesWorkflowsStatus = null;
|
||||
if (existing == null)
|
||||
{
|
||||
finalCasesWorkflowsStatus =
|
||||
await repositoryCasesWorkflowsStatus.GetByGuidAsync(model.CaseWorkflowStatusGuid, token).ConfigureAwait(false);
|
||||
|
||||
await repositoryCase.InsertAsync(model, token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var repositoryCasesWorkflowsStatus =
|
||||
new CaseWorkflowStatusRepository(dbContext, createCase.TenantRegistryId);
|
||||
|
||||
var recordCasesWorkflowsStatus =
|
||||
var existingCasesWorkflowsStatus =
|
||||
await repositoryCasesWorkflowsStatus.GetByGuidAsync(model.CaseWorkflowStatusGuid, token).ConfigureAwait(false);
|
||||
|
||||
if (recordCasesWorkflowsStatus.Priority < existing.Priority)
|
||||
if (existingCasesWorkflowsStatus.Priority < existing.Priority)
|
||||
{
|
||||
finalCasesWorkflowsStatus =
|
||||
await repositoryCasesWorkflowsStatus.GetByGuidAsync(model.CaseWorkflowStatusGuid, token).ConfigureAwait(false);
|
||||
|
||||
model.Id = existing.CaseId;
|
||||
model.Locked = 0;
|
||||
model.CaseWorkflowStatusGuid = createCase.CaseWorkflowStatusGuid;
|
||||
@@ -98,6 +108,48 @@ namespace Jube.Engine.BackgroundTasks.TaskStarters.Case
|
||||
}
|
||||
}
|
||||
|
||||
var caseBytes = 0;
|
||||
if (createCase.Json != null)
|
||||
{
|
||||
if (finalCasesWorkflowsStatus != null)
|
||||
{
|
||||
caseBytes = createCase.Json.Length;
|
||||
var jObject = JObject.Parse(model.Json);
|
||||
|
||||
var values = new Dictionary<string, string>();
|
||||
foreach (var (key, value) in jObject)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
values.Add(key, value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (finalCasesWorkflowsStatus.EnableNotification == 1 ||
|
||||
finalCasesWorkflowsStatus.EnableHttpEndpoint == 1)
|
||||
{
|
||||
if (finalCasesWorkflowsStatus.EnableNotification == 1)
|
||||
{
|
||||
var notification = new Notification(log, dynamicEnvironment);
|
||||
await notification.SendAsync(finalCasesWorkflowsStatus.NotificationTypeId ?? 1,
|
||||
finalCasesWorkflowsStatus.NotificationDestination,
|
||||
finalCasesWorkflowsStatus.NotificationSubject,
|
||||
finalCasesWorkflowsStatus.NotificationBody, values, token);
|
||||
}
|
||||
|
||||
if (finalCasesWorkflowsStatus.EnableHttpEndpoint == 1)
|
||||
{
|
||||
if (finalCasesWorkflowsStatus.HttpEndpointTypeId != null)
|
||||
{
|
||||
await SendHttpEndpoint.SendAsync(finalCasesWorkflowsStatus.HttpEndpoint,
|
||||
finalCasesWorkflowsStatus.HttpEndpointTypeId.Value
|
||||
, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (log.IsInfoEnabled)
|
||||
{
|
||||
log.Info(
|
||||
@@ -105,7 +157,7 @@ namespace Jube.Engine.BackgroundTasks.TaskStarters.Case
|
||||
$"Case Workflow ID of {createCase.EntityAnalysisModelInstanceEntryGuid}, " +
|
||||
$"Case Workflow Status ID of {createCase.CaseWorkflowStatusGuid}, " +
|
||||
$"Case Key of {createCase.CaseKeyValue}, " +
|
||||
$"Case JSON Bytes {createCase.Json.Length}");
|
||||
$"Case JSON Bytes {caseBytes}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<PackageReference Include="DnsClient" Version="1.2.0"/>
|
||||
<PackageReference Include="Fastenshtein" Version="1.0.0.5"/>
|
||||
<PackageReference Include="log4net" Version="2.0.14"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.10.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.10.0"/>
|
||||
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0"/>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.14.15">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@@ -51,6 +51,7 @@
|
||||
<ProjectReference Include="..\Accord.Neuro\Accord.Neuro.csproj"/>
|
||||
<ProjectReference Include="..\Accord.Statistics\Accord.Statistics.csproj"/>
|
||||
<ProjectReference Include="..\Jube.Cache\Jube.Cache.csproj"/>
|
||||
<ProjectReference Include="..\Jube.Case\Jube.Case.csproj"/>
|
||||
<ProjectReference Include="..\Jube.Data\Jube.Data.csproj"/>
|
||||
<ProjectReference Include="..\Jube.DynamicEnvironment\Jube.DynamicEnvironment.csproj"/>
|
||||
<ProjectReference Include="..\Jube.Dictionary\Jube.Dictionary.csproj"/>
|
||||
|
||||
@@ -55,6 +55,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jube.HealthCheck", "Jube.He
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jube.Sandbox", "Jube.Sandbox\Jube.Sandbox.csproj", "{28E3B7D8-799C-4367-BA9C-1AECF86939D4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jube.Case", "Jube.Case\Jube.Case.csproj", "{0F52BDA7-5117-48E9-8DB8-859221524B50}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -165,6 +167,10 @@ Global
|
||||
{28E3B7D8-799C-4367-BA9C-1AECF86939D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{28E3B7D8-799C-4367-BA9C-1AECF86939D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{28E3B7D8-799C-4367-BA9C-1AECF86939D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0F52BDA7-5117-48E9-8DB8-859221524B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0F52BDA7-5117-48E9-8DB8-859221524B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0F52BDA7-5117-48E9-8DB8-859221524B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F52BDA7-5117-48E9-8DB8-859221524B50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
EndGlobalSection
|
||||
|
||||
Reference in New Issue
Block a user