Browse Source

fixed update settings method

pull/8075/head
dashevchenko 4 years ago
parent
commit
a25e328b7c
  1. 31
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  2. 31
      application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java
  3. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java
  4. 58
      dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java

31
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -92,7 +92,8 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
public class UserController extends BaseController { public class UserController extends BaseController {
public static final String USER_ID = "userId"; public static final String USER_ID = "userId";
public static final String JSON_PATHS = "jsonPaths"; public static final String PATH = "path";
public static final String PATHS = "paths";
public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!"; public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!";
public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s"; public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
@ -406,13 +407,21 @@ public class UserController extends BaseController {
"{A:10, B:{C:10, D:5}}, E:6") "{A:10, B:{C:10, D:5}}, E:6")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PutMapping(value = "/user/settings") @PutMapping(value = "/user/settings")
public JsonNode putUserSettings(@RequestBody JsonNode settings) throws ThingsboardException { public void putUserSettings(@RequestBody JsonNode settings) throws ThingsboardException {
SecurityUser currentUser = getCurrentUser(); SecurityUser currentUser = getCurrentUser();
userSettingsService.updateUserSettings(currentUser.getTenantId(), currentUser.getId(), settings);
}
UserSettings userSettings = new UserSettings(); @ApiOperation(value = "Update user settings (saveUserSettings)",
userSettings.setSettings(settings); notes = "Update user settings for authorized user. Only specified json elements will be updated." +
userSettings.setUserId(currentUser.getId()); "Example: you have such settings: {A:5, B:{C:10, D:5}}. Updating it with {A:10, E:6} will result in" +
return userSettingsService.updateUserSettings(currentUser.getTenantId(), userSettings).getSettings(); "{A:10, B:{C:10, D:5}}, E:6")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PutMapping(value = "/user/settings/{path}")
public void putUserSettings(@ApiParam(value = PATH)
@PathVariable(PATH) String path, @RequestBody JsonNode settings) throws ThingsboardException {
SecurityUser currentUser = getCurrentUser();
userSettingsService.updateUserSettings(currentUser.getTenantId(), currentUser.getId(), path, settings);
} }
@ApiOperation(value = "Get user settings (getUserSettings)", @ApiOperation(value = "Get user settings (getUserSettings)",
@ -430,12 +439,12 @@ public class UserController extends BaseController {
notes = "Delete user settings by specifying list of json element xpaths. \n " + notes = "Delete user settings by specifying list of json element xpaths. \n " +
"Example: to delete B and C element in { \"A\": {\"B\": 5}, \"C\": 15} send A.B,C in jsonPaths request parameter" ) "Example: to delete B and C element in { \"A\": {\"B\": 5}, \"C\": 15} send A.B,C in jsonPaths request parameter" )
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user/settings/{jsonPaths}", method = RequestMethod.DELETE) @RequestMapping(value = "/user/settings/{paths}", method = RequestMethod.DELETE)
public void deleteUserSettings( @ApiParam(value = JSON_PATHS) public void deleteUserSettings(@ApiParam(value = PATHS)
@PathVariable(JSON_PATHS) String jsonPaths) throws ThingsboardException { @PathVariable(PATHS) String paths) throws ThingsboardException {
checkParameter(USER_ID, jsonPaths); checkParameter(USER_ID, paths);
SecurityUser currentUser = getCurrentUser(); SecurityUser currentUser = getCurrentUser();
userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), Arrays.asList(jsonPaths.split(","))); userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), Arrays.asList(paths.split(",")));
} }
} }

31
application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java

