diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java index 040e360c0..1071bfb20 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java @@ -80,26 +80,20 @@ public class AdminSettingsController { }) public ResponseEntity getSettings( @RequestParam(value = "includePending", defaultValue = "false") boolean includePending) { - log.info("Admin requested all application settings (includePending={}, pendingChanges.size={})", includePending, pendingChanges.size()); + log.debug("Admin requested all application settings (includePending={})", includePending); - // Convert ApplicationProperties to Map and mask sensitive fields - Map maskedSettings = maskSensitiveFields( - objectMapper.convertValue(applicationProperties, Map.class) - ); + // Convert ApplicationProperties to Map + Map settings = objectMapper.convertValue(applicationProperties, Map.class); - if (!includePending) { - log.debug("Returning current settings only (includePending=false)"); - return ResponseEntity.ok(maskedSettings); + if (includePending && !pendingChanges.isEmpty()) { + // Merge pending changes into the settings map + settings = mergePendingChanges(settings, pendingChanges); } - // Include pending changes in response (also mask sensitive pending changes) - Map response = new HashMap<>(); - response.put("currentSettings", maskedSettings); - response.put("pendingChanges", maskSensitiveFields(new HashMap<>(pendingChanges))); - response.put("hasPendingChanges", !pendingChanges.isEmpty()); + // Mask sensitive fields after merging + Map maskedSettings = maskSensitiveFields(settings); - log.info("Returning settings with pending changes: hasPendingChanges={}, pendingChanges.keys={}", !pendingChanges.isEmpty(), pendingChanges.keySet()); - return ResponseEntity.ok(response); + return ResponseEntity.ok(maskedSettings); } @GetMapping("/delta") @@ -588,4 +582,44 @@ public class AdminSettingsController { } } + /** + * Merge pending changes into the settings map using dot notation keys + */ + @SuppressWarnings("unchecked") + private Map mergePendingChanges(Map settings, Map pendingChanges) { + // Create a deep copy of the settings to avoid modifying the original + Map mergedSettings = new HashMap<>(settings); + + for (Map.Entry pendingEntry : pendingChanges.entrySet()) { + String dotNotationKey = pendingEntry.getKey(); + Object pendingValue = pendingEntry.getValue(); + + // Split the dot notation key into parts + String[] keyParts = dotNotationKey.split("\\."); + + // Navigate to the parent object and set the value + Map currentMap = mergedSettings; + + // Navigate through all parts except the last one + for (int i = 0; i < keyParts.length - 1; i++) { + String keyPart = keyParts[i]; + + // Get or create the nested map + Object nested = currentMap.get(keyPart); + if (!(nested instanceof Map)) { + // Create a new nested map if it doesn't exist or isn't a map + nested = new HashMap(); + currentMap.put(keyPart, nested); + } + currentMap = (Map) nested; + } + + // Set the final value + String finalKey = keyParts[keyParts.length - 1]; + currentMap.put(finalKey, pendingValue); + } + + return mergedSettings; + } + }