Skip to content

Commit 9e8b177

Browse files
Thierry Habarthabarthierry-hue
authored andcommitted
Ticket #11 : Add milestone
Ticket #12 : support performerRef
1 parent b00445d commit 9e8b177

73 files changed

Lines changed: 1499 additions & 319 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Doc.docx

30 KB
Binary file not shown.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.Authentication.Cookies;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
using System.Collections.Generic;
6+
using System.Security.Claims;
7+
using System.Text.Encodings.Web;
8+
using System.Threading.Tasks;
9+
10+
namespace CaseManagement.CMMN.Benchmark.Middlewares
11+
{
12+
public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
13+
{
14+
public CustomAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
15+
{
16+
}
17+
18+
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
19+
{
20+
var claims = new List<Claim>
21+
{
22+
new Claim(ClaimTypes.Name, "Thierry Habart"),
23+
new Claim(ClaimTypes.NameIdentifier, "thabart")
24+
};
25+
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
26+
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
27+
var authenticationTicket = new AuthenticationTicket(
28+
claimsPrincipal,
29+
new AuthenticationProperties(),
30+
CookieAuthenticationDefaults.AuthenticationScheme);
31+
return Task.FromResult(AuthenticateResult.Success(authenticationTicket));
32+
}
33+
}
34+
}

src/CaseManagement.CMMN.Benchmark/Startup.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
using CaseManagement.Workflow.Domains;
1+
using CaseManagement.CMMN.Benchmark.Middlewares;
2+
using CaseManagement.Workflow.Domains;
3+
using Microsoft.AspNetCore.Authentication;
4+
using Microsoft.AspNetCore.Authentication.Cookies;
25
using Microsoft.AspNetCore.Builder;
36
using Microsoft.AspNetCore.Hosting;
47
using Microsoft.Extensions.DependencyInjection;
58
using Microsoft.Extensions.Logging;
9+
using System;
610
using System.Collections.Generic;
711
using System.IO;
812

