From 300179447393f3f76189d02270ec4028a0dae7b7 Mon Sep 17 00:00:00 2001
From: ruhanga <ruhanganathan@gmail.com>
Date: Wed, 21 Nov 2018 15:59:18 +0300
Subject: [PATCH] RESTWS-641: Add support for MIME types when posting
 complexObs value in json request

---
 .../resource/openmrs1_8/ObsResource1_8.java   |  18 ++-
 .../openmrs2_0/ObsController2_0Test.java      | 120 ++++++++++++++++++
 .../test/resources/ComplexObsTestImage.png    | Bin 0 -> 82 bytes
 3 files changed, 136 insertions(+), 2 deletions(-)
 create mode 100644 omod-2.0/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs2_0/ObsController2_0Test.java
 create mode 100644 omod-2.0/src/test/resources/ComplexObsTestImage.png

diff --git a/omod-1.8/src/main/java/org/openmrs/module/webservices/rest/web/v1_0/resource/openmrs1_8/ObsResource1_8.java b/omod-1.8/src/main/java/org/openmrs/module/webservices/rest/web/v1_0/resource/openmrs1_8/ObsResource1_8.java
index 098f808c7..5619b4576 100644
--- a/omod-1.8/src/main/java/org/openmrs/module/webservices/rest/web/v1_0/resource/openmrs1_8/ObsResource1_8.java
+++ b/omod-1.8/src/main/java/org/openmrs/module/webservices/rest/web/v1_0/resource/openmrs1_8/ObsResource1_8.java
@@ -388,10 +388,24 @@ public static void setConcept(Obs obs, Object value) {
 	public static void setValue(Obs obs, Object value) throws ParseException, ConversionException, IOException {
 		if (value != null) {
 			if (obs.isComplex()) {
-				byte[] bytes = DatatypeConverter.parseBase64Binary(value.toString());
+				byte[] bytes = null;
 				
-				ComplexData complexData = new ComplexData(obs.getUuid() + ".raw", new ByteArrayInputStream(bytes));
+				String extension = "raw";
+				//Try to extract extension from the MIME type if it is provided in value
+				if (value.toString().startsWith("data:")) {
+					String dataUri = value.toString();
+					String mimeType = (dataUri.split(":", 2)[1]).split(";", 2)[0];
+					bytes = DatatypeConverter.parseBase64Binary(dataUri.split(",", 2)[1]);
+					extension = mimeType.toLowerCase().split("/")[1];
+					//extensions with hyphen within them are not supported, instead "raw" is used
+					extension = extension.contains("-") ? "raw" : extension;
+				} else {
+					//no MIME type provided
+					bytes = DatatypeConverter.parseBase64Binary(value.toString());
+				}
+				ComplexData complexData = new ComplexData(obs.getUuid() + "." + extension, new ByteArrayInputStream(bytes));
 				obs.setComplexData(complexData);
+				
 			} else if (obs.getConcept().getDatatype().isCoded()) {
 				// setValueAsString is not implemented for coded obs (in core)
 				
diff --git a/omod-2.0/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs2_0/ObsController2_0Test.java b/omod-2.0/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs2_0/ObsController2_0Test.java
new file mode 100644
index 000000000..1d6156788
--- /dev/null
+++ b/omod-2.0/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs2_0/ObsController2_0Test.java
@@ -0,0 +1,120 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
+ * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
+ *
+ * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
+ * graphic logo is a trademark of OpenMRS Inc.
+ */
+package org.openmrs.module.webservices.rest.web.v1_0.controller.openmrs2_0;
+
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.junit.Assert;
+import org.junit.Test;
+import org.openmrs.ConceptComplex;
+import org.openmrs.ConceptName;
+import org.openmrs.GlobalProperty;
+import org.openmrs.api.AdministrationService;
+import org.openmrs.api.ConceptService;
+import org.openmrs.api.context.Context;
+import org.openmrs.module.webservices.rest.SimpleObject;
+import org.openmrs.module.webservices.rest.test.Util;
+import org.openmrs.module.webservices.rest.web.RestTestConstants1_8;
+import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException;
+import org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceControllerTest;
+import org.openmrs.util.OpenmrsConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.mock.web.MockMultipartHttpServletRequest;
+import javax.imageio.ImageIO;
+import javax.xml.bind.DatatypeConverter;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+import static org.junit.Assert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.equalTo;
+
+public class ObsController2_0Test extends MainResourceControllerTest {
+	
+	@Autowired
+	ConceptService conceptService;
+	
+	@Autowired
+	AdministrationService adminService;
+	
+	/**
+	 * @see org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceControllerTest#getURI()
+	 */
+	@Override
+	public String getURI() {
+		return "obs";
+	}
+	
+	@Override
+	public long getAllCount() {
+		return Context.getObsService().getObservationCount(null, true);
+	}
+	
+	/**
+	 * @see org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceControllerTest#getUuid()
+	 */
+	@Override
+	public String getUuid() {
+		return RestTestConstants1_8.OBS_UUID;
+	}
+	
+	/**
+	 * @see org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceControllerTest#shouldGetAll()
+	 */
+	@Override
+	@Test(expected = ResourceDoesNotSupportOperationException.class)
+	public void shouldGetAll() throws Exception {
+		super.shouldGetAll();
+	}
+	
+	@Test
+	public void shouldSupportMimeTypesWhenPostingBase64Binary() throws Exception {
+		ConceptComplex conceptComplex = newConceptComplex();
+		
+		InputStream in = getClass().getClassLoader().getResourceAsStream("ComplexObsTestImage.png");
+		
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		ImageIO.write(ImageIO.read(in), "png", out);
+		
+		String value = DatatypeConverter.printBase64Binary(out.toByteArray());
+		String contentType = "image/png";
+		
+		String json = "{\"concept\":\"" + conceptComplex.getUuid() + "\"," + "\"value\":\"" + "data:"
+		        + contentType + ";base64," + value + "\",\"person\":\"5946f880-b197-400b-9caa-a3c661d23041\","
+		        + "\"obsDatetime\":\"2015-09-07T00:00:00.000+0530\"}";
+		
+		SimpleObject response = deserialize(handle(newPostRequest(getURI(), json)));
+		
+		MockHttpServletResponse rawResponse = handle(newGetRequest(getURI() + "/" + response.get("uuid") + "/value"));
+		
+		assertThat(contentType, is(equalTo(rawResponse.getContentType())));
+		assertThat(out.toByteArray(), is(equalTo(rawResponse.getContentAsByteArray())));
+	}
+	
+	private ConceptComplex newConceptComplex() {
+		setupBinaryDataHandler();
+		
+		ConceptComplex conceptComplex = new ConceptComplex();
+		conceptComplex.setHandler("ImageHandler");
+		conceptComplex.addName(new ConceptName("Xml Test Data", Locale.ENGLISH));
+		conceptComplex.setDatatype(conceptService.getConceptDatatypeByName("Complex"));
+		conceptComplex.setConceptClass(conceptService.getConceptClassByName("Misc"));
+		conceptService.saveConcept(conceptComplex);
+		return conceptComplex;
+	}
+	
+	private void setupBinaryDataHandler() {
+		adminService.saveGlobalProperty(new GlobalProperty("obs.complex_obs_dir", "complexObsDir"));
+	}
+}
diff --git a/omod-2.0/src/test/resources/ComplexObsTestImage.png b/omod-2.0/src/test/resources/ComplexObsTestImage.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c9a1d9f373b1327bb696de17783997e3a3a5eb4
GIT binary patch
literal 82
zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga%mF?juK#@*VoWXSfm|+67srr_
bImt;tHX8%8nR(3$AdA7%)z4*}Q$iB}P&yD{

literal 0
HcmV?d00001