diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index 463c21ef8d..81111d2de4 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -765,9 +765,24 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { JsonNode newSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16}}"); JsonNode updatedSettings = doPut("/api/user/settings", newSettings, JsonNode.class); - JsonNode expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16}, \"E\":18}"); Assert.assertEquals(expectedSettings, updatedSettings); + + JsonNode patchedSettings = mapper.readTree("\"C\":{\"E\": 22}}"); + updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); + expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"E\": 22}, \"E\":18}"); + Assert.assertEquals(expectedSettings, updatedSettings); + + patchedSettings = mapper.readTree("\"C.D\": 16}}"); + updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); + expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16, \"E\": 22}, \"E\":18}"); + Assert.assertEquals(expectedSettings, updatedSettings); + + patchedSettings = mapper.readTree("\"C.D\": {\"A\":5}}}"); + updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); + expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": {\"A\":5}, \"E\": 22}, \"E\":18}"); + Assert.assertEquals(expectedSettings, updatedSettings); + } @Test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java index 5ed1eab92a..30f9b9334a 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java @@ -15,18 +15,9 @@ */ package org.thingsboard.server.dao.user; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserSettings; -import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java index 88087d28b1..dc1e18352c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java @@ -24,6 +24,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.UserSettings; @@ -46,14 +47,7 @@ public class UserSettingsServiceImpl extends AbstractCachedService jsonPaths) { + public void deleteUserSettings(TenantId tenantId, UserId userId, List jsonPaths) { log.trace("Executing deleteUserSettings for user [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); UserSettings userSettings = userSettingsDao.findById(tenantId, userId); - DocumentContext docSettings = JsonPath.parse(userSettings.getSettings().toString()); + if (userSettings == null) { + return; + } try { + DocumentContext docSettings = JsonPath.parse(userSettings.getSettings().toString()); for (String s : jsonPaths) { docSettings = docSettings.delete("$." + s); } userSettings.setSettings(new ObjectMapper().readValue(docSettings.jsonString(), ObjectNode.class)); - userSettingsDao.save(tenantId, userSettings); - publishEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId())); } catch (Exception t) { handleEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId())); throw new RuntimeException(t); } + doSaveUserSettings(tenantId, userSettings); + } + + private UserSettings doSaveUserSettings(TenantId tenantId, UserSettings userSettings) { + try { + //TODO: add validation for "." and ","; + UserSettings saved = userSettingsDao.save(tenantId, userSettings); + publishEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId())); + return saved; + } catch (Exception t) { + handleEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId())); + throw t; + } } @TransactionalEventListener(classes = UserSettingsEvictEvent.class) @@ -110,15 +111,13 @@ public class UserSettingsServiceImpl extends AbstractCachedService fieldNames = updateNode.fieldNames(); while (fieldNames.hasNext()) { String fieldName = fieldNames.next(); JsonNode jsonNode = mainNode.get(fieldName); if (jsonNode != null && jsonNode.isObject()) { merge(jsonNode, updateNode.get(fieldName)); - } - else { + } else { if (mainNode instanceof ObjectNode) { JsonNode value = updateNode.get(fieldName); ((ObjectNode) mainNode).set(fieldName, value);