Skip to content

Commit 29ec4b8

Browse files
committed
implement Classified to /validate endpoints
1 parent 72bf595 commit 29ec4b8

15 files changed

+642
-91
lines changed

build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ dependencies {
280280
testRuntimeOnly "org.junit.platform:junit-platform-commons:1.8.1"
281281
testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.6.0'
282282
testImplementation group:'org.mockito', name: 'mockito-junit-jupiter', version:'3.6.0'
283+
testImplementation 'org.mockito:mockito-inline:4.11.0'
283284
testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: powermockVersion
284285
testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion
285286
testImplementation group: 'io.rest-assured', name: 'rest-assured', version: '4.3.0'

src/aat/resources/features/F-1017 - Validate Event to Update TTL/F-1017.feature

+14-8
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ Feature: F-1017: Validate Event to Update TTL
252252
# #CCD-3535 & #CCD-3562: Trigger a mid-event callback that makes permitted changes to the TTL values: v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1
253253
#-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
254254

255-
@S-1017.21 #CCD-3535
255+
@S-1017.21 @Ignore #CCD-3535
256256
Scenario: Trigger a mid event callback that changes TTL.Suspended (null -> missing). Mid Event is invoked on v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1
257257
Given a user with [an active profile in CCD]
258258
And a user with [a caseworker with an active profile in CCD]
@@ -270,9 +270,11 @@ Feature: F-1017: Validate Event to Update TTL
270270

271271
Then a positive response is received
272272
And the response has all other details as expected
273-
And the response [does not contain the TTL as citizen user has no access]
273+
And the response [contains the TTL.SystemTTL for the case, that has been set to 20 days from today]
274+
And the response [contains the TTL.OverrideTTL from the previouse data]
275+
And the response [does not contain the TTL.Suspended as removed by callback (null -> missing)]
274276

275-
@S-1017.22 #CCD-3535
277+
@S-1017.22 @Ignore #CCD-3535
276278
Scenario: Trigger a mid event callback that changes TTL.Suspended (No -> NO). Mid Event is invoked on v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1
277279
Given a user with [an active profile in CCD]
278280
And a user with [a caseworker with an active profile in CCD]
@@ -291,9 +293,11 @@ Feature: F-1017: Validate Event to Update TTL
291293

292294
Then a positive response is received
293295
And the response has all other details as expected
294-
And the response [does not contain the TTL as citizen user has no access]
296+
And the response [contains the TTL.SystemTTL for the case, that has been set to 20 days from today]
297+
And the response [does not contain the TTL.OverrideTTL as removed by callback (null -> missing)]
298+
And the response [contains the adjusted TTL.Suspended from the callback (No -> NO)]
295299

296-
@S-1017.23 #CCD-3535
300+
@S-1017.23 @Ignore #CCD-3535
297301
Scenario: Trigger a mid event callback that changes TTL.Suspended (Yes -> YES). Mid Event is invoked on v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1
298302
Given a user with [an active profile in CCD]
299303
And a user with [a caseworker with an active profile in CCD]
@@ -312,10 +316,12 @@ Feature: F-1017: Validate Event to Update TTL
312316

313317
Then a positive response is received
314318
And the response has all other details as expected
315-
And the response [does not contain the TTL as citizen user has no access]
319+
And the response [contains the TTL.SystemTTL for the case, that has been set to 20 days from today]
320+
And the response [does not contain the TTL.OverrideTTL as removed by callback (null -> missing)]
321+
And the response [contains the adjusted TTL.Suspended from the callback (Yes -> YES)]
316322

317323

318-
@S-1017.25 #CCD-3562
324+
@S-1017.25 @Ignore #CCD-3562
319325
Scenario: Trigger a mid event callback that has TTL missing. Mid Event is invoked on v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1
320326
Given a user with [an active profile in CCD]
321327
And a successful call [to create a case] as in [CreateCase_TTLCaseType_PreRequisiteCitizen]
@@ -329,7 +335,7 @@ Feature: F-1017: Validate Event to Update TTL
329335

330336
Then a positive response is received
331337
And the response has all other details as expected
332-
And the response [does not contain the TTL as citizen user has no access]
338+
And the response [contains the TTL.SystemTTL for the case, that has been set to 20 days from today]
333339

334340
@S-1017.26 #CCD-3562
335341
Scenario: Trigger a mid event callback that changes TTL set to null. Mid Event is invoked on v1_external#/citizen/case-details-endpoint/validateCaseDetailsUsingPOST_1

src/aat/resources/features/F-1017 - Validate Event to Update TTL/S-1017.21.td.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
"has a TTLIncrement of 20 days configured",
1919
"is configured to trigger a mid event callback that changes the TTL.Suspended value (null -> missing)",
2020

21-
"does not contain the TTL as citizen user has no access"
21+
"contains the TTL.SystemTTL for the case, that has been set to 20 days from today",
22+
"contains the TTL.OverrideTTL from the previouse data",
23+
"does not contain the TTL.Suspended as removed by callback (null -> missing)"
2224
],
2325