@ -759,30 +759,33 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testUpdateUserSettings() throws Exception { public void testUpdateUserSettings() throws Exception {
loginCustomerUser(); loginCustomerUser();
JsonNode userSettings = mapper.readTree("{\"A\":5, \"B\":10, \"E\":18}"); JsonNode userSettings = mapper.readTree("{\"A\":5, \"B\":{\"C\":5, \"D\":5}}");
JsonNode savedSettings = doPost("/api/user/settings", userSettings, JsonNode.class); JsonNode savedSettings = doPost("/api/user/settings", userSettings, JsonNode.class);
Assert.assertEquals(userSettings, savedSettings); Assert.assertEquals(userSettings, savedSettings);
JsonNode newSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16}}"); JsonNode newSettings = mapper.readTree("{\"A\":10}");
JsonNode updatedSettings = doPut("/api/user/settings", newSettings, JsonNode.class); doPut("/api/user/settings", newSettings);
JsonNode expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16}, \"E\":18}"); JsonNode updatedSettings = doGet("/api/user/settings", JsonNode.class);
JsonNode expectedSettings = mapper.readTree("{\"A\":10, \"B\":{\"C\":5, \"D\":5}}");
Assert.assertEquals(expectedSettings, updatedSettings); Assert.assertEquals(expectedSettings, updatedSettings);
JsonNode patchedSettings = mapper.readTree("\"C\":{\"E\": 22}}"); JsonNode patchedSettings = mapper.readTree("{\"B\":{\"E\": 22}}");
updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); doPut("/api/user/settings", patchedSettings);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"E\": 22}, \"E\":18}"); updatedSettings = doGet("/api/user/settings", JsonNode.class);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":{\"E\": 22}}");
Assert.assertEquals(expectedSettings, updatedSettings); Assert.assertEquals(expectedSettings, updatedSettings);
patchedSettings = mapper.readTree("\"C.D\": 16}}"); patchedSettings = mapper.readTree("{\"I\": 56}");
updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); doPut("/api/user/settings/B.E", patchedSettings);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": 16, \"E\": 22}, \"E\":18}"); updatedSettings = doGet("/api/user/settings", JsonNode.class);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":{\"E\": {\"I\":56}}}");
Assert.assertEquals(expectedSettings, updatedSettings); Assert.assertEquals(expectedSettings, updatedSettings);
patchedSettings = mapper.readTree("\"C.D\": {\"A\":5}}}"); patchedSettings = mapper.readTree("{\"I\": 76, \"F\": 92}");
updatedSettings = doPut("/api/user/settings", patchedSettings, JsonNode.class); doPut("/api/user/settings/B.E", patchedSettings);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":10, \"C\":{\"D\": {\"A\":5}, \"E\": 22}, \"E\":18}"); updatedSettings = doGet("/api/user/settings", JsonNode.class);
expectedSettings = mapper.readTree("{\"A\":10, \"B\":{\"E\": {\"I\":76, \"F\": 92}}}");
Assert.assertEquals(expectedSettings, updatedSettings); Assert.assertEquals(expectedSettings, updatedSettings);
} }
@Test @Test

