Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/main/java/com/augment/cbsa/web/delacc/DelaccController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.augment.cbsa.web.delacc;

import com.augment.cbsa.config.CbsaProperties;
import com.augment.cbsa.domain.AccountDetails;
import com.augment.cbsa.domain.DelaccRequest;
import com.augment.cbsa.domain.DelaccResult;
import com.augment.cbsa.service.DelaccService;
import com.augment.cbsa.web.delacc.dto.DelaccCommareaRequestDto;
import com.augment.cbsa.web.delacc.dto.DelaccCommareaResponseDto;
import com.augment.cbsa.web.delacc.dto.DelaccRequestDto;
import com.augment.cbsa.web.delacc.dto.DelaccResponseDto;
Expand Down Expand Up @@ -33,9 +35,11 @@ public class DelaccController {
private static final DateTimeFormatter COBOL_DATE_FORMATTER = DateTimeFormatter.ofPattern("ddMMyyyy", Locale.ROOT);

private final DelaccService delaccService;
private final CbsaProperties cbsaProperties;

public DelaccController(DelaccService delaccService) {
public DelaccController(DelaccService delaccService, CbsaProperties cbsaProperties) {
this.delaccService = Objects.requireNonNull(delaccService, "delaccService must not be null");
this.cbsaProperties = Objects.requireNonNull(cbsaProperties, "cbsaProperties must not be null");
}

@DeleteMapping("/remove/{accno}")
Expand All @@ -48,6 +52,15 @@ public ResponseEntity<?> delete(
) {
Objects.requireNonNull(requestDto, "requestDto must not be null");

// The body's DelAccAccno and DelAccScode are optional (patterns allow ""
// / null). When present they must agree with the path account number
// and the configured branch sortcode so a misaddressed request can
// never silently delete the path target.
ProblemDetail mismatch = validateBodyAgainstPath(requestDto.delAcc(), accountNumber);
if (mismatch != null) {
return ResponseEntity.badRequest().body(mismatch);
}

DelaccResult result = delaccService.delete(new DelaccRequest(accountNumber));
if (!result.deleteSuccess()) {
return ResponseEntity.status(failureStatus(result)).body(failureBody(result));
Expand All @@ -56,6 +69,26 @@ public ResponseEntity<?> delete(
return ResponseEntity.ok(toResponse(result));
}

private ProblemDetail validateBodyAgainstPath(DelaccCommareaRequestDto delAcc, long pathAccountNumber) {
Long bodyAccno = delAcc.delAccAccno();
if (bodyAccno != null && bodyAccno != pathAccountNumber) {
return mismatch("Body DelAccAccno does not match path accno.");
}
String bodyScode = delAcc.delAccScode();
if (bodyScode != null && !bodyScode.isEmpty()
&& !bodyScode.equals(cbsaProperties.sortcode())) {
return mismatch("Body DelAccScode does not match the configured branch sortcode.");
}
return null;
}

private ProblemDetail mismatch(String detail) {
ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
problemDetail.setTitle("Validation failed");
problemDetail.setDetail(detail);
return problemDetail;
}

private HttpStatus failureStatus(DelaccResult result) {
if (result.isNotFoundFailure()) {
return HttpStatus.NOT_FOUND;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import java.time.LocalDate;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.Matchers.containsString;
Expand All @@ -26,6 +28,8 @@

@WebMvcTest(DelaccController.class)
@Import(CbsaExceptionHandler.class)
@EnableConfigurationProperties(com.augment.cbsa.config.CbsaProperties.class)
@TestPropertySource(properties = "cbsa.sortcode=987654")
class DelaccControllerWebMvcTest {

@Autowired
Expand Down Expand Up @@ -88,6 +92,47 @@ void requestValidationFailuresRemainProblemDetails() throws Exception {
.andExpect(jsonPath("$.title").value("Validation failed"));
}

@Test
void rejectsBodyAccnoThatMismatchesPath() throws Exception {
String body = requestJson().replace("\"DelAccAccno\": 12345678", "\"DelAccAccno\": 99999999");
mockMvc.perform(delete("/api/v1/delacc/remove/12345678").contentType(APPLICATION_JSON).content(body))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.title").value("Validation failed"))
.andExpect(jsonPath("$.detail").value("Body DelAccAccno does not match path accno."));
}

@Test
void rejectsBodyScodeThatMismatchesConfiguredSortcode() throws Exception {
String body = requestJson().replace("\"DelAccScode\": \"987654\"", "\"DelAccScode\": \"123456\"");
mockMvc.perform(delete("/api/v1/delacc/remove/12345678").contentType(APPLICATION_JSON).content(body))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.title").value("Validation failed"))
.andExpect(jsonPath("$.detail").value("Body DelAccScode does not match the configured branch sortcode."));
}

@Test
void allowsEmptyOrNullBodyKeyFields() throws Exception {
when(delaccService.delete(new DelaccRequest(12345678L))).thenReturn(DelaccResult.success(new AccountDetails(
"987654",
10L,
12345678L,
"ISA",
new BigDecimal("1.50"),
LocalDate.of(2024, 1, 2),
new BigDecimal("250.00"),
LocalDate.of(2024, 2, 3),
LocalDate.of(2024, 3, 4),
new BigDecimal("1500.25"),
new BigDecimal("1499.75")
)));

String body = requestJson()
.replace("\"DelAccAccno\": 12345678,", "")
.replace("\"DelAccScode\": \"987654\"", "\"DelAccScode\": \"\"");
mockMvc.perform(delete("/api/v1/delacc/remove/12345678").contentType(APPLICATION_JSON).content(body))
.andExpect(status().isOk());
}

@Test
void redactsAbendExceptionMessageFromResponseBody() throws Exception {
when(delaccService.delete(new DelaccRequest(12345678L)))
Expand Down
Loading