2426
"users": {

src/aat/resources/features/F-1017 - Validate Event to Update TTL/S-1017.22.td.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"is configured to trigger a mid event callback that changes the TTL.OverrideTTL value (null -> missing)",
2020
"is configured to trigger a mid event callback that changes the TTL.Suspended value (No -> NO)",
2121

22-
"does not contain the TTL as citizen user has no access"
22+
"contains the TTL.SystemTTL for the case, that has been set to 20 days from today",
23+
"does not contain the TTL.OverrideTTL as removed by callback (null -> missing)",
24+
"contains the adjusted TTL.Suspended from the callback (No -> NO)"
2325
],
2426

2527
"users": {

src/aat/resources/features/F-1017 - Validate Event to Update TTL/S-1017.23.td.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"is configured to trigger a mid event callback that changes the TTL.OverrideTTL value (null -> missing)",
2020
"is configured to trigger a mid event callback that changes the TTL.Suspended value (Yes -> YES)",
2121

22-
"does not contain the TTL as citizen user has no access"
22+
"contains the TTL.SystemTTL for the case, that has been set to 20 days from today",
23+
"does not contain the TTL.OverrideTTL as removed by callback (null -> missing)",
24+
"contains the adjusted TTL.Suspended from the callback (Yes -> YES)"
2325
],
2426

2527
"users": {

src/aat/resources/features/F-1017 - Validate Event to Update TTL/S-1017.25.td.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"has a TTLIncrement of 20 days configured",
1717
"is configured to trigger a mid event callback that responds with TTL missing",
1818

19-
"does not contain the TTL as citizen user has no access"
19+
"contains the TTL.SystemTTL for the case, that has been set to 20 days from today"
2020
],
2121

