diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentController.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentController.java index a036ca94a0..2051eb46d1 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentController.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentController.java @@ -35,6 +35,7 @@ public class VisitDocumentController extends BaseRestController { private static final String INSUFFICIENT_PRIVILEGE = "Insufficient privilege"; private static final String INVALID_USER_PRIVILEGE = "User [%d] does not have required privilege to delete patient file [%s]"; private final String baseVisitDocumentUrl = "/rest/" + RestConstants.VERSION_1 + "/bahmnicore/visitDocument"; + @Autowired private VisitDocumentService visitDocumentService; @@ -62,23 +63,31 @@ public VisitDocumentResponse save(@RequestBody VisitDocumentRequest visitDocumen @RequestMapping(method = RequestMethod.POST, value = baseVisitDocumentUrl + "/uploadDocument") @ResponseBody - public HashMap saveDocument(@RequestBody Document document) { + public ResponseEntity> saveDocument(@RequestBody Document document) { try { - HashMap savedDocument = new HashMap<>(); + HashMap savedDocument = new HashMap<>(); Patient patient = Context.getPatientService().getPatientByUuid(document.getPatientUuid()); String encounterTypeName = document.getEncounterTypeName(); + Long maxDocumentSizeMb = Long.parseLong(System.getenv("DOCUMENT_MAX_SIZE_MB")); + Long maxDocumentSizeBytes = maxDocumentSizeMb * 1024 * 1024; + if (StringUtils.isEmpty(encounterTypeName)) { encounterTypeName = administrationService.getGlobalProperty("bahmni.encounterType.default"); } String fileName = sanitizeFileName(document.getFileName()); Paths.get(fileName); + if (document.getContent().length() > maxDocumentSizeBytes) { + logger.warn("Uploaded document size is greater than the maximum size " + maxDocumentSizeMb + "MB"); + savedDocument.put("maxDocumentSizeMB", maxDocumentSizeMb); + return new ResponseEntity<>(savedDocument, HttpStatus.PAYLOAD_TOO_LARGE); + } // Old files will follow: patientid-encounterName-uuid.ext (eg. 6-Patient-Document-706a448b-3f10-11e4-adec-0800271c1b75.png) // New ones will follow: patientid_encounterName_uuid__filename.ext (eg. 6-Patient-Document-706a448b-3f10-11e4-adec-0800271c1b75__doc1.png) String url = patientDocumentService.saveDocument(patient.getId(), encounterTypeName, document.getContent(), document.getFormat(), document.getFileType(), fileName); savedDocument.put("url", url); - return savedDocument; + return new ResponseEntity<>(savedDocument, HttpStatus.OK); } catch (Exception e) { throw new InvalidInputException("Could not save patient document", e); } diff --git a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentControllerTest.java b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentControllerTest.java index 1e03acc5f9..e0ed25b547 100644 --- a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentControllerTest.java +++ b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/controller/VisitDocumentControllerTest.java @@ -7,6 +7,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -29,13 +30,14 @@ import org.springframework.http.ResponseEntity; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import java.util.Base64; import java.util.HashMap; @PrepareForTest(Context.class) @@ -59,9 +61,15 @@ public class VisitDocumentControllerTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + @Rule + public final EnvironmentVariables environmentVariables + = new EnvironmentVariables(); + + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + environmentVariables.set("DOCUMENT_MAX_SIZE_MB","7"); } @Test @@ -189,9 +197,10 @@ public void shouldSaveIfFileNameNotWithSpecialCharsOtherThanDashAndUnderscoreIsP Document document = new Document("abcd", "jpeg", "consultation", "patient-uuid", "image", "file-name"); - HashMap mapWithUrl = visitDocumentController.saveDocument(document); + ResponseEntity> responseEntity = visitDocumentController.saveDocument(document); + HashMap mapWithUrl = responseEntity.getBody(); if (mapWithUrl!=null) { - String documentSavedPath = mapWithUrl.get("url"); + String documentSavedPath = (String) mapWithUrl.get("url"); if (documentSavedPath!=null) { assertTrue(documentSavedPath.endsWith("__file-name.jpeg")); } @@ -202,4 +211,52 @@ public void shouldSaveIfFileNameNotWithSpecialCharsOtherThanDashAndUnderscoreIsP verify(patientDocumentService, times(1)).saveDocument(1, "consultation", "abcd", "jpeg", document.getFileType(), document.getFileName()); } + @Test + public void shouldReturn413PayloadTooLargeIfDocumentSizeExceedsLimit() throws Exception { + PowerMockito.mockStatic(Context.class); + when(Context.getPatientService()).thenReturn(patientService); + + Patient patient = new Patient(); + patient.setId(1); + patient.setUuid("patient-uuid"); + when(patientService.getPatientByUuid("patient-uuid")).thenReturn(patient); + + when(administrationService.getGlobalProperty("bahmni.encounterType.default")).thenReturn("consultation"); + + Document document = new Document("abcd", "jpeg", null, "patient-uuid", "image", "file-name"); + + byte[] largeContent = new byte[8 * 1024 * 1024]; + String base64Content = Base64.getEncoder().encodeToString(largeContent); + document.setContent(base64Content); + System.out.println(document.getContent().length()); + + ResponseEntity> responseEntity = visitDocumentController.saveDocument(document); + + Assert.assertEquals(HttpStatus.PAYLOAD_TOO_LARGE, responseEntity.getStatusCode()); + } + + @Test + public void shouldSaveDocumentIfDocumentSizeIsLessThanSizeLimit() throws Exception { + PowerMockito.mockStatic(Context.class); + when(Context.getPatientService()).thenReturn(patientService); + + Patient patient = new Patient(); + patient.setId(1); + patient.setUuid("patient-uuid"); + when(patientService.getPatientByUuid("patient-uuid")).thenReturn(patient); + + when(administrationService.getGlobalProperty("bahmni.encounterType.default")).thenReturn("consultation"); + + Document document = new Document("abcd", "jpeg", null, "patient-uuid", "image", "file-name"); + + byte[] largeContent = new byte[2 * 1024 * 1024]; + String base64Content = Base64.getEncoder().encodeToString(largeContent); + document.setContent(base64Content); + + ResponseEntity> responseEntity = visitDocumentController.saveDocument(document); + + Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + + verify(patientDocumentService, times(1)).saveDocument(1, "consultation", base64Content, "jpeg", document.getFileType(), document.getFileName()); + } } diff --git a/pom.xml b/pom.xml index 1918cd8609..1b33d663f6 100644 --- a/pom.xml +++ b/pom.xml @@ -312,6 +312,12 @@ pom test + + com.github.stefanbirkner + system-rules + 1.19.0 + test + org.openmrs.tools openmrs-tools