From c9e0ae9bf2273ff80b6fc15e698c86c5ad355cf6 Mon Sep 17 00:00:00 2001 From: Ian Allen Date: Tue, 24 Dec 2024 10:25:25 -0400 Subject: [PATCH] Fix set site settings in swagger_ui so it function correctly. Prior to this fix, the swagger ui for applying site settings was not working. --- .../java/org/fao/geonet/api/site/SiteApi.java | 67 +++++++++++++++---- .../org/fao/geonet/api/site/SiteApiTest.java | 36 +++++++++- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/site/SiteApi.java b/services/src/main/java/org/fao/geonet/api/site/SiteApi.java index 01882b580ed..2345806d934 100644 --- a/services/src/main/java/org/fao/geonet/api/site/SiteApi.java +++ b/services/src/main/java/org/fao/geonet/api/site/SiteApi.java @@ -25,8 +25,11 @@ import co.elastic.clients.elasticsearch.core.CountRequest; import co.elastic.clients.elasticsearch.core.CountResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; @@ -88,10 +91,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; @@ -387,24 +387,67 @@ public List getSettingsDetails( @io.swagger.v3.oas.annotations.Operation( summary = "Save settings", - description = "") - @RequestMapping( + description = "Save the provided settings.", + requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "Map of settings to be saved", + required = true, + content = { + @Content( + mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE, + schema = @Schema(implementation = Map.class), + examples = { + @ExampleObject( + name = "Example setting (application/x-www-form-urlencoded)", + value = "{\n \"additionalProp1\": \"string\",\n \"additionalProp2\": \"string\",\n \"additionalProp3\": \"string\"\n}" + ), + @ExampleObject( + name = "Example setting selection manager max records to 1000 (application/x-www-form-urlencoded)", + value = "{\n \"system/selectionmanager/maxrecords\": \"1000\"\n}" + ) + } + ), + @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = Map.class), + examples = { + @ExampleObject( + name = "Example setting (application/json)", + value = "{\n \"additionalProp1\": \"string\",\n \"additionalProp2\": \"string\",\n \"additionalProp3\": \"string\"\n}" + ), + @ExampleObject( + name = "Example setting selection manager max records to 1000 (application/json)", + value = "{\n \"system/selectionmanager/maxrecords\": \"1000\"\n}" + ) + } + ) + } + ) + ) + @PostMapping( path = "/settings", - produces = MediaType.APPLICATION_JSON_VALUE, - method = RequestMethod.POST + consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE} ) @PreAuthorize("hasAuthority('Administrator')") @ResponseStatus(HttpStatus.NO_CONTENT) @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Settings saved.", content = {@Content(schema = @Schema(hidden = true))}), + @ApiResponse(responseCode = "204", description = "Settings saved."), @ApiResponse(responseCode = "403", description = ApiParams.API_RESPONSE_NOT_ALLOWED_ONLY_ADMIN) }) public void saveSettings( - @Parameter(hidden = false) - @RequestParam - Map allRequestParams, + // Mark parameter as hidden in open api specification as the Operation requestBody(above) will describe the format to be supplied + // Without this fix, the swagger ui will fail to work correctly. + @Parameter(description = "Map of settings to be saved", + required = true, hidden = true) + @RequestParam Map allRequestParams, HttpServletRequest request ) throws Exception { + //If sent as JSON then the allRequestParams will be empty, and we need to manually load it from the request body + if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType()) && allRequestParams.isEmpty()) { + BufferedReader reader = request.getReader(); + ObjectMapper mapper = new ObjectMapper(); + allRequestParams = mapper.readValue(reader, new TypeReference>() {}); + } + ApplicationContext applicationContext = ApplicationContextHolder.get(); String currentUuid = settingManager.getSiteId(); String oldSiteName = settingManager.getSiteName(); diff --git a/services/src/test/java/org/fao/geonet/api/site/SiteApiTest.java b/services/src/test/java/org/fao/geonet/api/site/SiteApiTest.java index 87f3852d8de..7af3772df0d 100644 --- a/services/src/test/java/org/fao/geonet/api/site/SiteApiTest.java +++ b/services/src/test/java/org/fao/geonet/api/site/SiteApiTest.java @@ -62,7 +62,7 @@ public void getSettingsSet() throws Exception { @Test - public void updateSettings() throws Exception { + public void updateSettingsFormUrlEncoded() throws Exception { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); this.mockHttpSession = loginAsAdmin(); @@ -78,10 +78,42 @@ public void updateSettings() throws Exception { String newName = "DataHub"; this.mockMvc.perform(post("/srv/api/site/settings") + .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE) .param("system/site/name", newName) + .session(this.mockHttpSession)) + .andExpect(status().is(204)) + .andExpect(content().string("")); // No content should be returned. + + this.mockMvc.perform(get("/srv/api/site/settings") .session(this.mockHttpSession) .accept(MediaType.parseMediaType("application/json"))) - .andExpect(status().is(204)); + .andExpect(status().isOk()) + .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)) + .andExpect(jsonPath("$['system/site/name']", is(newName))); + } + + @Test + public void updateSettingsJson() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + + this.mockHttpSession = loginAsAdmin(); + + encryptor.initialize(); + + this.mockMvc.perform(get("/srv/api/site/settings") + .session(this.mockHttpSession) + .accept(MediaType.parseMediaType("application/json"))) + .andExpect(status().isOk()) + .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)) + .andExpect(jsonPath("$['system/site/name']", is("My GeoNetwork catalogue"))); + + String newName = "JsonDataHub"; + this.mockMvc.perform(post("/srv/api/site/settings") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content("{\"system/site/name\": \"" + newName + "\"}") + .session(this.mockHttpSession)) + .andExpect(status().is(204)) + .andExpect(content().string("")); // No content should be returned. this.mockMvc.perform(get("/srv/api/site/settings") .session(this.mockHttpSession)