2222
"users": {

src/main/java/uk/gov/hmcts/ccd/domain/service/createevent/MidEventCallback.java

+4-15
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package uk.gov.hmcts.ccd.domain.service.createevent;
22

33
import com.fasterxml.jackson.databind.JsonNode;
4-
import com.fasterxml.jackson.databind.ObjectMapper;
5-
import com.fasterxml.jackson.databind.node.ObjectNode;
4+
65
import java.util.Map;
76
import java.util.Optional;
87
import java.util.Set;
@@ -52,9 +51,7 @@ public MidEventCallback(CallbackInvoker callbackInvoker,
5251
}
5352

5453
@Transactional
55-
public JsonNode invoke(String caseTypeId,
56-
CaseDataContent content,
57-
String pageId) {
54+
public Map<String, JsonNode> invoke(String caseTypeId, CaseDataContent content, String pageId) {
5855
if (!isBlank(pageId)) {
5956
Event event = content.getEvent();
6057
final CaseTypeDefinition caseTypeDefinition = getCaseType(caseTypeId);
@@ -91,11 +88,10 @@ public JsonNode invoke(String caseTypeId,
9188
caseDetailsBefore,
9289
currentOrNewCaseDetails,
9390
content.getIgnoreWarning());
94-
95-
return dataJsonNode(caseDetailsFromMidEventCallback.getData());
91+
return caseDetailsFromMidEventCallback.getData();
9692
}
9793
}
98-
return dataJsonNode(content.getData());
94+
return content.getData();
9995
}
10096

10197
private void removeNextPageFieldData(CaseDetails currentCaseDetails, Integer order,
@@ -112,13 +108,6 @@ private void removeNextPageFieldData(CaseDetails currentCaseDetails, Integer ord
112108
}
113109
}
114110

115-
private JsonNode dataJsonNode(Map<String, JsonNode> data) {
116-
ObjectMapper mapper = new ObjectMapper();
117-
ObjectNode objectNode = mapper.createObjectNode();
118-
objectNode.set("data", mapper.valueToTree(data));
119-
return objectNode;
120-
}
121-
122111
private CaseTypeDefinition getCaseType(String caseTypeId) {
123112
final CaseTypeDefinition caseTypeDefinition = caseDefinitionRepository.getCaseType(caseTypeId);
124113
if (caseTypeDefinition == null) {

src/main/java/uk/gov/hmcts/ccd/domain/service/validate/AuthorisedValidateCaseFieldsOperation.java

+8-14
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
1414
import uk.gov.hmcts.ccd.domain.service.common.AccessControlService;
1515
import uk.gov.hmcts.ccd.domain.service.common.CaseAccessService;
16-
import uk.gov.hmcts.ccd.domain.service.createevent.MidEventCallback;
1716
import uk.gov.hmcts.ccd.endpoint.exceptions.ValidationException;
1817

1918
import java.util.Map;
@@ -32,20 +31,17 @@ public class AuthorisedValidateCaseFieldsOperation implements ValidateCaseFields
3231
private final CaseDefinitionRepository caseDefinitionRepository;
3332
private final CaseAccessService caseAccessService;
3433
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
35-
private final MidEventCallback midEventCallback;
3634

3735
public AuthorisedValidateCaseFieldsOperation(AccessControlService accessControlService,
3836
@Qualifier(CachedCaseDefinitionRepository.QUALIFIER)
3937
CaseDefinitionRepository caseDefinitionRepository,
4038
CaseAccessService caseAccessService,
41-
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
42-
ValidateCaseFieldsOperation validateCaseFieldsOperation,
43-
MidEventCallback midEventCallback) {
39+
@Qualifier(ClassifiedValidateCaseFieldsOperation.QUALIFIER)
40+
ValidateCaseFieldsOperation validateCaseFieldsOperation) {
4441
this.accessControlService = accessControlService;
4542
this.caseDefinitionRepository = caseDefinitionRepository;
4643
this.caseAccessService = caseAccessService;
4744
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
48-
this.midEventCallback = midEventCallback;
4945
}
5046

5147
@Override
@@ -54,13 +50,6 @@ public Map<String, JsonNode> validateCaseDetails(OperationContext operationConte
5450

5551
CaseDataContent content = operationContext.content();
5652
String caseTypeId = operationContext.caseTypeId();
57-
String pageId = operationContext.pageId();
58-
59-
final JsonNode data = midEventCallback.invoke(caseTypeId,
60-
content,
61-
pageId);
62-
63-
content.setData(JacksonUtils.convertValue(data));
6453

6554
String caseReference = content.getCaseReference();
6655
Set<AccessProfile> accessProfiles = StringUtils.isNotEmpty(caseReference)
@@ -81,6 +70,11 @@ public void validateData(Map<String, JsonNode> data, CaseTypeDefinition caseType
8170
private void verifyReadAccess(final String caseTypeId, CaseDataContent content, Set<AccessProfile> accessProfiles) {
8271
final CaseTypeDefinition caseTypeDefinition = getCaseDefinitionType(caseTypeId);
8372

73+
if (content.getData() == null) {
74+
content.setData(newHashMap());
75+
return;
76+
}
77+
8478
if (!accessControlService.canAccessCaseTypeWithCriteria(
8579
caseTypeDefinition,
8680
accessProfiles,
@@ -91,7 +85,7 @@ private void verifyReadAccess(final String caseTypeId, CaseDataContent content,
9185

9286
content.setData(JacksonUtils.convertValueInDataField(
9387
accessControlService.filterCaseFieldsByAccess(
94-
JacksonUtils.convertValueJsonNode(content.getData().get(JacksonUtils.DATA)),
88+
JacksonUtils.convertValueJsonNode(content.getData()),
9589
caseTypeDefinition.getCaseFieldDefinitions(),
9690
accessProfiles,
9791
CAN_READ,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package uk.gov.hmcts.ccd.domain.service.validate;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.springframework.beans.factory.annotation.Qualifier;
6+
import org.springframework.stereotype.Service;
7+
import uk.gov.hmcts.ccd.data.definition.CachedCaseDefinitionRepository;
8+
import uk.gov.hmcts.ccd.data.definition.CaseDefinitionRepository;
9+
import uk.gov.hmcts.ccd.domain.model.definition.CaseDetails;
10+
import uk.gov.hmcts.ccd.domain.model.definition.CaseTypeDefinition;
11+
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
12+
import uk.gov.hmcts.ccd.domain.service.common.CaseDataService;
13+
import uk.gov.hmcts.ccd.domain.service.common.CaseService;
14+
import uk.gov.hmcts.ccd.domain.service.common.SecurityClassificationServiceImpl;
15+
import uk.gov.hmcts.ccd.domain.service.createevent.MidEventCallback;
16+
import uk.gov.hmcts.ccd.endpoint.exceptions.ValidationException;
17+
18+
import java.util.Map;
19+
20+
import static com.google.common.collect.Maps.newHashMap;
21+
import static java.util.Optional.ofNullable;
22+
23+
@Service
24+
@Qualifier(ClassifiedValidateCaseFieldsOperation.QUALIFIER)
25+
public class ClassifiedValidateCaseFieldsOperation implements ValidateCaseFieldsOperation {
26+
public static final String QUALIFIER = "classified";
27+
28+
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
29+
private final SecurityClassificationServiceImpl classificationService;
30+
private final MidEventCallback midEventCallback;
31+
private final CaseDataService caseDataService;
32+
private final CaseDefinitionRepository caseDefinitionRepository;
33+
private final CaseService caseService;
34+
35+
36+
37+
public ClassifiedValidateCaseFieldsOperation(@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
38+
ValidateCaseFieldsOperation validateCaseFieldsOperation,
39+
SecurityClassificationServiceImpl classificationService,
40+
MidEventCallback midEventCallback, CaseDataService caseDataService,
41+
@Qualifier(CachedCaseDefinitionRepository.QUALIFIER)
42+
CaseDefinitionRepository caseDefinitionRepository,
43+
CaseService caseService) {
44+
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
45+
this.classificationService = classificationService;
46+
this.midEventCallback = midEventCallback;
47+
this.caseDataService = caseDataService;
48+
this.caseDefinitionRepository = caseDefinitionRepository;
49+
this.caseService = caseService;
50+
}
51+
52+
@Override
53+
public Map<String, JsonNode> validateCaseDetails(OperationContext operationContext) {
54+
validateCaseFieldsOperation.validateCaseDetails(operationContext);
55+
56+
CaseDataContent content = operationContext.content();
57+
String caseTypeId = operationContext.caseTypeId();
58+
String pageId = operationContext.pageId();
59+
60+
61+
final Map<String, JsonNode> callbackData = midEventCallback.invoke(caseTypeId,
62+
content,
63+
pageId);
64+
65+
CaseTypeDefinition caseTypeDefinition = getCaseDefinitionType(caseTypeId);
66+
67+
CaseGenerationResult caseDetailsAndIsCreate = generateOrRetrieveCaseDetails(operationContext, caseTypeDefinition,
68+
callbackData);
69+
70+
CaseDetails classifiedCaseDetails =
71+
classificationService.applyClassification(caseDetailsAndIsCreate.caseDetails(),
72+
caseDetailsAndIsCreate.isCreate()).orElse(new CaseDetails());
73+
74+
content.setData(classifiedCaseDetails.getData());
75+
76+
return content.getData();
77+
}
78+
79+
@Override
80+
public void validateData(Map<String, JsonNode> data, CaseTypeDefinition caseTypeDefinition,
81+
CaseDataContent content) {
82+
validateCaseFieldsOperation.validateData(data, caseTypeDefinition, content);
83+
}
84+
85+
private CaseGenerationResult generateOrRetrieveCaseDetails(OperationContext operationContext,
86+
CaseTypeDefinition caseTypeDefinition,
87+
Map<String, JsonNode> callbackData){
88+
CaseDetails caseDetails;
89+
boolean isCreate;
90+
if (StringUtils.isNotEmpty(operationContext.content().getCaseReference())) {
91+
isCreate = false;
92+
caseDetails =
93+
caseService.getCaseDetails(caseTypeDefinition.getJurisdictionId(),
94+
operationContext.content().getCaseReference());
95+
} else {
96+
isCreate = true;
97+
caseDetails = new CaseDetails();
98+
caseDetails.setCaseTypeId(operationContext.caseTypeId());
99+
caseDetails.setSecurityClassification(caseTypeDefinition.getSecurityClassification());
100+
}
101+
102+
caseDetails.setData(callbackData);
103+
deduceDataClassificationForNewFields(caseTypeDefinition, caseDetails);
104+
105+
return new CaseGenerationResult(caseDetails, isCreate);
106+
}
107+
108+
private CaseTypeDefinition getCaseDefinitionType(String caseTypeId) {
109+
final CaseTypeDefinition caseTypeDefinition = caseDefinitionRepository.getCaseType(caseTypeId);
110+
if (caseTypeDefinition == null) {
111+
throw new ValidationException("Cannot find case type definition for " + caseTypeId);
112+
}
113+
return caseTypeDefinition;
114+
}
115+
116+
private void deduceDataClassificationForNewFields(CaseTypeDefinition caseTypeDefinition, CaseDetails caseDetails) {
117+
Map<String, JsonNode> defaultSecurityClassifications = caseDataService.getDefaultSecurityClassifications(
118+
caseTypeDefinition,
119+
caseDetails.getData(),
120+
ofNullable(caseDetails.getDataClassification()).orElse(
121+
newHashMap()));
122+
caseDetails.setDataClassification(defaultSecurityClassifications);
123+
}
124+
125+
private record CaseGenerationResult(CaseDetails caseDetails, boolean isCreate) {}
126+
127+
}

src/main/java/uk/gov/hmcts/ccd/domain/service/validate/ValidateCaseFieldsOperation.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
public interface ValidateCaseFieldsOperation {
1010

11-
Map<String, JsonNode> validateCaseDetails(OperationContext validationContext);
11+
Map<String, JsonNode> validateCaseDetails(OperationContext operationContext);
1212

1313
void validateData(final Map<String, JsonNode> data,
1414
final CaseTypeDefinition caseTypeDefinition,

0 commit comments

Comments
 (0)