Skip to content

Commit cf5e210

Browse files
Thierry Habarthabarthierry-hue
authored andcommitted
Ticket #20 : Support discretionary element in case
1 parent 7672f25 commit cf5e210

43 files changed

Lines changed: 1297 additions & 281 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.

Architecture.pptx

3.72 KB
Binary file not shown.

src/CaseManagement.CMMN.AspNet/Apis/CaseDefinitionsController.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ private static FindWorkflowDefinitionsParameter ExtractFindParameter(IEnumerable
122122
{
123123
string caseFile;
124124
string text;
125+
string caseOwner;
125126
var parameter = new FindWorkflowDefinitionsParameter();
126127
parameter.ExtractFindParameter(query);
127128
if (query.TryGet("case_file", out caseFile))
@@ -134,6 +135,11 @@ private static FindWorkflowDefinitionsParameter ExtractFindParameter(IEnumerable
134135
parameter.Text = text;
135136
}
136137

138+
if (query.TryGet("caseowner", out caseOwner))
139+
{
140+
parameter.CaseOwner = caseOwner;
141+
}
142+
137143
return parameter;
138144
}
139145
}

src/CaseManagement.CMMN.AspNetCore/Apis/CaseInstancesController.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ public class CaseInstancesController : Controller
3333
private readonly ICloseCommandHandler _closeCommandHandler;
3434
private readonly IConfirmFormCommandHandler _confirmFormCommandHandler;
3535
private readonly IActivateCommandHandler _activateCommandHandler;
36+
private readonly IConfirmTableItemCommandHandler _confirmTableItemCommandHandler;
3637
private readonly ICaseInstanceQueryRepository _cmmnWorkflowInstanceQueryRepository;
3738
private readonly ICaseFileItemRepository _caseFileItemRepository;
3839

39-
public CaseInstancesController(ICreateCaseInstanceCommandHandler createCaseInstanceCommandHandler, ILaunchCaseInstanceCommandHandler launchCaseInstanceCommandHandler, ISuspendCommandHandler suspendCommandHandler, IResumeCommandHandler resumeCommandHandler, ITerminateCommandHandler terminateCommandHandler, IReactivateCommandHandler reactivateCommandHandler, ICloseCommandHandler closeCommandHandler, IConfirmFormCommandHandler confirmFormCommandHandler, IActivateCommandHandler activateCommandHandler, ICaseInstanceQueryRepository cmmnWorkflowInstanceQueryRepository, ICaseFileItemRepository caseFileItemRepository)
40+
public CaseInstancesController(ICreateCaseInstanceCommandHandler createCaseInstanceCommandHandler, ILaunchCaseInstanceCommandHandler launchCaseInstanceCommandHandler, ISuspendCommandHandler suspendCommandHandler, IResumeCommandHandler resumeCommandHandler, ITerminateCommandHandler terminateCommandHandler, IReactivateCommandHandler reactivateCommandHandler, ICloseCommandHandler closeCommandHandler, IConfirmFormCommandHandler confirmFormCommandHandler, IActivateCommandHandler activateCommandHandler, IConfirmTableItemCommandHandler confirmTableItemCommandHandler, ICaseInstanceQueryRepository cmmnWorkflowInstanceQueryRepository, ICaseFileItemRepository caseFileItemRepository)
4041
{
4142
_createCaseInstanceCommandHandler = createCaseInstanceCommandHandler;
4243
_launchCaseInstanceCommandHandler = launchCaseInstanceCommandHandler;
@@ -47,6 +48,7 @@ public CaseInstancesController(ICreateCaseInstanceCommandHandler createCaseInsta
4748
_closeCommandHandler = closeCommandHandler;
4849
_confirmFormCommandHandler = confirmFormCommandHandler;
4950
_activateCommandHandler = activateCommandHandler;
51+
_confirmTableItemCommandHandler = confirmTableItemCommandHandler;
5052
_cmmnWorkflowInstanceQueryRepository = cmmnWorkflowInstanceQueryRepository;
5153
_caseFileItemRepository = caseFileItemRepository;
5254
}
@@ -98,7 +100,7 @@ public async Task<IActionResult> Create([FromBody] CreateCaseInstanceCommand cre
98100
}, HttpStatusCode.NotFound, Request);
99101
}
100102
}
101-
103+
102104
[HttpGet("{id}/launch")]
103105
public async Task<IActionResult> Launch(string id)
104106
{
@@ -482,6 +484,49 @@ public async Task<IActionResult> Activate(string id, string elt)
482484
}
483485
}
484486

