Skip to content

Commit 1ecd3eb

Browse files
Ticket ## : Generate OTP Code
1 parent ae7b98b commit 1ecd3eb

File tree

7 files changed

+233
-9
lines changed

7 files changed

+233
-9
lines changed

src/CaseManagement.BPMN.Host/Bpmns/UpdatePassword.bpmn

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<message id="humanTaskCreated" name="humanTaskCreated" />
55
<process id="Process_1" isExecutable="false">
66
<serviceTask id="Task_1hcentk" name="Send Email" implementation="##csharpcallback" cmg:delegateId="SendEmailDelegate">
7-
<incoming>Flow_0kge1w3</incoming>
7+
<incoming>Flow_0dts36d</incoming>
88
</serviceTask>
99
<userTask id="Activity_0fhwdxz" name="Submit Password" implementation="##WsHumanTask" cmg:wsHumanTaskDefName="updatePassword">
1010
<incoming>Flow_1fdpmlk</incoming>
@@ -24,17 +24,26 @@
2424
<messageEventDefinition id="MessageEventDefinition_01rnx81" messageRef="userMessage" />
2525
</startEvent>
2626
<sequenceFlow id="Flow_1fdpmlk" sourceRef="StartEvent_1y45yut" targetRef="Activity_0fhwdxz" />
27-
<sequenceFlow id="Flow_0kge1w3" sourceRef="Event_0q7uygb" targetRef="Task_1hcentk" />
2827
<boundaryEvent id="Event_0q7uygb" attachedToRef="Activity_0fhwdxz">
29-
<outgoing>Flow_0kge1w3</outgoing>
28+
<outgoing>Flow_02s526x</outgoing>
3029
<messageEventDefinition id="MessageEventDefinition_135rspe" messageRef="humanTaskCreated" />
3130
</boundaryEvent>
31+
<sequenceFlow id="Flow_02s526x" sourceRef="Event_0q7uygb" targetRef="Activity_0owchb4" />
32+
<sequenceFlow id="Flow_0dts36d" sourceRef="Activity_0owchb4" targetRef="Task_1hcentk" />
33+
<serviceTask id="Activity_0owchb4" name="Generate OTP" implementation="##csharpcallback" cmg:delegateId="GenerateOTPDelegate">
34+
<incoming>Flow_02s526x</incoming>
35+
<outgoing>Flow_0dts36d</outgoing>
36+
</serviceTask>
3237
</process>
3338
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
3439
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
35-
<bpmndi:BPMNEdge id="Flow_0kge1w3_di" bpmnElement="Flow_0kge1w3">
40+
<bpmndi:BPMNEdge id="Flow_0dts36d_di" bpmnElement="Flow_0dts36d">
41+
<omgdi:waypoint x="490" y="350" />
42+
<omgdi:waypoint x="490" y="440" />
43+
</bpmndi:BPMNEdge>
44+
<bpmndi:BPMNEdge id="Flow_02s526x_di" bpmnElement="Flow_02s526x">
3645
<omgdi:waypoint x="490" y="208" />
37-
<omgdi:waypoint x="490" y="280" />
46+
<omgdi:waypoint x="490" y="270" />
3847
</bpmndi:BPMNEdge>
3948
<bpmndi:BPMNEdge id="Flow_1fdpmlk_di" bpmnElement="Flow_1fdpmlk">
4049
<omgdi:waypoint x="188" y="150" />
@@ -49,7 +58,7 @@
4958
<omgdi:waypoint x="720" y="150" />
5059
</bpmndi:BPMNEdge>
5160
<bpmndi:BPMNShape id="Activity_1saua76_di" bpmnElement="Task_1hcentk">
52-
<omgdc:Bounds x="440" y="280" width="100" height="80" />
61+
<omgdc:Bounds x="440" y="440" width="100" height="80" />
5362
</bpmndi:BPMNShape>
5463
<bpmndi:BPMNShape id="Activity_1j5vxke_di" bpmnElement="Activity_0fhwdxz">
5564
<omgdc:Bounds x="390" y="110" width="100" height="80" />
@@ -63,6 +72,9 @@
6372
<bpmndi:BPMNShape id="Event_0bfv2sq_di" bpmnElement="StartEvent_1y45yut">
6473
<omgdc:Bounds x="152" y="132" width="36" height="36" />
6574
</bpmndi:BPMNShape>
75+
<bpmndi:BPMNShape id="Activity_0yn3q1b_di" bpmnElement="Activity_0owchb4">
76+
<omgdc:Bounds x="440" y="270" width="100" height="80" />
77+
</bpmndi:BPMNShape>
6678
<bpmndi:BPMNShape id="Event_10s7arv_di" bpmnElement="Event_0q7uygb">
6779
<omgdc:Bounds x="472" y="172" width="36" height="36" />
6880
</bpmndi:BPMNShape>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using CaseManagement.BPMN.Domains;
2+
using CaseManagement.BPMN.Exceptions;
3+
using CaseManagement.BPMN.ProcessInstance.Processors;
4+
using IdentityModel.Client;
5+
using Newtonsoft.Json.Linq;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Net.Http;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
13+
namespace CaseManagement.BPMN.Host.Delegates
14+
{
15+
public class GenerateOTPDelegate : IDelegateHandler
16+
{
17+
public async Task<ICollection<MessageToken>> Execute(BPMNExecutionContext context, ICollection<MessageToken> incoming, DelegateConfigurationAggregate delegateConfiguration, CancellationToken cancellationToken)
18+
{
19+
var user = incoming.FirstOrDefault(i => i.Name == "user");
20+
if (user == null)
21+
{
22+
throw new BPMNProcessorException("user must be passed in the request");
23+
}
24+
25+
var userId = user.GetProperty("userId");
26+
if (string.IsNullOrWhiteSpace(userId))
27+
{
28+
throw new BPMNProcessorException("userId is not passed in the request");
29+
}
30+
31+
var parameter = GenerateOTPPasswordParameter.Create(delegateConfiguration);
32+
using (var httpClient = new HttpClient())
33+
{
34+
var tokenResponse = await httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
35+
{
36+
Address = parameter.TokenUrl,
37+
ClientId = parameter.ClientId,
38+
ClientSecret = parameter.ClientSecret,
39+
Scope = parameter.Scope
40+
}, cancellationToken);
41+
if (tokenResponse.IsError)
42+
{
43+
throw new BPMNProcessorException(tokenResponse.Error);
44+
}
45+
46+
var url = parameter.UserUrl.Replace("{id}", userId);
47+
var request = new HttpRequestMessage
48+
{
49+
Method = HttpMethod.Get,
50+
RequestUri = new Uri(url)
51+
};
52+
request.Headers.Add("Authorization", $"Bearer {tokenResponse.AccessToken}");
53+
var httpResponse = await httpClient.SendAsync(request, cancellationToken);
54+
httpResponse.EnsureSuccessStatusCode();
55+
var content = await httpResponse.Content.ReadAsStringAsync();
56+
var otp = long.Parse(content);
57+
ICollection<MessageToken> result = new List<MessageToken>
58+
{
59+
MessageToken.NewMessage(context.Pointer.InstanceFlowNodeId, "otp", new JObject
60+
{
61+
{ "otpCode", otp }
62+
}.ToString())
63+
};
64+
return result;
65+
}
66+
}
67+
68+
private class GenerateOTPPasswordParameter
69+
{
70+
public string TokenUrl { get; set; }
71+
public string UserUrl { get; set; }
72+
public string ClientId { get; set; }
73+
public string ClientSecret { get; set; }
74+
public string Scope { get; set; }
75+
76+
public static GenerateOTPPasswordParameter Create(DelegateConfigurationAggregate delegateConfiguration)
77+
{
78+
return new GenerateOTPPasswordParameter
79+
{
80+
ClientId = delegateConfiguration.GetValue("clientId"),
81+
ClientSecret = delegateConfiguration.GetValue("clientSecret"),
82+
TokenUrl = delegateConfiguration.GetValue("tokenUrl"),
83+
UserUrl = delegateConfiguration.GetValue("userUrl"),
84+
Scope = delegateConfiguration.GetValue("scope")
85+
};
86+
}
87+
}
88+
}
89+
}