@@ -12,6 +16,12 @@ public class Startup
1216
{
1317
public void ConfigureServices(IServiceCollection services)
1418
{
19+
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
20+
.AddCustomAuthentication(opts => { });
21+
services.AddAuthorization(policy =>
22+
{
23+
policy.AddPolicy("IsConnected", p => p.RequireAuthenticatedUser());
24+
});
1525
var builder = services.AddCMMN();
1626
builder.AddDefinitions(c =>
1727
{
@@ -20,9 +30,9 @@ public void ConfigureServices(IServiceCollection services)
2030
c.ImportDefinition(file);
2131
}
2232
})
23-
.AddForms(new List<Form>
33+
.AddForms(new List<FormAggregate>
2434
{
25-
new Form
35+
new FormAggregate
2636
{
2737
Id = "createMeetingForm",
2838
Elements = new List<FormElement>
@@ -49,4 +59,13 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
4959
app.UseCMMN();
5060
}
5161
}
62+
63+
public static class ServiceCollectionExtensions
64+
{
65+
public static AuthenticationBuilder AddCustomAuthentication(this AuthenticationBuilder authBuilder, Action<AuthenticationSchemeOptions> callback)
66+
{
67+
authBuilder.AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>(CookieAuthenticationDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme, callback);
68+
return authBuilder;
69+
}
70+
}
5271
}

src/CaseManagement.CMMN.Host/Startup.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) SimpleIdServer. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
33
using CaseManagement.Workflow.Domains;
4+
using Microsoft.AspNetCore.Authentication.Cookies;
45
using Microsoft.AspNetCore.Builder;
56
using Microsoft.AspNetCore.Hosting;
67
using Microsoft.Extensions.DependencyInjection;
@@ -16,6 +17,12 @@ public Startup(IHostingEnvironment env) { }
1617

1718
public void ConfigureServices(IServiceCollection services)
1819
{
20+
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
21+
.AddCookie();
22+
services.AddAuthorization(policy =>
23+
{
24+
policy.AddPolicy("IsConnected", p => p.RequireAuthenticatedUser());
25+
});
1926
var builder = services.AddCMMN();
2027
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
2128
.AllowAnyMethod()
@@ -27,9 +34,9 @@ public void ConfigureServices(IServiceCollection services)
2734
c.ImportDefinition(file);
2835
}
2936
})
30-
.AddForms(new List<Form>
37+
.AddForms(new List<FormAggregate>
3138
{
32-
new Form
39+
new FormAggregate
3340
{
3441
Id = "createMeetingForm",
3542
Elements = new List<FormElement>
@@ -46,6 +53,7 @@ public void ConfigureServices(IServiceCollection services)
4653

4754
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
4855
{
56+
app.UseAuthentication();
4957
app.UseCors("AllowAll");
5058
app.UseCMMN();
5159
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using CaseManagement.CMMN.Extensions;
2+
using CaseManagement.Workflow.Domains;
3+
using CaseManagement.Workflow.Persistence;
4+
using CaseManagement.Workflow.Persistence.Parameters;
5+
using CaseManagement.Workflow.Persistence.Responses;
6+
using Microsoft.AspNetCore.Authorization;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Mvc;
9+
using Newtonsoft.Json.Linq;
10+
using System;
11+
using System.Collections.Generic;
12+
using System.Linq;
13+
using System.Threading.Tasks;
14+
15+
namespace CaseManagement.CMMN.Apis
16+
{
17+
[Route(CMMNConstants.RouteNames.CaseFormInstances)]
18+
public class CaseFormInstancesController : Controller
19+
{
20+
private readonly IFormInstanceQueryRepository _formInstanceQueryRepository;
21+
private readonly IRoleQueryRepository _roleQueryRepository;
22+
23+
public CaseFormInstancesController(IFormInstanceQueryRepository formInstanceQueryRepository, IRoleQueryRepository roleQueryRepository)
24+
{
25+
_formInstanceQueryRepository = formInstanceQueryRepository;
26+
_roleQueryRepository = roleQueryRepository;
27+
}
28+
29+
[HttpGet(".me/search")]
30+
[Authorize("IsConnected")]
31+
public async Task<IActionResult> Search()
32+
{
33+
var nameIdentifier = this.GetNameIdentifier();
34+
var userRoles = await _roleQueryRepository.FindRolesByUser(nameIdentifier);
35+
var roleIds = userRoles.Select(r => r.Id);
36+
var query = HttpContext.Request.Query;
37+
var result = await _formInstanceQueryRepository.Find(ExtractFindFormInstanceParameter(query, roleIds));
38+
return new OkObjectResult(ToDto(result));
39+
}
40+
41+
private static JObject ToDto(FindResponse<FormInstanceAggregate> resp)
42+
{
43+
return new JObject
44+
{
45+
{ "start_index", resp.StartIndex },
46+
{ "total_length", resp.TotalLength },
47+
{ "count", resp.Count },
48+
{ "content", new JArray(resp.Content.Select(r => {
49+
var result = new JObject
50+
{
51+
{ "create_datetime", r.CreateDateTime },
52+
{ "update_datetime", r.UpdateDateTime },
53+
{ "status", Enum.GetName(typeof(FormInstanceStatus), r.Status).ToLowerInvariant() },
54+
{ "form_id", r.FormId }
55+
};
56+
foreach(var title in r.Titles)
57+
{
58+
result.Add($"title#{title.Language}", title.Value);
59+
}
60+
61+
var content = new JArray();
62+
foreach(var formElt in r.Content)
63+
{
64+
var record = new JObject
65+
{
66+
{ "form_element_id", formElt.FormElementId },
67+
{ "is_required", formElt.IsRequired },
68+
{ "value", formElt.Value },
69+
{ "type", Enum.GetName(typeof(FormElementTypes), formElt.Type).ToLowerInvariant() }
70+
};
71+
foreach(var name in formElt.Names)
72+
{
73+
record.Add($"name#{name.Language}", name.Value);
74+
}
75+
76+
foreach(var description in formElt.Descriptions)
77+
{
78+
record.Add($"description#{description.Language}", description.Value);
79+
}
80+
81+
content.Add(record);
82+
}
83+
84+
result.Add("content", content);
85+
return result;
86+
})) }
87+
};
88+
}
89+
90+
private static FindFormInstanceParameter ExtractFindFormInstanceParameter(IQueryCollection query, IEnumerable<string> roleIds)
91+
{
92+
var parameter = new FindFormInstanceParameter
93+
{
94+
RoleIds = roleIds
95+
};
96+
parameter.ExtractFindParameter(query);
97+
return parameter;
98+
}
99+
}
100+
}

src/CaseManagement.CMMN/Apis/CaseInstancesController.cs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public async Task<IActionResult> Launch(string id)
6464
[HttpPost("{id}/confirm/{elt}")]
6565
public async Task<IActionResult> ConfirmForm(string id, string elt, [FromBody] JObject jObj)
6666
{
67+
// CHECK THE ROLE.
6768
try
6869
{
6970
await _confirmFormCommandHandler.Handle(new ConfirmFormCommand { CaseInstanceId = id, CaseElementInstanceId = elt, Content = jObj });
@@ -126,43 +127,17 @@ private static FindWorkflowInstanceParameter ExtractFindWorkflowInstanceParamete
126127
{
127128
parameter.ProcessFlowTemplateId = templateId;
128129
}
129-
ExtractFindParameter(query, parameter);
130+
parameter.ExtractFindParameter(query);
130131
return parameter;
131132
}
132133

133134
private static FindExecutionStepsParameter ExtractFindExecutionStepsParameter(IQueryCollection query)
134135
{
135136
var parameter = new FindExecutionStepsParameter();
136-
ExtractFindParameter(query, parameter);
137+
parameter.ExtractFindParameter(query);
137138
return parameter;
138139
}
139140

140-
private static void ExtractFindParameter(IQueryCollection query, BaseFindParameter parameter)
141-
{
142-
int startIndex, count;
143-
string orderBy;
144-
FindOrders findOrder;
145-
if (query.TryGet("start_index", out startIndex))
146-
{
147-
parameter.StartIndex = startIndex;
148-
}
149-
150-
if (query.TryGet("count", out count))
151-
{
152-
parameter.Count = count;
153-
}
154-
155-
if (query.TryGet("order_by", out orderBy))
156-
{
157-
parameter.OrderBy = orderBy;
158-
}
159-
160-
if (query.TryGet("order", out findOrder))
161-
{
162-
parameter.Order = findOrder;
163-
}
164-
}
165-
166141
private static JObject ToDto(FindResponse<ProcessFlowInstanceExecutionStep> resp)
167142
{
168143
return new JObject

src/CaseManagement.CMMN/CMMNConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public static class RouteNames
77
public const string CaseDefinitions = "case-definitions";
88
public const string CaseInstances = "case-instances";
99
public const string CaseProcesses = "case-processes";
10+
public const string CaseFormInstances = "case-form-instances";
1011
}
1112

1213
public static class ProcessImplementationTypes

src/CaseManagement.CMMN/CaseInstance/CommandHandlers/ConfirmFormCommandHandler.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
using CaseManagement.CMMN.CaseInstance.Exceptions;
33
using CaseManagement.CMMN.Domains;
44
using CaseManagement.Workflow.Domains;
5+
using CaseManagement.Workflow.Domains.Process.Exceptions;
56
using CaseManagement.Workflow.Infrastructure.Bus;
67
using CaseManagement.Workflow.Infrastructure.EvtStore;
78
using CaseManagement.Workflow.Persistence;
9+
using Newtonsoft.Json.Linq;
10+
using System.Collections.Generic;
811
using System.Linq;
912
using System.Threading.Tasks;
1013

@@ -49,9 +52,53 @@ public async Task<bool> Handle(ConfirmFormCommand confirmFormCommand)
4952
throw new UnknownFormException(humanTask.FormId);
5053
}
5154

52-
caseInstance.ConfirmForm(confirmFormCommand.CaseElementInstanceId, form, confirmFormCommand.Content);
53-
await _queueProvider.QueueConfirmForm(caseInstance.Id, confirmFormCommand.CaseElementInstanceId, confirmFormCommand.Content);
55+
var formValues = CheckConfirmForm(form, confirmFormCommand.Content);
56+
await _queueProvider.QueueConfirmForm(caseInstance.Id, confirmFormCommand.CaseElementInstanceId, formValues);
5457
return true;
5558
}
59+
60+
private static Dictionary<string, string> CheckConfirmForm(FormAggregate form, JObject content)
61+
{
62+
var result = new Dictionary<string, string>();
63+
var errors = new Dictionary<string, string>();
64+
foreach (var elt in form.Elements)
65+
{
66+
string value = string.Empty;
67+
if (elt.IsRequired && (!content.ContainsKey(elt.Id) || string.IsNullOrWhiteSpace((value = content[elt.Id].ToString()))))
68+
{
69+
errors.Add("validation_error", $"field {elt.Id} is required");
70+
}
71+
72+
switch (elt.Type)
73+
{
74+
case FormElementTypes.INT:
75+
int i;
76+
if (!int.TryParse(value, out i))
77+
{
78+
errors.Add("validation_error", $"field {elt.Id} is not an integer");
79+
}
80+
break;
81+
case FormElementTypes.BOOL:
82+
bool b;
83+
if (!bool.TryParse(value, out b))
84+
{
85+
errors.Add("validation_error", $"field {elt.Id} is not a boolean");
86+
}
87+
break;
88+
}
89+
90+
result.Add(elt.Id, value);
91+
}
92+
93+
if (errors.Any())
94+
{
95+
throw new ProcessFlowInstanceDomainException
96+
{
97+
Errors = errors
98+
};
99+
}
100+
101+
return result;
102+
}
56103
}
57104
}

src/CaseManagement.CMMN/CaseInstance/CommandHandlers/CreateCaseInstanceCommandHandler.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ private static CMMNPlanItem BuildPlanItem(string id, string name, tPlanItemDefin
106106
return CMMNPlanItem.New(id, name, BuildTimerEventListener((tTimerEventListener)planItemDef));
107107
}
108108

109+
if (planItemDef is tMilestone)
110+
{
111+
return CMMNPlanItem.New(id, name, BuildMilestone((tMilestone)planItemDef));
112+
}
113+
109114
return null;
110115
}
111116

@@ -151,7 +156,17 @@ private static CMMNProcessTask BuildProcessTask(tProcessTask processTask)
151156

152157
private static CMMNHumanTask BuildHumanTask(tHumanTask humanTask)
153158
{
154-
return new CMMNHumanTask(humanTask.name) { FormId = humanTask.caseFormRef, IsBlocking = humanTask.isBlocking };
159+
return new CMMNHumanTask(humanTask.name)
160+
{
161+
PerformerRef = humanTask.performerRef,
162+
FormId = humanTask.caseFormRef,
163+
IsBlocking = humanTask.isBlocking
164+
};
165+
}
166+
167+
private static CMMNMilestone BuildMilestone(tMilestone milestone)
168+
{
169+
return new CMMNMilestone(milestone.name);
155170
}
156171

157172
private static CMMNTimerEventListener BuildTimerEventListener(tTimerEventListener timerEventListener)

0 commit comments

Comments
 (0)