Skip to content

Commit a44a9d3

Browse files
committed
O3-310: allow Put operations on an application-writable config.json file
There should be a `config.json` file that the application is allowed to manage, which lives in the application data directory.
1 parent 417b277 commit a44a9d3

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* This Source Code Form is subject to the terms of the Mozilla Public License,
3+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
4+
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5+
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6+
*
7+
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8+
* graphic logo is a trademark of OpenMRS Inc.
9+
*/
10+
package org.openmrs.module.webservices.rest.web.v1_0.controller.openmrs1_9;
11+
12+
import java.io.BufferedReader;
13+
import java.io.ByteArrayInputStream;
14+
import java.io.IOException;
15+
import java.io.File;
16+
import java.io.FileInputStream;
17+
import java.io.InputStream;
18+
import java.io.OutputStream;
19+
import java.nio.file.Files;
20+
import java.nio.charset.StandardCharsets;
21+
import javax.servlet.http.HttpServletRequest;
22+
import javax.servlet.http.HttpServletResponse;
23+
24+
import org.openmrs.User;
25+
import org.openmrs.api.AdministrationService;
26+
import org.openmrs.api.context.Context;
27+
import org.openmrs.module.webservices.rest.web.RestConstants;
28+
import org.openmrs.module.webservices.rest.web.v1_0.controller.BaseRestController;
29+
import org.openmrs.util.OpenmrsUtil;
30+
import org.slf4j.Logger;
31+
import org.slf4j.LoggerFactory;
32+
import org.springframework.http.HttpStatus;
33+
import org.springframework.stereotype.Controller;
34+
import org.springframework.web.bind.annotation.RequestMapping;
35+
import org.springframework.web.bind.annotation.RequestMethod;
36+
import org.springframework.web.bind.annotation.ResponseStatus;
37+
import org.codehaus.jackson.JsonProcessingException;
38+
import org.codehaus.jackson.map.ObjectMapper;
39+
40+
@Controller
41+
@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/frontend/config.json")
42+
public class FrontendJsonConfigController1_9 extends BaseRestController {
43+
44+
private static final String DEFAULT_FRONTEND_DIRECTORY = "frontend";
45+
private static final String GP_LOCAL_DIRECTORY = "spa.local.directory";
46+
private static final String JSON_CONFIG_FILE_NAME = "config.json";
47+
48+
private static final Logger log = LoggerFactory.getLogger(FrontendJsonConfigController1_9.class);
49+
50+
@RequestMapping(method = RequestMethod.GET)
51+
public void getFrontendConfigFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
52+
File jsonConfigFile = getJsonConfigFile();
53+
if (!jsonConfigFile.exists()) {
54+
log.debug("Configuration file does not exist");
55+
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Configuration file does not exist");
56+
}
57+
try {
58+
InputStream inputStream = new FileInputStream(jsonConfigFile);
59+
OutputStream outStream = response.getOutputStream();
60+
OpenmrsUtil.copyFile(inputStream, outStream);
61+
62+
response.setContentType("application/json");
63+
response.setHeader("Content-Disposition", "attachment; filename=" + jsonConfigFile.getName());
64+
response.setStatus(HttpServletResponse.SC_OK);
65+
} catch (IOException e) {
66+
log.error("Error reading Configuration file: " + jsonConfigFile.getAbsolutePath(), e);
67+
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error reading Configuration file: " + jsonConfigFile.getPath());
68+
}
69+
}
70+
71+
@RequestMapping(method = RequestMethod.POST)
72+
@ResponseStatus(HttpStatus.OK)
73+
public void saveFrontendConfigFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
74+
User user = Context.getAuthenticatedUser();
75+
if (user == null || !user.isSuperUser()) {
76+
log.error("Authorization error while creating a config.json file");
77+
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Authorization error while creating a config.json file");
78+
return;
79+
}
80+
saveJsonConfigFile(request, response);
81+
}
82+
83+
private void saveJsonConfigFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
84+
File jsonConfigFile = getJsonConfigFile();
85+
try {
86+
BufferedReader reader = request.getReader();
87+
StringBuilder stringBuilder = new StringBuilder();
88+
String line;
89+
while ((line = reader.readLine()) != null) {
90+
stringBuilder.append(line);
91+
}
92+
String requestBody = stringBuilder.toString();
93+
94+
// verify that is in a valid JSON format
95+
new ObjectMapper().readTree(requestBody);
96+
97+
InputStream inputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
98+
OutputStream outStream = Files.newOutputStream(jsonConfigFile.toPath());
99+
OpenmrsUtil.copyFile(inputStream, outStream);
100+
101+
if (jsonConfigFile.exists()) {
102+
log.debug("file: '{}' written successfully", jsonConfigFile.getAbsolutePath());
103+
response.setStatus(HttpServletResponse.SC_OK);
104+
}
105+
} catch (JsonProcessingException e) {
106+
log.error("Invalid JSON format", e);
107+
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JSON format");
108+
}
109+
}
110+
111+
private File getJsonConfigFile() throws IOException {
112+
File folder = getSpaStaticFilesDir();
113+
if (!folder.isDirectory()) {
114+
log.debug("Unable to find the OpenMRS SPA module frontend directory hence creating it at: " + folder.getAbsolutePath());
115+
if (!folder.mkdirs()) {
116+
throw new IOException("Failed to create the OpenMRS SPA module frontend directory at: " + folder.getPath());
117+
}
118+
}
119+
return new File(folder.getAbsolutePath(), JSON_CONFIG_FILE_NAME);
120+
}
121+
122+
private File getSpaStaticFilesDir() {
123+
AdministrationService as = Context.getAdministrationService();
124+
String folderName = as.getGlobalProperty(GP_LOCAL_DIRECTORY, DEFAULT_FRONTEND_DIRECTORY);
125+
126+
// try to load the repository folder straight away.
127+
File folder = new File(folderName);
128+
129+
// if the property wasn't a full path already, assume it was intended to be a
130+
// folder in the application directory
131+
if (!folder.exists()) {
132+
folder = new File(OpenmrsUtil.getApplicationDataDirectory(), folderName);
133+
}
134+
return folder;
135+
}
136+
}

0 commit comments

Comments
 (0)