src/CaseManagement.BPMN.Host/Delegates/SendEmailDelegate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public Task<ICollection<MessageToken>> Execute(BPMNExecutionContext context, ICo
3939
{
4040
From = new MailAddress(parameter.FromEmail),
4141
Subject = parameter.Subject,
42-
Body = parameter.HttpBody,
42+
Body = DelegateHelper.Parse(delegateConfiguration, incoming, parameter.HttpBody),
4343
IsBodyHtml = true
4444
};
4545

src/CaseManagement.BPMN.Host/Startup.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,14 @@ private static ConcurrentBag<DelegateConfigurationAggregate> GetDelegateConfigur
198198
var sendEmailDelegate = DelegateConfigurationAggregate.Create("SendEmailDelegate", typeof(SendEmailDelegate).FullName);
199199
sendEmailDelegate.AddDisplayName("fr", "Envoyer un email");
200200
sendEmailDelegate.AddDisplayName("en", "Send email");
201-
sendEmailDelegate.AddRecord("httpBody", "Please click on this link to update the password");
201+
sendEmailDelegate.AddRecord("httpBody", "Please update the password by clicking on the website {{configuration.Get('humanTaskUrl')}}/humantasks/{{messages.Get('humanTaskCreated', 'humanTaskInstance.fileId')}}/instances/{{messages.Get('humanTaskCreated', 'humanTaskInstance.id')}}?auth=email, the OTP code is {{messages.Get('otp', 'otpCode')}}");
202202
sendEmailDelegate.AddRecord("subject", "Update password");
203203
sendEmailDelegate.AddRecord("fromEmail", credential.Login);
204204
sendEmailDelegate.AddRecord("smtpHost", "smtp.gmail.com");
205205
sendEmailDelegate.AddRecord("smtpPort", "587");
206206
sendEmailDelegate.AddRecord("smtpUserName", credential.Login);
207207
sendEmailDelegate.AddRecord("smtpPassword", credential.Password);
208+
sendEmailDelegate.AddRecord("humanTaskUrl", "http://localhost:4200");
208209
sendEmailDelegate.AddRecord("smtpEnableSsl", "true");
209210

210211
var updateUserPasswordDelegate = DelegateConfigurationAggregate.Create("UpdateUserPasswordDelegate", typeof(UpdateUserPasswordDelegate).FullName);
@@ -216,11 +217,21 @@ private static ConcurrentBag<DelegateConfigurationAggregate> GetDelegateConfigur
216217
updateUserPasswordDelegate.AddRecord("userUrl", "https://localhost:60000/management/users/{id}/password");
217218
updateUserPasswordDelegate.AddRecord("scope", "manage_users");
218219

220+
var generateOTPDelegate = DelegateConfigurationAggregate.Create("GenerateOTPDelegate", typeof(GenerateOTPDelegate).FullName);
221+
generateOTPDelegate.AddDisplayName("fr", "Générer le code OTP");
222+
generateOTPDelegate.AddDisplayName("en", "Generate OTP code");
223+
generateOTPDelegate.AddRecord("clientId", "humanTaskClient");
224+
generateOTPDelegate.AddRecord("clientSecret", "humanTaskClientSecret");
225+
generateOTPDelegate.AddRecord("tokenUrl", "https://localhost:60000/token");
226+
generateOTPDelegate.AddRecord("userUrl", "https://localhost:60000/management/users/{id}/otp");
227+
generateOTPDelegate.AddRecord("scope", "manage_users");
228+
219229
return new ConcurrentBag<DelegateConfigurationAggregate>
220230
{
221231
getWeatherInformationDelegate,
222232
sendEmailDelegate,
223-
updateUserPasswordDelegate
233+
updateUserPasswordDelegate,
234+
generateOTPDelegate
224235
};
225236
}
226237

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using CaseManagement.BPMN.Domains;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.RegularExpressions;
5+
6+
namespace CaseManagement.BPMN
7+
{
8+
public static class DelegateHelper
9+
{
10+
public static string Parse(DelegateConfigurationAggregate configuration, ICollection<MessageToken> incoming, string message)
11+
{
12+
var regularExpression = new Regex(@"{{([a-zA-Z]|_|\.|\(|\)|\'|\ |\,)*\}}");
13+
var isMessageRegularExpression = new Regex(@"messages.Get\((\'([a-zA-Z]|\.|\ |\,)*\')");
14+
var isConfigurationRegularExpression = new Regex(@"configuration.Get\((\'([a-zA-Z])*\')");
15+
return regularExpression.Replace(message, (m) =>
16+
{
17+
if (string.IsNullOrWhiteSpace(m.Value))
18+
{
19+
return string.Empty;
20+
}
21+
22+
var str = m.Value.Replace("{{", "");
23+
str = str.Replace("}}", "");
24+
if (isMessageRegularExpression.IsMatch(str))
25+
{
26+
str = str.Replace("messages.Get('", "");
27+
str = str.TrimEnd(')');
28+
str = str.Replace("'", "");
29+
if (string.IsNullOrWhiteSpace(str))
30+
{
31+
return null;
32+
}
33+
34+
var parameters = str.Split(',');
35+
if (parameters.Count() != 2)
36+
{
37+
return null;
38+
}
39+
40+
var firstParameter = parameters.First().Replace(" ", "");
41+
var secondParameter = parameters.Last().Replace(" ", "");
42+
var token = incoming.FirstOrDefault(i => i.Name == firstParameter);
43+
if (token == null)
44+
{
45+
return null;
46+
}
47+
48+
if (string.IsNullOrWhiteSpace(secondParameter))
49+
{
50+
return null;
51+
}
52+
53+
var jsonToken = token.JObjMessageContent.SelectToken(secondParameter);
54+
if (jsonToken == null)
55+
{
56+
return null;
57+
}
58+
59+
return jsonToken.ToString();
60+
}
61+
62+
if (isConfigurationRegularExpression.IsMatch(str))
63+
{
64+
str = str.Replace("configuration.Get('", "");
65+
str = str.TrimEnd(')');
66+
str = str.Replace("'", "");
67+
return configuration.GetValue(str);
68+
}
69+
70+
return null;
71+
});
72+
}
73+
}
74+
}

