mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-08-02 13:48:15 +02:00
remove file endpoint, show delta cahgned to tracking instead
This commit is contained in:
parent
f9d36b985a
commit
26a6534ae4
@ -1,11 +1,9 @@
|
||||
package stirling.software.proprietary.security.controller.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -17,10 +15,10 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@ -32,7 +30,6 @@ import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.common.configuration.InstallationPathConfig;
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
import stirling.software.proprietary.security.model.api.admin.SettingValueResponse;
|
||||
@ -49,11 +46,14 @@ public class AdminSettingsController {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
// Track settings that have been modified but not yet applied (require restart)
|
||||
private static final ConcurrentHashMap<String, Object> pendingChanges = new ConcurrentHashMap<>();
|
||||
|
||||
@GetMapping
|
||||
@Operation(
|
||||
summary = "Get all application settings",
|
||||
description = "Retrieve all current application settings. Admin access required.")
|
||||
description = "Retrieve all current application settings. Use includePending=true to include settings that will take effect after restart. Admin access required.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "200", description = "Settings retrieved successfully"),
|
||||
@ -61,116 +61,44 @@ public class AdminSettingsController {
|
||||
responseCode = "403",
|
||||
description = "Access denied - Admin role required")
|
||||
})
|
||||
public ResponseEntity<ApplicationProperties> getSettings() {
|
||||
log.debug("Admin requested all application settings");
|
||||
return ResponseEntity.ok(applicationProperties);
|
||||
}
|
||||
|
||||
@GetMapping("/file")
|
||||
@Operation(
|
||||
summary = "Get settings file as JSON",
|
||||
description =
|
||||
"Retrieve the settings.yml file parsed as JSON, showing the latest saved values (after restart). Comments and formatting are ignored. Admin access required.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Settings file retrieved and parsed successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "Settings file not found"),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Access denied - Admin role required"),
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "Failed to read or parse settings file")
|
||||
})
|
||||
public ResponseEntity<?> getSettingsFile() {
|
||||
try {
|
||||
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
if (!Files.exists(settingsPath)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
// Parse YAML file to JSON
|
||||
ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
|
||||
ObjectMapper jsonMapper = new ObjectMapper();
|
||||
|
||||
Object yamlData = yamlMapper.readValue(settingsPath.toFile(), Object.class);
|
||||
|
||||
log.debug("Admin requested settings file as JSON");
|
||||
return ResponseEntity.ok(yamlData);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to read or parse settings file: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("Failed to read or parse settings file: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error reading settings file: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("Unexpected error reading settings file");
|
||||
public ResponseEntity<?> getSettings(@RequestParam(defaultValue = "false") boolean includePending) {
|
||||
log.debug("Admin requested all application settings (includePending={})", includePending);
|
||||
|
||||
if (!includePending) {
|
||||
return ResponseEntity.ok(applicationProperties);
|
||||
}
|
||||
|
||||
// Include pending changes in response
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("currentSettings", applicationProperties);
|
||||
response.put("pendingChanges", pendingChanges);
|
||||
response.put("hasPendingChanges", !pendingChanges.isEmpty());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@GetMapping("/delta")
|
||||
@Operation(
|
||||
summary = "Get settings delta (pending changes)",
|
||||
summary = "Get pending settings changes",
|
||||
description =
|
||||
"Compare current runtime settings with saved file settings to show pending changes that will take effect after restart. Admin access required.")
|
||||
"Retrieve settings that have been modified but not yet applied (require restart). Admin access required.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Settings delta retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "Settings file not found"),
|
||||
description = "Pending changes retrieved successfully"),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Access denied - Admin role required"),
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "Failed to calculate settings delta")
|
||||
description = "Access denied - Admin role required")
|
||||
})
|
||||
public ResponseEntity<?> getSettingsDelta() {
|
||||
try {
|
||||
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
if (!Files.exists(settingsPath)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
// Get current runtime settings as JSON
|
||||
Map<String, Object> runtimeSettings =
|
||||
objectMapper.convertValue(applicationProperties, Map.class);
|
||||
|
||||
// Parse YAML file to get saved settings
|
||||
ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
|
||||
Object fileData = yamlMapper.readValue(settingsPath.toFile(), Object.class);
|
||||
Map<String, Object> savedSettings = objectMapper.convertValue(fileData, Map.class);
|
||||
|
||||
// Calculate differences
|
||||
Map<String, Object> delta = new HashMap<>();
|
||||
Map<String, Object> pendingChanges = new HashMap<>();
|
||||
Map<String, Object> currentValues = new HashMap<>();
|
||||
|
||||
findDifferences("", runtimeSettings, savedSettings, pendingChanges, currentValues);
|
||||
|
||||
delta.put(
|
||||
"pendingChanges", pendingChanges); // Values that will take effect after restart
|
||||
delta.put("currentValues", currentValues); // Current runtime values
|
||||
delta.put("hasPendingChanges", !pendingChanges.isEmpty());
|
||||
|
||||
log.debug(
|
||||
"Admin requested settings delta - found {} pending changes",
|
||||
pendingChanges.size());
|
||||
return ResponseEntity.ok(delta);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to calculate settings delta: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("Failed to calculate settings delta: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error calculating settings delta: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("Unexpected error calculating settings delta");
|
||||
}
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("pendingChanges", pendingChanges);
|
||||
response.put("hasPendingChanges", !pendingChanges.isEmpty());
|
||||
response.put("count", pendingChanges.size());
|
||||
|
||||
log.debug("Admin requested pending changes - found {} settings", pendingChanges.size());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@ -209,6 +137,10 @@ public class AdminSettingsController {
|
||||
|
||||
log.info("Admin updating setting: {} = {}", key, value);
|
||||
GeneralUtils.saveKeyToSettings(key, value);
|
||||
|
||||
// Track this as a pending change
|
||||
pendingChanges.put(key, value);
|
||||
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
@ -314,6 +246,10 @@ public class AdminSettingsController {
|
||||
|
||||
log.info("Admin updating section setting: {} = {}", fullKey, value);
|
||||
GeneralUtils.saveKeyToSettings(fullKey, value);
|
||||
|
||||
// Track this as a pending change
|
||||
pendingChanges.put(fullKey, value);
|
||||
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
@ -401,6 +337,9 @@ public class AdminSettingsController {
|
||||
Object value = request.getValue();
|
||||
log.info("Admin updating single setting: {} = {}", key, value);
|
||||
GeneralUtils.saveKeyToSettings(key, value);
|
||||
|
||||
// Track this as a pending change
|
||||
pendingChanges.put(key, value);
|
||||
|
||||
String escapedKey = HtmlUtils.htmlEscape(key);
|
||||
return ResponseEntity.ok(
|
||||
@ -557,49 +496,4 @@ public class AdminSettingsController {
|
||||
}
|
||||
}
|
||||
|
||||
/** Recursively compare two maps to find differences between runtime and saved settings */
|
||||
@SuppressWarnings("unchecked")
|
||||
private void findDifferences(
|
||||
String keyPrefix,
|
||||
Map<String, Object> runtime,
|
||||
Map<String, Object> saved,
|
||||
Map<String, Object> pendingChanges,
|
||||
Map<String, Object> currentValues) {
|
||||
|
||||
// Check all keys in saved settings (these are the pending changes)
|
||||
for (Map.Entry<String, Object> entry : saved.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String fullKey = keyPrefix.isEmpty() ? key : keyPrefix + "." + key;
|
||||
Object savedValue = entry.getValue();
|
||||
Object runtimeValue = runtime.get(key);
|
||||
|
||||
if (savedValue instanceof Map && runtimeValue instanceof Map) {
|
||||
// Recursively check nested objects
|
||||
findDifferences(
|
||||
fullKey,
|
||||
(Map<String, Object>) runtimeValue,
|
||||
(Map<String, Object>) savedValue,
|
||||
pendingChanges,
|
||||
currentValues);
|
||||
} else {
|
||||
// Compare values - if they're different, savedValue is pending
|
||||
if (!java.util.Objects.equals(runtimeValue, savedValue)) {
|
||||
pendingChanges.put(fullKey, savedValue);
|
||||
currentValues.put(fullKey, runtimeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for keys that exist in runtime but not in saved (these would be removed on restart)
|
||||
for (Map.Entry<String, Object> entry : runtime.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String fullKey = keyPrefix.isEmpty() ? key : keyPrefix + "." + key;
|
||||
|
||||
if (!saved.containsKey(key)) {
|
||||
// This runtime setting would be lost on restart
|
||||
pendingChanges.put(fullKey + " (will be removed)", null);
|
||||
currentValues.put(fullKey, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user