5
common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserSettingsService.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.dao.user; package org.thingsboard.server.dao.user;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserSettings; import org.thingsboard.server.common.data.security.UserSettings;
@ -23,7 +25,8 @@ import java.util.List;
public interface UserSettingsService { public interface UserSettingsService {
UserSettings updateUserSettings(TenantId tenantId, UserSettings userSettings); void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings);
void updateUserSettings(TenantId tenantId, UserId userId, String path, JsonNode settings);
UserSettings saveUserSettings(TenantId tenantId, UserSettings userSettings); UserSettings saveUserSettings(TenantId tenantId, UserSettings userSettings);

58
dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsServiceImpl.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.dao.user; package org.thingsboard.server.dao.user;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
@ -33,6 +35,7 @@ import org.thingsboard.server.dao.entity.AbstractCachedService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
@ -51,13 +54,37 @@ public class UserSettingsServiceImpl extends AbstractCachedService<UserId, UserS
} }
@Override @Override
public UserSettings updateUserSettings(TenantId tenantId, UserSettings userSettings) { public void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings) {
log.trace("Executing updateUserSettings for user [{}], [{}]", userSettings.getUserId(), userSettings); log.trace("Executing updateUserSettings for user [{}], [{}]", userId, settings);
validateId(userSettings.getUserId(), INCORRECT_USER_ID + userSettings.getUserId()); validateId(userId, INCORRECT_USER_ID + userId);
UserSettings oldSettings = userSettingsDao.findById(tenantId, userSettings.getUserId());
UserSettings oldSettings = userSettingsDao.findById(tenantId, userId);
JsonNode oldSettingsJson = oldSettings != null ? oldSettings.getSettings() : JacksonUtil.newObjectNode(); JsonNode oldSettingsJson = oldSettings != null ? oldSettings.getSettings() : JacksonUtil.newObjectNode();
userSettings.setSettings(merge(oldSettingsJson, userSettings.getSettings()));
return doSaveUserSettings(tenantId, userSettings); UserSettings newUserSettings = new UserSettings();
newUserSettings.setUserId(userId);
newUserSettings.setSettings(update(oldSettingsJson, settings));
doSaveUserSettings(tenantId, newUserSettings);
}
@Override
public void updateUserSettings(TenantId tenantId, UserId userId, String path, JsonNode settings) {
log.trace("Executing updateUserSettings for user [{}], [{}]", userId, settings);
validateId(userId, INCORRECT_USER_ID + userId);
UserSettings oldSettings = userSettingsDao.findById(tenantId, userId);
UserSettings newUserSettings = new UserSettings();
newUserSettings.setUserId(userId);
JsonNode oldSettingsJson = oldSettings != null ? oldSettings.getSettings() : JacksonUtil.newObjectNode();
DocumentContext dcSettings = JsonPath.parse(oldSettingsJson.toString());
dcSettings = dcSettings.set("$." + path, new ObjectMapper().convertValue(settings, new TypeReference<Map<String, Object>>(){}));
try {
newUserSettings.setSettings(new ObjectMapper().readValue(dcSettings.jsonString(), ObjectNode.class));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
doSaveUserSettings(tenantId, newUserSettings);
} }
@Override @Override
@ -78,11 +105,11 @@ public class UserSettingsServiceImpl extends AbstractCachedService<UserId, UserS
return; return;
} }
try { try {
DocumentContext docSettings = JsonPath.parse(userSettings.getSettings().toString()); DocumentContext dcSettings = JsonPath.parse(userSettings.getSettings().toString());
for (String s : jsonPaths) { for (String s : jsonPaths) {
docSettings = docSettings.delete("$." + s); dcSettings = dcSettings.delete("$." + s);
} }
userSettings.setSettings(new ObjectMapper().readValue(docSettings.jsonString(), ObjectNode.class)); userSettings.setSettings(new ObjectMapper().readValue(dcSettings.jsonString(), ObjectNode.class));
} catch (Exception t) { } catch (Exception t) {
handleEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId())); handleEvictEvent(new UserSettingsEvictEvent(userSettings.getUserId()));
throw new RuntimeException(t); throw new RuntimeException(t);
@ -110,19 +137,12 @@ public class UserSettingsServiceImpl extends AbstractCachedService<UserId, UserS
cache.evict(keys); cache.evict(keys);
} }
public JsonNode merge(JsonNode mainNode, JsonNode updateNode) { public JsonNode update(JsonNode mainNode, JsonNode updateNode) {
Iterator<String> fieldNames = updateNode.fieldNames(); Iterator<String> fieldNames = updateNode.fieldNames();
while (fieldNames.hasNext()) { while (fieldNames.hasNext()) {
String fieldName = fieldNames.next(); String fieldName = fieldNames.next();
JsonNode jsonNode = mainNode.get(fieldName); JsonNode value = updateNode.get(fieldName);
if (jsonNode != null && jsonNode.isObject()) { ((ObjectNode) mainNode).set(fieldName, value);
merge(jsonNode, updateNode.get(fieldName));
} else {
if (mainNode instanceof ObjectNode) {
JsonNode value = updateNode.get(fieldName);
((ObjectNode) mainNode).set(fieldName, value);
}
}
} }
return mainNode; return mainNode;
} }

Loading…
Cancel
Save