src/CaseManagement.BPMN/ProcessInstance/Processors/Activities/Handlers/WsHumanTaskHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public async Task<ICollection<MessageToken>> Execute(BPMNExecutionContext execut
9494
executionContext.Instance.UpdateMetadata(pointer.InstanceFlowNodeId, HUMANTASK_INSTANCE_ID_NAME, humanTaskInstanceId);
9595
var humanTaskInstance = new JObject();
9696
humanTaskInstance.Add("id", humanTaskInstanceId);
97+
humanTaskInstance.Add("fileId", userTask.HumanTaskName);
9798
var messageContent = new JObject();
9899
messageContent.Add("humanTaskInstance", humanTaskInstance);
99100
executionContext.Instance.ConsumeMessage(new MessageToken
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using CaseManagement.BPMN.Domains;
2+
using Newtonsoft.Json.Linq;
3+
using System;
4+
using System.Collections.Generic;
5+
using Xunit;
6+
7+
namespace CaseManagement.BPMN.Tests
8+
{
9+
public class DelegateHelperFixture
10+
{
11+
[Fact]
12+
public void Parse_Parameter()
13+
{
14+
// ARRANGE
15+
var message = "Please update the password by clicking on the website {{configuration.Get('humanTaskUrl')}}/humantasks/{{messages.Get('humanTaskCreated', 'humanTaskInstance.fileId')}}/instances/{{messages.Get('humanTaskCreated', 'humanTaskInstance.id')}}?auth=email";
16+
var incomingTokens = new List<MessageToken>
17+
{
18+
MessageToken.NewMessage(Guid.NewGuid().ToString(), "humanTaskCreated", new JObject
19+
{
20+
{ "humanTaskInstance", new JObject
21+
{
22+
{ "id", "id" },
23+
{ "fileId", "fileId" }
24+
}}
25+
}.ToString())
26+
};
27+
var configuration = new DelegateConfigurationAggregate();
28+
configuration.AddRecord("humanTaskUrl", "http://localhost:4200");
29+
30+
// ACT
31+
var result = DelegateHelper.Parse(configuration, incomingTokens, message);
32+
33+
// ASSERT
34+
Assert.Equal("Please update the password by clicking on the website http://localhost:4200/humantasks/fileId/instances/id?auth=email", result);
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)