487+
[HttpGet("{id}/confirmplanitem/{elt}")]
488+
[Authorize("IsConnected")]
489+
public async Task<IActionResult> ConfirmPlanItem(string id, string elt)
490+
{
491+
try
492+
{
493+
await _confirmTableItemCommandHandler.Handle(new ConfirmTableItemCommand { CaseInstanceId = id, CaseElementDefinitionId = elt, User = this.GetNameIdentifier() });
494+
return new OkResult();
495+
}
496+
catch (UnknownCaseInstanceException)
497+
{
498+
return ToError(new Dictionary<string, string>
499+
{
500+
{ "bad_request", "case instance doesn't exist" }
501+
}, HttpStatusCode.NotFound, Request);
502+
}
503+
catch (UnknownCaseElementDefinitionException)
504+
{
505+
return ToError(new Dictionary<string, string>
506+
{
507+
{ "bad_request", "case element doesn't exist" }
508+
}, HttpStatusCode.NotFound, Request);
509+
}
510+
catch (UnauthorizedCaseWorkerException)
511+
{
512+
return ToError(new Dictionary<string, string>
513+
{
514+
{ "unauthorized_request", "you're not authorized to confirm the human task" }
515+
}, HttpStatusCode.Unauthorized, Request);
516+
}
517+
catch (AggregateValidationException ex)
518+
{
519+
return ToError(ex.Errors, HttpStatusCode.BadRequest, Request);
520+
}
521+
catch (Exception ex)
522+
{
523+
return ToError(new Dictionary<string, string>
524+
{
525+
{ "invalid_request", ex.Message }
526+
}, HttpStatusCode.BadRequest, Request);
527+
}
528+
}
529+
485530
private static JObject ToDto(FindResponse<Domains.CaseInstance> resp)
486531
{
487532
return new JObject
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using CaseManagement.CMMN.Domains;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace CaseManagement.CMMN.Builders
7+
{
8+
public class TableItemBuilder
9+
{
10+
private readonly TableItem _tableItem;
11+
12+
public TableItemBuilder(TableItem tableItem)
13+
{
14+
_tableItem = tableItem;
15+
}
16+
17+
public TableItemBuilder SetAuthorizedRole(string name)
18+
{
19+
_tableItem.AuthorizedRoleRef = name;
20+
return this;
21+
}
22+
23+
public TableItemBuilder SetApplicabilityRule(string name, string contextRef, string expression)
24+
{
25+
_tableItem.ApplicabilityRuleRef = new ApplicabilityRule { Name = name, ContextRef = contextRef, Expression = expression };
26+
return this;
27+
}
28+
}
29+
}

src/CaseManagement.CMMN/Builders/WorkflowBuilder.cs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class WorkflowBuilder
1010
private readonly string _processFlowName;
1111
private ICollection<CaseElementDefinition> _elements { get; set; }
1212
private ICollection<Criteria> _exitCriterias { get; set; }
13+
private string _caseOwner;
1314

1415
private WorkflowBuilder(string processFlowTemplateId, string processFlowName)
1516
{
@@ -44,6 +45,18 @@ public WorkflowBuilder AddCMMNTask(string id, string name, Action<TaskBuilder> c
4445
return this;
4546
}
4647

48+
public WorkflowBuilder AddDiscretionaryTask(string id, string name, Action<TaskBuilder> callback, Action<TableItemBuilder> callbackTableItem)
49+
{
50+
var planItemDef = new CMMNTask(name);
51+
var processTask = PlanItemDefinition.New(id, name, planItemDef);
52+
callback(new TaskBuilder(processTask));
53+
var tableItem = new TableItem();
54+
callbackTableItem(new TableItemBuilder(tableItem));
55+
processTask.TableItem = tableItem;
56+
AddCMMNPlanItem(processTask);
57+
return this;
58+
}
59+
4760
public WorkflowBuilder AddTimerEventListener(string id, string name, Action<TimerEventListenerBuilder> callback)
4861
{
4962
var planItemDef = new TimerEventListener(name);
@@ -53,6 +66,18 @@ public WorkflowBuilder AddTimerEventListener(string id, string name, Action<Time
5366
return this;
5467
}
5568

69+
public WorkflowBuilder AddDiscretionaryTimerEventListener(string id, string name, Action<TimerEventListenerBuilder> callback, Action<TableItemBuilder> callbackTableItem)
70+
{
71+
var planItemDef = new TimerEventListener(name);
72+
var timer = PlanItemDefinition.New(id, name, planItemDef);
73+
callback(new TimerEventListenerBuilder(timer));
74+
var tableItem = new TableItem();
75+
callbackTableItem(new TableItemBuilder(tableItem));
76+
timer.TableItem = tableItem;
77+
AddCMMNPlanItem(timer);
78+
return this;
79+
}
80+
5681
public WorkflowBuilder AddCMMNMilestone(string id, string name, Action<MilestoneBuilder> callback)
5782
{
5883
var planItemDef = new Milestone(name);
@@ -62,6 +87,18 @@ public WorkflowBuilder AddCMMNMilestone(string id, string name, Action<Milestone
6287
return this;
6388
}
6489

90+
public WorkflowBuilder AddDiscretionaryMilestone(string id, string name, Action<MilestoneBuilder> callback, Action<TableItemBuilder> callbackTableItem)
91+
{
92+
var planItemDef = new Milestone(name);
93+
var milestone = PlanItemDefinition.New(id, name, planItemDef);
94+
callback(new MilestoneBuilder(milestone));
95+
var tableItem = new TableItem();
96+
callbackTableItem(new TableItemBuilder(tableItem));
97+
milestone.TableItem = tableItem;
98+
AddCMMNPlanItem(milestone);
99+
return this;
100+
}
101+
65102
public WorkflowBuilder AddCMMNHumanTask(string id, string name, Action<HumanTaskBuilder> callback)
66103
{
67104
var planItemDef = new HumanTask(name);
@@ -71,6 +108,18 @@ public WorkflowBuilder AddCMMNHumanTask(string id, string name, Action<HumanTask
71108
return this;
72109
}
73110

111+
public WorkflowBuilder AddDiscretionaryHumanTask(string id, string name, Action<HumanTaskBuilder> callback, Action<TableItemBuilder> callbackTableItem)
112+
{
113+
var planItemDef = new HumanTask(name);
114+
var humanTask = PlanItemDefinition.New(id, name, planItemDef);
115+
callback(new HumanTaskBuilder(humanTask));
116+
var tableItem = new TableItem();
117+
callbackTableItem(new TableItemBuilder(tableItem));
118+
humanTask.TableItem = tableItem;
119+
AddCMMNPlanItem(humanTask);
120+
return this;
121+
}
122+
74123
public WorkflowBuilder AddCaseFileItem(string id, string name, Action<CaseFileItemBuilder> callback)
75124
{
76125
var caseFile = new CaseFileItemDefinition(id, name);
@@ -88,6 +137,18 @@ public WorkflowBuilder AddCMMNProcessTask(string id, string name, Action<Process
88137
return this;
89138
}
90139

140+
public WorkflowBuilder AddDiscretionaryProcessTask(string id, string name, Action<ProcessTaskBuilder> callback, Action<TableItemBuilder> callbackTableItem)
141+
{
142+
var planItemDef = new ProcessTask(name);
143+
var processTask = PlanItemDefinition.New(id, name, planItemDef);
144+
callback(new ProcessTaskBuilder(processTask));
145+
var tableItem = new TableItem();
146+
callbackTableItem(new TableItemBuilder(tableItem));
147+
processTask.TableItem = tableItem;
148+
AddCMMNPlanItem(processTask);
149+
return this;
150+
}
151+
91152
public WorkflowBuilder AddExitCriteria(string name, Action<SEntryBuilder> callback)
92153
{
93154
var sEntry = new SEntry(name);
@@ -97,9 +158,15 @@ public WorkflowBuilder AddExitCriteria(string name, Action<SEntryBuilder> callba
97158
return this;
98159
}
99160

161+
public WorkflowBuilder SetCaseOwner(string caseOwner)
162+
{
163+
this._caseOwner = caseOwner;
164+
return this;
165+
}
166+
100167
public CaseDefinition Build()
101168
{
102-
var result = CaseDefinition.New(_processFlowTemplateId, _processFlowName, _processFlowName, _elements);
169+
var result = CaseDefinition.New(_processFlowTemplateId, _processFlowName, _processFlowName, _elements, _caseOwner);
103170
result.ExitCriterias = _exitCriterias;
104171
return result;
105172
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using CaseManagement.CMMN.CaseInstance.Commands;
2+
using CaseManagement.CMMN.CaseInstance.Exceptions;
3+
using CaseManagement.CMMN.Infrastructures;
4+
using CaseManagement.CMMN.Infrastructures.Bus;
5+
using CaseManagement.CMMN.Infrastructures.EvtStore;
6+
using CaseManagement.CMMN.Persistence;
7+
using CaseManagement.Workflow.Infrastructure.Bus;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Threading.Tasks;
11+
12+
namespace CaseManagement.CMMN.CaseInstance.CommandHandlers
13+
{
14+
public class ConfirmTableItemCommandHandler : IConfirmTableItemCommandHandler
15+
{
16+
private readonly IEventStoreRepository _eventStoreRepository;
17+
private readonly IRoleQueryRepository _roleQueryRepository;
18+
private readonly ICaseDefinitionQueryRepository _caseDefinitionQueryRepository;
19+
private readonly IQueueProvider _queueProvider;
20+
private readonly ICommitAggregateHelper _commitAggregateHelper;
21+
22+
public ConfirmTableItemCommandHandler(IEventStoreRepository eventStoreRepository, IRoleQueryRepository roleQueryRepository, ICaseDefinitionQueryRepository caseDefinitionQueryRepository, IQueueProvider queueProvider, ICommitAggregateHelper commitAggregateHelper)
23+
{
24+
_eventStoreRepository = eventStoreRepository;
25+
_roleQueryRepository = roleQueryRepository;
26+
_caseDefinitionQueryRepository = caseDefinitionQueryRepository;
27+
_queueProvider = queueProvider;
28+
_commitAggregateHelper = commitAggregateHelper;
29+
}
30+
31+
public async Task Handle(ConfirmTableItemCommand confirmPlanItemCommand)
32+
{
33+
var caseInstance = await _eventStoreRepository.GetLastAggregate<Domains.CaseInstance>(confirmPlanItemCommand.CaseInstanceId, Domains.CaseInstance.GetStreamName(confirmPlanItemCommand.CaseInstanceId));
34+
if (caseInstance == null || string.IsNullOrWhiteSpace(caseInstance.Id))
35+
{
36+
throw new UnknownCaseInstanceException(confirmPlanItemCommand.CaseInstanceId);
37+
}
38+
39+
var caseDefinition = await _caseDefinitionQueryRepository.FindById(caseInstance.CaseDefinitionId);
40+
var caseElementDef = caseDefinition.GetElement(confirmPlanItemCommand.CaseElementDefinitionId);
41+
if (caseElementDef == null)
42+
{
43+
throw new UnknownCaseElementDefinitionException(caseInstance.Id, confirmPlanItemCommand.CaseElementDefinitionId);
44+
}
45+
46+
if (caseElementDef.TableItem != null)
47+
{
48+
if (!string.IsNullOrWhiteSpace(caseElementDef.TableItem.AuthorizedRoleRef))
49+
{
50+
var roles = await _roleQueryRepository.FindRolesByUser(confirmPlanItemCommand.User);
51+
if (!roles.Any(r => r.Id == caseElementDef.TableItem.AuthorizedRoleRef))
52+
{
53+
throw new UnauthorizedCaseWorkerException(confirmPlanItemCommand.User, caseInstance.Id, confirmPlanItemCommand.CaseElementDefinitionId);
54+
}
55+
}
56+
}
57+
58+
caseInstance.ConfirmTableItem(confirmPlanItemCommand.CaseElementDefinitionId, confirmPlanItemCommand.User);
59+
if (caseInstance.IsRunning())
60+
{
61+
await _queueProvider.QueueConfirmTableItem(caseInstance.Id, confirmPlanItemCommand.CaseElementDefinitionId, confirmPlanItemCommand.User);
62+
}
63+
else
64+
{
65+
await _commitAggregateHelper.Commit(caseInstance, new List<DomainEvent> { caseInstance.DomainEvents.Last() }, caseInstance.Version, caseInstance.GetStreamName());
66+
}
67+
}
68+
}
69+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ public CreateCaseInstanceCommandHandler(ICaseDefinitionQueryRepository cmmnWorkf
3030
return workflowInstance;
3131
}
3232
}
33-
}
33+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using CaseManagement.CMMN.CaseInstance.Commands;
2+
using System.Threading.Tasks;
3+
4+
namespace CaseManagement.CMMN.CaseInstance.CommandHandlers
5+
{
6+
public interface IConfirmTableItemCommandHandler
7+
{
8+
Task Handle(ConfirmTableItemCommand confirmPlanItemCommand);
9+
}
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace CaseManagement.CMMN.CaseInstance.Commands
2+
{
3+
public class ConfirmTableItemCommand
4+
{
5+
public string CaseInstanceId { get; set; }
6+
public string CaseElementDefinitionId { get; set; }
7+
public string User { get; set; }
8+
}
9+
}

src/CaseManagement.CMMN/CaseInstance/EventHandlers/WorkflowInstanceHandler.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ namespace CaseManagement.CMMN.CaseInstance.EventHandlers
99
{
1010
public class WorkflowInstanceHandler : IDomainEventHandler<CaseInstanceCreatedEvent>, IDomainEventHandler<CaseElementCreatedEvent>, IDomainEventHandler<CaseElementFinishedEvent>,
1111
IDomainEventHandler<CaseElementInstanceFormCreatedEvent>, IDomainEventHandler<CaseElementInstanceFormSubmittedEvent>, IDomainEventHandler<CaseElementStartedEvent>,
12-
IDomainEventHandler<CaseElementTransitionRaisedEvent>, IDomainEventHandler<CaseTransitionRaisedEvent>, IDomainEventHandler<CaseInstanceVariableAddedEvent>
12+
IDomainEventHandler<CaseElementTransitionRaisedEvent>, IDomainEventHandler<CaseTransitionRaisedEvent>, IDomainEventHandler<CaseInstanceVariableAddedEvent>,
13+
IDomainEventHandler<CaseElementPlanificationConfirmedEvent>
1314
{
1415
private readonly ICaseInstanceCommandRepository _cmmnWorkflowInstanceCommandRepository;
1516
private readonly ICaseInstanceQueryRepository _cmmnWorkflowInstanceQueryRepository;
@@ -93,5 +94,13 @@ public async Task Handle(CaseInstanceVariableAddedEvent @event, CancellationToke
9394
_cmmnWorkflowInstanceCommandRepository.Update(flowInstance);
9495
await _cmmnWorkflowInstanceCommandRepository.SaveChanges();
9596
}
97+
98+
public async Task Handle(CaseElementPlanificationConfirmedEvent @event, CancellationToken cancellationToken)
99+
{
100+
var flowInstance = await _cmmnWorkflowInstanceQueryRepository.FindFlowInstanceById(@event.AggregateId);
101+
flowInstance.Handle(@event);
102+
_cmmnWorkflowInstanceCommandRepository.Update(flowInstance);
103+
await _cmmnWorkflowInstanceCommandRepository.SaveChanges();
104+
}
96105
}
97106
}

0 commit comments

Comments
 (0)