Skip to content

Commit b3e1c78

Browse files
authored
Merge pull request #11467 from IQSS/11448-api-endpoint-for-analytics-html
Feature Request: API endpoint for analytics.html
2 parents 9a24b32 + 7019b96 commit b3e1c78

File tree

8 files changed

+163
-17
lines changed

8 files changed

+163
-17
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Feature Request: API endpoint for analytics.html
2+
3+
New API to get the analytics.html from settings for SPA (Also can be used to get homePage, header, footer, style, and logo)
4+
5+
See also [the guides](https://dataverse-guide--11359.org.readthedocs.build/en/11359/installation/config.html#web-analytics-code), #11448.

doc/sphinx-guides/source/api/native-api.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5836,6 +5836,34 @@ The fully expanded example above (without environment variables) looks like this
58365836
58375837
curl "https://demo.dataverse.org/api/info/exportFormats"
58385838
5839+
Get Customization File Contents
5840+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5841+
5842+
The Customization API is used to retrieve the analytics-code.html as well as other customization file contents.
5843+
5844+
See also :ref:`web-analytics-code` in the Configuration section of the Installation Guide and :ref:`Branding Your Installation`
5845+
5846+
The Content-Type returned in the header is based on the media type of the file being returned (example: analytics-code.html returns "text/html; charset=UTF-8"
5847+
5848+
Valid types are "homePage", "header", "footer", "style", "analytics", and "logo".
5849+
5850+
A curl example getting the analytics-code
5851+
5852+
.. code-block:: bash
5853+
5854+
export SERVER_URL=https://demo.dataverse.org
5855+
export TYPE=analytics
5856+
5857+
curl -X GET "$SERVER_URL/api/info/settings/customization/$TYPE"
5858+
5859+
The fully expanded example above (without environment variables) looks like this:
5860+
5861+
.. code-block:: bash
5862+
5863+
curl -X GET "https://demo.dataverse.org/api/info/settings/customization/analytics"
5864+
5865+
.. _customization-analytics:
5866+
58395867
.. _metadata-blocks-api:
58405868
58415869
Metadata Blocks

src/main/java/edu/harvard/iq/dataverse/CustomizationFilesServlet.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import java.io.PrintWriter;
1515
import java.nio.file.Path;
1616
import java.nio.file.Paths;
17+
import java.util.logging.Logger;
18+
1719
import jakarta.servlet.ServletException;
1820
import jakarta.servlet.annotation.WebServlet;
1921
import jakarta.servlet.http.HttpServlet;
@@ -22,14 +24,16 @@
2224
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
2325
import jakarta.ejb.EJB;
2426
import org.apache.commons.io.IOUtils;
27+
import org.apache.tika.Tika;
2528

2629
/**
2730
*
2831
* @author skraffmi
2932
*/
3033
@WebServlet(name = "CustomizationFilesServlet", urlPatterns = {"/CustomizationFilesServlet"})
3134
public class CustomizationFilesServlet extends HttpServlet {
32-
35+
private static final Logger logger = Logger.getLogger(CustomizationFilesServlet.class.getCanonicalName());
36+
3337
@EJB
3438
SettingsServiceBean settingsService;
3539

@@ -45,7 +49,7 @@ public class CustomizationFilesServlet extends HttpServlet {
4549
*/
4650
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
4751
throws ServletException, IOException {
48-
response.setContentType("text/html;charset=UTF-8");
52+
response.setContentType(request.getContentType());
4953

5054
String customFileType = request.getParameter("customFileType");
5155
String filePath = getFilePath(customFileType);
@@ -56,6 +60,13 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re
5660
try {
5761
File fileIn = physicalPath.toFile();
5862
if (fileIn != null) {
63+
Tika tika = new Tika();
64+
try {
65+
String mimeType = tika.detect(fileIn);
66+
response.setContentType(mimeType);
67+
} catch (Exception e) {
68+
logger.info("Error getting MIME Type for " + filePath + " : " + e.getMessage());
69+
}
5970
inputStream = new FileInputStream(fileIn);
6071

6172
in = new BufferedReader(new InputStreamReader(inputStream));

src/main/java/edu/harvard/iq/dataverse/api/Info.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
package edu.harvard.iq.dataverse.api;
22

3-
import java.io.FileInputStream;
4-
import java.io.InputStream;
5-
import java.net.URL;
6-
import java.nio.charset.StandardCharsets;
7-
import java.util.Arrays;
8-
import java.util.List;
9-
import java.util.logging.Level;
103
import java.util.logging.Logger;
114

12-
import jakarta.ws.rs.Produces;
13-
import org.apache.commons.io.IOUtils;
5+
import edu.harvard.iq.dataverse.customization.CustomizationConstants;
6+
import jakarta.ws.rs.*;
7+
import jakarta.ws.rs.client.Client;
8+
import jakarta.ws.rs.client.ClientBuilder;
9+
import jakarta.ws.rs.client.WebTarget;
1410

1511
import edu.harvard.iq.dataverse.export.ExportService;
1612
import edu.harvard.iq.dataverse.settings.JvmSettings;
1713
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
18-
import edu.harvard.iq.dataverse.util.BundleUtil;
1914
import edu.harvard.iq.dataverse.util.SystemConfig;
2015
import io.gdcc.spi.export.Exporter;
2116
import io.gdcc.spi.export.ExportException;
@@ -24,9 +19,6 @@
2419
import jakarta.json.Json;
2520
import jakarta.json.JsonObjectBuilder;
2621
import jakarta.json.JsonValue;
27-
import jakarta.ws.rs.GET;
28-
import jakarta.ws.rs.Path;
29-
import jakarta.ws.rs.QueryParam;
3022
import jakarta.ws.rs.core.MediaType;
3123
import jakarta.ws.rs.core.Response;
3224
import org.eclipse.microprofile.openapi.annotations.Operation;
@@ -139,6 +131,26 @@ public Response getExportFormats() {
139131
return ok(responseModel);
140132
}
141133

134+
@GET
135+
@Path("settings/customization/{customizationFileType}")
136+
public Response getCustomizationFile(@PathParam("customizationFileType") String customizationFileType) {
137+
String type = customizationFileType != null ? customizationFileType.toLowerCase() : "";
138+
if (!CustomizationConstants.validTypes.contains(type)) {
139+
return badRequest("Customization type unknown or missing. Must be one of the following: " + CustomizationConstants.validTypes);
140+
}
141+
Client client = ClientBuilder.newClient();
142+
WebTarget endpoint = client.target("http://localhost:8080/CustomizationFilesServlet");
143+
Response response = endpoint.queryParam("customFileType", type)
144+
.request(MediaType.MEDIA_TYPE_WILDCARD)
145+
.get();
146+
147+
if (response.getLength() < 1) {
148+
return notFound(type + " not found.");
149+
} else {
150+
return response;
151+
}
152+
}
153+
142154
private Response getSettingResponseByKey(SettingsServiceBean.Key key) {
143155
String setting = settingsService.getValueForKey(key);
144156
if (setting != null) {

src/main/java/edu/harvard/iq/dataverse/customization/CustomizationConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
package edu.harvard.iq.dataverse.customization;
77

8+
import java.util.List;
9+
810
/**
911
*
1012
* @author rmp553
@@ -23,5 +25,5 @@ public class CustomizationConstants {
2325

2426
public static String fileTypeLogo = "logo";
2527

26-
28+
public static List<String> validTypes = List.of(fileTypeHomePage, fileTypeHeader, fileTypeFooter, fileTypeStyle, fileTypeAnalytics, fileTypeLogo);
2729
} // end CustomizationConstants
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package edu.harvard.iq.dataverse.api;
2+
3+
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
4+
import io.restassured.response.Response;
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.BeforeAll;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.nio.file.Files;
10+
import java.nio.file.Paths;
11+
12+
import static org.hamcrest.CoreMatchers.*;
13+
14+
public class CustomizationIT {
15+
16+
static String docroot;
17+
@BeforeAll
18+
public static void setup() {
19+
// setup docroot for running test either in docker or in Jenkins
20+
if (Files.exists(Paths.get("docker-dev-volumes"))) {
21+
docroot = "./appserver/glassfish/domains/domain1/docroot/";
22+
} else {
23+
docroot = "../docroot/";
24+
}
25+
}
26+
@AfterEach
27+
public void after() {
28+
UtilIT.deleteSetting(SettingsServiceBean.Key.WebAnalyticsCode);
29+
}
30+
31+
@Test
32+
public void testGetCustomAnalytics() {
33+
String setting = docroot + "index.html";
34+
UtilIT.setSetting(SettingsServiceBean.Key.WebAnalyticsCode, setting).prettyPrint();
35+
36+
Response getResponse = UtilIT.getCustomizationFile("analytics");
37+
getResponse.then().assertThat()
38+
.statusCode(200)
39+
.body(containsString("<!doctype html>"));
40+
41+
assert (getResponse.getHeaders().get("Content-Type").getValue().startsWith("text/html"));
42+
43+
UtilIT.deleteSetting(SettingsServiceBean.Key.WebAnalyticsCode).prettyPrint();
44+
45+
getResponse = UtilIT.getCustomizationFile("analytics");
46+
getResponse.then().assertThat()
47+
.statusCode(404)
48+
.body(containsString("not found."));
49+
}
50+
51+
@Test
52+
public void testGetCustomLogo() {
53+
String setting = docroot + "img/logo.png";
54+
UtilIT.setSetting(SettingsServiceBean.Key.LogoCustomizationFile, setting).prettyPrint();
55+
56+
Response getResponse = UtilIT.getCustomizationFile("logo");
57+
getResponse.then().assertThat()
58+
.statusCode(200)
59+
.body(containsString("PNG"));
60+
61+
assert (getResponse.getHeaders().get("Content-Type").getValue().startsWith("image/png"));
62+
63+
UtilIT.deleteSetting(SettingsServiceBean.Key.LogoCustomizationFile).prettyPrint();
64+
65+
getResponse = UtilIT.getCustomizationFile("logo");
66+
getResponse.prettyPrint();
67+
getResponse.then().assertThat()
68+
.statusCode(404)
69+
.body(containsString("not found."));
70+
}
71+
72+
@Test
73+
public void testGetCustomUnknown() {
74+
Response getResponse = UtilIT.getCustomizationFile("unknownType");
75+
getResponse.then().assertThat()
76+
.statusCode(400)
77+
.body(containsString("Customization type unknown or missing. Must be one of the following: [homePage, header"));
78+
}
79+
}

src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4961,6 +4961,15 @@ public static Response updateDatasetFilesMetadata(String datasetIdOrPersistentId
49614961
.post("/api/datasets/" + idInPath + "/files/metadata" + optionalQueryParam);
49624962
}
49634963

4964+
public static Response getCustomizationFile(String fileType) {
4965+
RequestSpecification requestSpec = given();
4966+
4967+
Response resp = requestSpec.contentType("text/html; charset=UTF-8")
4968+
.get("/api/info/settings/customization/" + fileType);
4969+
4970+
return resp;
4971+
}
4972+
49644973
static Response getUserSelectableRoles(String apiToken) {
49654974
return given()
49664975
.header(API_TOKEN_HTTP_HEADER, apiToken)

tests/integration-tests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,HarvestingClientsIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT,LinkIT,DeleteUsersIT,DeactivateUsersIT,AuxiliaryFilesIT,InvalidCharactersIT,LicensesIT,NotificationsIT,BagIT,MetadataBlocksIT,NetcdfIT,SignpostingIT,FitsIT,LogoutIT,DataRetrieverApiIT,ProvIT,S3AccessIT,OpenApiIT,InfoIT,DatasetFieldsIT,SavedSearchIT,DatasetTypesIT,DataverseFeaturedItemsIT,SendFeedbackApiIT
1+
DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,HarvestingClientsIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT,LinkIT,DeleteUsersIT,DeactivateUsersIT,AuxiliaryFilesIT,InvalidCharactersIT,LicensesIT,NotificationsIT,BagIT,MetadataBlocksIT,NetcdfIT,SignpostingIT,FitsIT,LogoutIT,DataRetrieverApiIT,ProvIT,S3AccessIT,OpenApiIT,InfoIT,DatasetFieldsIT,SavedSearchIT,DatasetTypesIT,DataverseFeaturedItemsIT,SendFeedbackApiIT,CustomizationIT

0 commit comments

Comments
 (0)