diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index a6bb7d4d67..34f065d500 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -103,6 +103,7 @@ import org.thingsboard.server.common.data.rpc.Rpc; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.settings.UserDashboardAction; import org.thingsboard.server.common.data.util.ThrowingBiFunction; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; @@ -169,6 +170,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.StringUtils.isNotEmpty; @@ -446,6 +448,14 @@ public abstract class BaseController { } } + protected T checkEnumParameter(String name, String param, Function valueOf) throws ThingsboardException { + try { + return valueOf.apply(param.toUpperCase()); + } catch (IllegalArgumentException e) { + throw new ThingsboardException(name + " \"" + param + "\" is not supported!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + } + UUID toUUID(String id) throws ThingsboardException { try { return UUID.fromString(id); diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index 4536d77a62..311622db5d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.settings.UserDashboardsInfo; import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.common.data.security.model.JwtPair; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.user.TbUserService; import org.thingsboard.server.service.query.EntityQueryService; @@ -451,7 +452,7 @@ public class UserController extends BaseController { SecurityUser currentUser = getCurrentUser(); UserSettings userSettings = new UserSettings(); - userSettings.setType(UserSettings.GENERAL); + userSettings.setType(UserSettingsType.GENERAL); userSettings.setSettings(settings); userSettings.setUserId(currentUser.getId()); return userSettingsService.saveUserSettings(currentUser.getTenantId(), userSettings).getSettings(); @@ -465,7 +466,7 @@ public class UserController extends BaseController { @PutMapping(value = "/user/settings") public void putUserSettings(@RequestBody JsonNode settings) throws ThingsboardException { SecurityUser currentUser = getCurrentUser(); - userSettingsService.updateUserSettings(currentUser.getTenantId(), currentUser.getId(), settings); + userSettingsService.updateUserSettings(currentUser.getTenantId(), currentUser.getId(), UserSettingsType.GENERAL, settings); } @ApiOperation(value = "Get user settings (getUserSettings)", @@ -475,7 +476,7 @@ public class UserController extends BaseController { public JsonNode getUserSettings() throws ThingsboardException { SecurityUser currentUser = getCurrentUser(); - UserSettings userSettings = userSettingsService.findUserSettings(currentUser.getTenantId(), currentUser.getId()); + UserSettings userSettings = userSettingsService.findUserSettings(currentUser.getTenantId(), currentUser.getId(), UserSettingsType.GENERAL); return userSettings == null ? JacksonUtil.newObjectNode() : userSettings.getSettings(); } @@ -489,7 +490,50 @@ public class UserController extends BaseController { checkParameter(USER_ID, paths); SecurityUser currentUser = getCurrentUser(); - userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), Arrays.asList(paths.split(","))); + userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), UserSettingsType.GENERAL, Arrays.asList(paths.split(","))); + } + + @ApiOperation(value = "Update user settings (saveUserSettings)", + notes = "Update user settings for authorized user. Only specified json elements will be updated." + + "Example: you have such settings: {A:5, B:{C:10, D:20}}. Updating it with {B:{C:10, D:30}} will result in" + + "{A:5, B:{C:10, D:30}}. The same could be achieved by putting {B.D:30}") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @PutMapping(value = "/user/settings/{type}") + public void putUserSettings(@ApiParam(value = "Settings type, one of: \"visit\", \"star\" or \"unstar\".") + @PathVariable("type") String strType, @RequestBody JsonNode settings) throws ThingsboardException { + SecurityUser currentUser = getCurrentUser(); + UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf); + checkNotReserved(strType, type); + userSettingsService.updateUserSettings(currentUser.getTenantId(), currentUser.getId(), type, settings); + } + + @ApiOperation(value = "Get user settings (getUserSettings)", + notes = "Fetch the User settings based on authorized user. ") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @GetMapping(value = "/user/settings/{type}") + public JsonNode getUserSettings(@ApiParam(value = "Settings type, one of: \"visit\", \"star\" or \"unstar\".") + @PathVariable("type") String strType) throws ThingsboardException { + SecurityUser currentUser = getCurrentUser(); + UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf); + checkNotReserved(strType, type); + UserSettings userSettings = userSettingsService.findUserSettings(currentUser.getTenantId(), currentUser.getId(), type); + return userSettings == null ? JacksonUtil.newObjectNode() : userSettings.getSettings(); + } + + @ApiOperation(value = "Delete user settings (deleteUserSettings)", + 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") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/user/settings/{type}/{paths}", method = RequestMethod.DELETE) + public void deleteUserSettings(@ApiParam(value = PATHS) + @PathVariable(PATHS) String paths, + @ApiParam(value = "Settings type, one of: \"visit\", \"star\" or \"unstar\".") + @PathVariable("type") String strType) throws ThingsboardException { + checkParameter(USER_ID, paths); + UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf); + checkNotReserved(strType, type); + SecurityUser currentUser = getCurrentUser(); + userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), type, Arrays.asList(paths.split(","))); } @ApiOperation(value = "Get information about last visited and starred dashboards (getLastVisitedDashboards)", @@ -513,16 +557,17 @@ public class UserController extends BaseController { @PathVariable("action") String strAction) throws ThingsboardException { checkParameter(DashboardController.DASHBOARD_ID, strDashboardId); checkParameter("action", strAction); + UserDashboardAction action = checkEnumParameter("Action", strAction, UserDashboardAction::valueOf); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - DashboardInfo dashboard = checkDashboardInfoId(dashboardId, Operation.READ); - UserDashboardAction action; - try { - action = UserDashboardAction.valueOf(strAction.toUpperCase()); - } catch (IllegalArgumentException e) { - throw new ThingsboardException("Action: " + strAction + " is not supported!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } + checkDashboardInfoId(dashboardId, Operation.READ); SecurityUser currentUser = getCurrentUser(); return userSettingsService.reportUserDashboardAction(currentUser.getTenantId(), currentUser.getId(), dashboardId, action); } + private void checkNotReserved(String strType, UserSettingsType type) throws ThingsboardException { + if (type.isReserved()) { + throw new ThingsboardException("Settings with type: " + strType + " are reserved for internal use!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java index 20a20a4bfc..3942cc6ad2 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java @@ -18,7 +18,6 @@ package org.thingsboard.server.service.entitiy.user; import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.HasTitle; @@ -32,12 +31,14 @@ import org.thingsboard.server.common.data.settings.StarredDashboardInfo; import org.thingsboard.server.common.data.settings.UserDashboardAction; import org.thingsboard.server.common.data.settings.UserDashboardsInfo; import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.user.UserSettingsService; import org.thingsboard.server.queue.util.TbCoreComponent; -import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -64,48 +65,33 @@ public class DefaultTbUserSettingsService implements TbUserSettingsService { } @Override - public void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings) { - updateUserSettings(tenantId, userId, UserSettings.GENERAL, settings); - } - - @Override - public void updateUserSettings(TenantId tenantId, UserId userId, String type, JsonNode settings) { + public void updateUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, JsonNode settings) { settingsService.updateUserSettings(tenantId, userId, type, settings); } @Override - public UserSettings findUserSettings(TenantId tenantId, UserId userId) { - return findUserSettings(tenantId, userId, UserSettings.GENERAL); - } - - @Override - public UserSettings findUserSettings(TenantId tenantId, UserId userId, String type) { + public UserSettings findUserSettings(TenantId tenantId, UserId userId, UserSettingsType type) { return settingsService.findUserSettings(tenantId, userId, type); } @Override - public void deleteUserSettings(TenantId tenantId, UserId userId, List jsonPaths) { - deleteUserSettings(tenantId, userId, UserSettings.GENERAL, jsonPaths); - } - - @Override - public void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths) { + public void deleteUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, List jsonPaths) { settingsService.deleteUserSettings(tenantId, userId, type, jsonPaths); } @Override public UserDashboardsInfo findUserDashboardsInfo(TenantId tenantId, UserId id) { - UserSettings us = findUserSettings(tenantId, id, UserSettings.STARRED_DASHBOARDS); + UserSettings us = findUserSettings(tenantId, id, UserSettingsType.VISITED_DASHBOARDS); if (us == null) { return UserDashboardsInfo.EMPTY; } UserDashboardsInfo stored = JacksonUtil.convertValue(us.getSettings(), UserDashboardsInfo.class); - return getUserDashboardsInfo(tenantId, stored); + return refreshDashboardTitles(tenantId, stored); } @Override public UserDashboardsInfo reportUserDashboardAction(TenantId tenantId, UserId id, DashboardId dashboardId, UserDashboardAction action) { - UserSettings us = findUserSettings(tenantId, id, UserSettings.STARRED_DASHBOARDS); + UserSettings us = findUserSettings(tenantId, id, UserSettingsType.VISITED_DASHBOARDS); UserDashboardsInfo stored = null; if (us != null) { stored = JacksonUtil.convertValue(us.getSettings(), UserDashboardsInfo.class); @@ -126,24 +112,26 @@ public class DefaultTbUserSettingsService implements TbUserSettingsService { break; } + stored = refreshDashboardTitles(tenantId, stored); + us = new UserSettings(); us.setUserId(id); - us.setType(UserSettings.STARRED_DASHBOARDS); + us.setType(UserSettingsType.VISITED_DASHBOARDS); us.setSettings(JacksonUtil.valueToTree(stored)); saveUserSettings(tenantId, us); - return getUserDashboardsInfo(tenantId, stored); + return stored; } private void addToVisited(UserDashboardsInfo stored, DashboardId dashboardId) { UUID id = dashboardId.getId(); long ts = System.currentTimeMillis(); - var opt = stored.getLast().stream().filter(d -> id.equals(d.getId())).findFirst(); + var opt = stored.getLast().stream().filter(filterById(id)).findFirst(); if (opt.isPresent()) { opt.get().setLastVisited(ts); } else { var newInfo = new LastVisitedDashboardInfo(); newInfo.setId(id); - newInfo.setStarred(stored.getStarred().stream().anyMatch(d -> id.equals(d.getId()))); + newInfo.setStarred(stored.getStarred().stream().anyMatch(filterById(id))); newInfo.setLastVisited(System.currentTimeMillis()); stored.getLast().add(newInfo); } @@ -155,14 +143,14 @@ public class DefaultTbUserSettingsService implements TbUserSettingsService { private void removeFromStarred(UserDashboardsInfo stored, DashboardId dashboardId) { UUID id = dashboardId.getId(); - stored.getStarred().removeIf(d -> id.equals(d.getId())); + stored.getStarred().removeIf(filterById(id)); stored.getLast().stream().filter(d -> id.equals(d.getId())).findFirst().ifPresent(d -> d.setStarred(false)); } private void addToStarred(UserDashboardsInfo stored, DashboardId dashboardId) { UUID id = dashboardId.getId(); long ts = System.currentTimeMillis(); - var opt = stored.getStarred().stream().filter(d -> id.equals(d.getId())).findFirst(); + var opt = stored.getStarred().stream().filter(filterById(id)).findFirst(); if (opt.isPresent()) { opt.get().setStarredAt(ts); } else { @@ -180,31 +168,34 @@ public class DefaultTbUserSettingsService implements TbUserSettingsService { stored.getLast().forEach(d -> d.setStarred(starredMap.contains(d.getId()))); } - private void setTitleIfEmpty(TenantId tenantId, AbstractUserDashboardInfo i) { - if (StringUtils.isEmpty(i.getTitle())) { - var dashboardInfo = dashboardService.findDashboardInfoById(tenantId, new DashboardId(i.getId())); - i.setTitle(dashboardInfo != null ? dashboardInfo.getTitle() : null); - } + private Predicate filterById(UUID id) { + return d -> id.equals(d.getId()); } - private UserDashboardsInfo getUserDashboardsInfo(TenantId tenantId, UserDashboardsInfo stored) { + private UserDashboardsInfo refreshDashboardTitles(TenantId tenantId, UserDashboardsInfo stored) { if (stored == null) { return UserDashboardsInfo.EMPTY; } - - if (!stored.getLast().isEmpty()) { - stored.getLast().forEach(i -> setTitleIfEmpty(tenantId, i)); - stored.getLast().removeIf(EMPTY_TITLE); - } - if (!stored.getStarred().isEmpty()) { - Map lastMap = stored.getLast().stream().collect(Collectors.toMap(LastVisitedDashboardInfo::getId, Function.identity())); - stored.getStarred().forEach(i -> { - var last = lastMap.get(i.getId()); - i.setTitle(last != null ? last.getTitle() : null); - }); - stored.getStarred().forEach(i -> setTitleIfEmpty(tenantId, i)); - stored.getStarred().removeIf(EMPTY_TITLE); - } + stored.getLast().forEach(i -> i.setTitle(null)); + stored.getStarred().forEach(i -> i.setTitle(null)); + + Set uniqueIds = new HashSet<>(); + stored.getLast().stream().map(AbstractUserDashboardInfo::getId).forEach(uniqueIds::add); + stored.getStarred().stream().map(AbstractUserDashboardInfo::getId).forEach(uniqueIds::add); + + Map dashboardTitles = new HashMap<>(); + uniqueIds.forEach(id -> { + var dashboardInfo = dashboardService.findDashboardInfoById(tenantId, new DashboardId(id)); + if (dashboardInfo != null && StringUtils.isNotEmpty(dashboardInfo.getTitle())) { + dashboardTitles.put(id, dashboardInfo.getTitle()); + } + } + ); + + stored.getLast().forEach(i -> i.setTitle(dashboardTitles.get(i.getId()))); + stored.getLast().removeIf(EMPTY_TITLE); + stored.getStarred().forEach(i -> i.setTitle(dashboardTitles.get(i.getId()))); + stored.getStarred().removeIf(EMPTY_TITLE); return stored; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserSettingsService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserSettingsService.java index 6632e1977c..a81dbcad2f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserSettingsService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserSettingsService.java @@ -22,24 +22,19 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.settings.UserDashboardAction; import org.thingsboard.server.common.data.settings.UserDashboardsInfo; import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsType; import java.util.List; public interface TbUserSettingsService { - void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings); - - void updateUserSettings(TenantId tenantId, UserId userId, String type, JsonNode settings); + void updateUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, JsonNode settings); UserSettings saveUserSettings(TenantId tenantId, UserSettings userSettings); - UserSettings findUserSettings(TenantId tenantId, UserId userId); - - UserSettings findUserSettings(TenantId tenantId, UserId userId, String type); - - void deleteUserSettings(TenantId tenantId, UserId userId, List jsonPaths); + UserSettings findUserSettings(TenantId tenantId, UserId userId, UserSettingsType type); - void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths); + void deleteUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, List jsonPaths); UserDashboardsInfo findUserDashboardsInfo(TenantId tenantId, UserId id); 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 84fab2d971..fd971fd72a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -1103,6 +1103,30 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { starred = newSettings.getStarred().get(0); Assert.assertEquals(savedDashboard2.getId().getId(), starred.getId()); Assert.assertEquals(savedDashboard2.getTitle(), starred.getTitle()); + + doDelete("/api/dashboard/" + savedDashboard1.getId().getId().toString()).andExpect(status().isOk()); + + newSettings = doGet("/api/user/dashboards", UserDashboardsInfo.class); + Assert.assertNotNull(newSettings); + Assert.assertNotNull(newSettings.getLast()); + Assert.assertEquals(1, newSettings.getLast().size()); + lastVisited = newSettings.getLast().get(0); + Assert.assertEquals(savedDashboard2.getId().getId(), lastVisited.getId()); + Assert.assertEquals(savedDashboard2.getTitle(), lastVisited.getTitle()); + Assert.assertTrue(lastVisited.isStarred()); + Assert.assertEquals(1, newSettings.getStarred().size()); + starred = newSettings.getStarred().get(0); + Assert.assertEquals(savedDashboard2.getId().getId(), starred.getId()); + Assert.assertEquals(savedDashboard2.getTitle(), starred.getTitle()); + + doDelete("/api/dashboard/" + savedDashboard2.getId().getId().toString()).andExpect(status().isOk()); + + retrievedSettings = doGet("/api/user/dashboards", UserDashboardsInfo.class); + Assert.assertNotNull(retrievedSettings); + Assert.assertNotNull(retrievedSettings.getLast()); + Assert.assertTrue(retrievedSettings.getLast().isEmpty()); + Assert.assertNotNull(retrievedSettings.getStarred()); + Assert.assertTrue(retrievedSettings.getStarred().isEmpty()); } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index 7c47efafc3..c6c87c07bf 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -36,6 +36,8 @@ public interface DashboardService extends EntityDaoService { DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId); +// String findDashboardTitleById(TenantId tenantId, DashboardId dashboardId); + ListenableFuture findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId); Dashboard saveDashboard(Dashboard dashboard); 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 c2531c5d65..58ac697409 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 @@ -19,17 +19,18 @@ import com.fasterxml.jackson.databind.JsonNode; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsType; import java.util.List; public interface UserSettingsService { - void updateUserSettings(TenantId tenantId, UserId userId, String type, JsonNode settings); + void updateUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, JsonNode settings); UserSettings saveUserSettings(TenantId tenantId, UserSettings userSettings); - UserSettings findUserSettings(TenantId tenantId, UserId userId, String type); + UserSettings findUserSettings(TenantId tenantId, UserId userId, UserSettingsType type); - void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths); + void deleteUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, List jsonPaths); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java index f1318dedfd..3969c6d851 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java @@ -40,16 +40,13 @@ public class UserSettings implements Serializable { private static final long serialVersionUID = 2628320657987010348L; - public static final String GENERAL = "general"; - public static final String STARRED_DASHBOARDS = "starred_dashboards"; - @ApiModelProperty(position = 1, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private UserId userId; @ApiModelProperty(position = 2, value = "Type of the settings.") @NoXss @Length(fieldName = "type", max = 50) - private transient String type; + private UserSettingsType type; @ApiModelProperty(position = 3, value = "JSON object with user settings.", dataType = "com.fasterxml.jackson.databind.JsonNode") @NoXss diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsCompositeKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsCompositeKey.java index 72fb432fd4..eba902fd7f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsCompositeKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsCompositeKey.java @@ -34,7 +34,7 @@ public class UserSettingsCompositeKey implements Serializable { public UserSettingsCompositeKey(UserSettings userSettings) { this.userId = userSettings.getUserId().getId(); - this.type = userSettings.getType(); + this.type = userSettings.getType().name(); } @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java new file mode 100644 index 0000000000..97ef85a5f2 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.settings; + +import lombok.Getter; + +public enum UserSettingsType { + + GENERAL, VISITED_DASHBOARDS(true), QUICK_LINKS, DOC_LINKS, DASHBOARDS; + + @Getter + private final boolean reserved; + + UserSettingsType() { + this.reserved = false; + } + + UserSettingsType(boolean reserved) { + this.reserved = reserved; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserSettingsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserSettingsEntity.java index 1c38017097..a00efff52f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserSettingsEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserSettingsEntity.java @@ -23,6 +23,7 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ToData; import org.thingsboard.server.dao.util.mapping.JsonStringType; @@ -54,7 +55,7 @@ public class UserSettingsEntity implements ToData { public UserSettingsEntity(UserSettings userSettings) { this.userId = userSettings.getUserId().getId(); - this.type = userSettings.getType(); + this.type = userSettings.getType().name(); if (userSettings.getSettings() != null) { this.settings = userSettings.getSettings(); } @@ -64,7 +65,7 @@ public class UserSettingsEntity implements ToData { public UserSettings toData() { UserSettings userSettings = new UserSettings(); userSettings.setUserId(new UserId(userId)); - userSettings.setType(type); + userSettings.setType(UserSettingsType.valueOf(type)); if (settings != null) { userSettings.setSettings(settings); } 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 88321faf66..86e63d3529 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 @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.entity.AbstractCachedService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.ConstraintValidator; @@ -55,11 +56,11 @@ public class UserSettingsServiceImpl extends AbstractCachedService userSettingsDao.findById(tenantId, key), true); } @Override - public void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths) { + public void deleteUserSettings(TenantId tenantId, UserId userId, UserSettingsType type, List jsonPaths) { log.trace("Executing deleteUserSettings for user [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); - var key = new UserSettingsCompositeKey(userId.getId(), type); + var key = new UserSettingsCompositeKey(userId.getId(), type.name()); UserSettings userSettings = userSettingsDao.findById(tenantId, key); if (userSettings == null) { return; diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDaoTest.java index d161af6b21..da38929ed7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDaoTest.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.AbstractJpaDaoTest; import org.thingsboard.server.dao.service.AbstractServiceTest; import org.thingsboard.server.dao.user.UserDao; @@ -67,18 +68,18 @@ public class JpaUserSettingsDaoTest extends AbstractJpaDaoTest { public void testFindSettingsByUserId() { UserSettings userSettings = createUserSettings(user.getId()); - UserSettings retrievedUserSettings = userSettingsDao.findById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettings.GENERAL)); + UserSettings retrievedUserSettings = userSettingsDao.findById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettingsType.GENERAL.name())); assertEquals(retrievedUserSettings.getSettings(), userSettings.getSettings()); - userSettingsDao.removeById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettings.GENERAL)); + userSettingsDao.removeById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettingsType.GENERAL.name())); - UserSettings retrievedUserSettings2 = userSettingsDao.findById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettings.GENERAL)); + UserSettings retrievedUserSettings2 = userSettingsDao.findById(SYSTEM_TENANT_ID, new UserSettingsCompositeKey(user.getId().getId(), UserSettingsType.GENERAL.name())); assertNull(retrievedUserSettings2); } private UserSettings createUserSettings(UserId userId) { UserSettings userSettings = new UserSettings(); - userSettings.setType(UserSettings.GENERAL); + userSettings.setType(UserSettingsType.GENERAL); userSettings.setSettings(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); userSettings.setUserId(userId); return userSettingsDao.save(SYSTEM_TENANT_ID, userSettings);