diff --git a/application/src/main/data/upgrade/3.4.4/schema_update.sql b/application/src/main/data/upgrade/3.4.4/schema_update.sql index 6860adc612..5965837898 100644 --- a/application/src/main/data/upgrade/3.4.4/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.4/schema_update.sql @@ -167,11 +167,12 @@ CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notific ALTER TABLE tb_user ADD COLUMN IF NOT EXISTS phone VARCHAR(255); CREATE TABLE IF NOT EXISTS user_settings ( - user_id uuid NOT NULL CONSTRAINT user_settings_pkey PRIMARY KEY, - settings varchar(100000), - CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE + user_id uuid NOT NULL, + type VARCHAR(50) NOT NULL, + settings varchar(10000), + CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE, + CONSTRAINT user_settings_pkey PRIMARY KEY (user_id, type) ); - -- ALARM INFO VIEW DROP VIEW IF EXISTS alarm_info CASCADE; 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 a68955d9b4..a6bb7d4d67 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -146,6 +146,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.edge.instructions.EdgeInstallService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; +import org.thingsboard.server.service.entitiy.user.TbUserSettingsService; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache; @@ -202,7 +203,7 @@ public abstract class BaseController { protected UserService userService; @Autowired - protected UserSettingsService userSettingsService; + protected TbUserSettingsService userSettingsService; @Autowired protected DeviceService deviceService; 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 06963e466f..341ec387e9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -38,12 +38,14 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.MailService; +import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.UserEmailInfo; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; @@ -55,7 +57,10 @@ import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.LastVisitedDashboardInfo; +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.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.common.data.security.model.JwtPair; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -76,6 +81,7 @@ import java.util.Map; import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEFAULT_DASHBOARD; import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; @@ -438,13 +444,14 @@ public class UserController extends BaseController { } @ApiOperation(value = "Save user settings (saveUserSettings)", - notes = "Save user settings represented in json format for authorized user. " ) + notes = "Save user settings represented in json format for authorized user. ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @PostMapping(value = "/user/settings") public JsonNode saveUserSettings(@RequestBody JsonNode settings) throws ThingsboardException { SecurityUser currentUser = getCurrentUser(); UserSettings userSettings = new UserSettings(); + userSettings.setType(UserSettings.GENERAL); userSettings.setSettings(settings); userSettings.setUserId(currentUser.getId()); return userSettingsService.saveUserSettings(currentUser.getTenantId(), userSettings).getSettings(); @@ -462,27 +469,60 @@ public class UserController extends BaseController { } @ApiOperation(value = "Get user settings (getUserSettings)", - notes = "Fetch the User settings based on authorized user. " ) + notes = "Fetch the User settings based on authorized user. ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @GetMapping(value = "/user/settings") public JsonNode getUserSettings() throws ThingsboardException { SecurityUser currentUser = getCurrentUser(); UserSettings userSettings = userSettingsService.findUserSettings(currentUser.getTenantId(), currentUser.getId()); - return userSettings == null ? JacksonUtil.newObjectNode(): userSettings.getSettings(); + 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" ) + "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/{paths}", method = RequestMethod.DELETE) public void deleteUserSettings(@ApiParam(value = PATHS) - @PathVariable(PATHS) String paths) throws ThingsboardException { + @PathVariable(PATHS) String paths) throws ThingsboardException { checkParameter(USER_ID, paths); SecurityUser currentUser = getCurrentUser(); userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), Arrays.asList(paths.split(","))); } + @ApiOperation(value = "Get information about last visited and starred dashboards (getLastVisitedDashboards)", + notes = "Fetch the list of last visited and starred dashboards. Both lists are limited to 10 items.") + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @GetMapping(value = "/user/dashboards") + public UserDashboardsInfo getUserDashboardsInfo() throws ThingsboardException { + SecurityUser currentUser = getCurrentUser(); + return userSettingsService.findUserDashboardsInfo(currentUser.getTenantId(), currentUser.getId()); + } + + @ApiOperation(value = "Report action of User over the dashboard (reportUserDashboardAction)", + notes = "Enables or Disables user credentials. Useful when you would like to block user account without deleting it. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/user/dashboards/{dashboardId}/{action}", method = RequestMethod.POST) + @ResponseBody + public UserDashboardsInfo reportUserDashboardAction( + @ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION) + @PathVariable(DashboardController.DASHBOARD_ID) String strDashboardId, + @ApiParam(value = "Dashboard action, one of: \"visit\", \"star\" or \"unstar\".") + @PathVariable("action") String strAction) throws ThingsboardException { + checkParameter(DashboardController.DASHBOARD_ID, strDashboardId); + checkParameter("action", strAction); + 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); + } + SecurityUser currentUser = getCurrentUser(); + return userSettingsService.reportUserDashboardAction(currentUser.getTenantId(), currentUser.getId(), dashboardId, action); + } + } 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 new file mode 100644 index 0000000000..add2343e84 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java @@ -0,0 +1,186 @@ +/** + * 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.service.entitiy.user; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.HasTitle; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.settings.AbstractUserDashboardInfo; +import org.thingsboard.server.common.data.settings.LastVisitedDashboardInfo; +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.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.user.UserSettingsService; +import org.thingsboard.server.queue.util.TbCoreComponent; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@Service +@TbCoreComponent +@AllArgsConstructor +@Slf4j +public class DefaultTbUserSettingsService implements TbUserSettingsService { + + private static final int MAX_DASHBOARD_INFO_LIST_SIZE = 10; + private static final Predicate EMPTY_TITLE = i -> StringUtils.isNotEmpty(i.getTitle()); + + private final UserSettingsService settingsService; + private final DashboardService dashboardService; + + @Override + public UserSettings saveUserSettings(TenantId tenantId, UserSettings userSettings) { + return settingsService.saveUserSettings(tenantId, userSettings); + } + + @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) { + 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) { + 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) { + settingsService.deleteUserSettings(tenantId, userId, type, jsonPaths); + } + + @Override + public UserDashboardsInfo findUserDashboardsInfo(TenantId tenantId, UserId id) { + UserSettings us = findUserSettings(tenantId, id, UserSettings.STARRED_DASHBOARDS); + if (us == null) { + return UserDashboardsInfo.EMPTY; + } + UserDashboardsInfo stored = JacksonUtil.convertValue(us.getSettings(), UserDashboardsInfo.class); + 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); + } + return stored; + } + + @Override + public UserDashboardsInfo reportUserDashboardAction(TenantId tenantId, UserId id, DashboardId dashboardId, UserDashboardAction action) { + UserSettings us = findUserSettings(tenantId, id, UserSettings.STARRED_DASHBOARDS); + UserDashboardsInfo stored = null; + if (us != null) { + stored = JacksonUtil.convertValue(us.getSettings(), UserDashboardsInfo.class); + } + if (stored == null) { + stored = new UserDashboardsInfo(); + } + + switch (action) { + case STAR: + addToStarred(stored, dashboardId); + break; + case UNSTAR: + removeFromStarred(stored, dashboardId); + break; + case VISIT: + addToVisited(stored, dashboardId); + break; + } + + us = new UserSettings(); + us.setUserId(id); + us.setType(UserSettings.STARRED_DASHBOARDS); + us.setSettings(JacksonUtil.valueToTree(stored)); + saveUserSettings(tenantId, us); + return stored; + } + + private void addToVisited(UserDashboardsInfo stored, DashboardId dashboardId) { + UUID id = dashboardId.getId(); + stored.getStarred().removeIf(d -> id.equals(d.getId())); + } + + private void removeFromStarred(UserDashboardsInfo stored, DashboardId dashboardId) { + UUID id = dashboardId.getId(); + stored.getStarred().removeIf(d -> id.equals(d.getId())); + 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(); + if (opt.isPresent()) { + opt.get().setStarredAt(ts); + } else { + var newInfo = new StarredDashboardInfo(); + newInfo.setId(id); + newInfo.setStarredAt(System.currentTimeMillis()); + stored.getStarred().add(newInfo); + } + stored.getLast().stream().filter(d -> id.equals(d.getId())).forEach(d -> d.setStarred(true)); + //TODO: self-heal if some of the dashboards were deleted. + //TODO: limit by size. + } + + 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); + } + } + + +} 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 new file mode 100644 index 0000000000..6632e1977c --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserSettingsService.java @@ -0,0 +1,47 @@ +/** + * 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.service.entitiy.user; + +import com.fasterxml.jackson.databind.JsonNode; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.TenantId; +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 java.util.List; + +public interface TbUserSettingsService { + + void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings); + + void updateUserSettings(TenantId tenantId, UserId userId, String 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); + + void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths); + + UserDashboardsInfo findUserDashboardsInfo(TenantId tenantId, UserId id); + + UserDashboardsInfo reportUserDashboardAction(TenantId tenantId, UserId id, DashboardId dashboardId, UserDashboardAction action); +} 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 2c6b149607..c2531c5d65 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 @@ -18,18 +18,18 @@ package org.thingsboard.server.dao.user; 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.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; import java.util.List; public interface UserSettingsService { - void updateUserSettings(TenantId tenantId, UserId userId, JsonNode settings); + void updateUserSettings(TenantId tenantId, UserId userId, String 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); + void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/AbstractUserDashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/AbstractUserDashboardInfo.java new file mode 100644 index 0000000000..ce214cb603 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/AbstractUserDashboardInfo.java @@ -0,0 +1,37 @@ +/** + * 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 io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.thingsboard.server.common.data.HasTitle; + +import java.io.Serializable; +import java.util.UUID; + +@ApiModel +@Data +public abstract class AbstractUserDashboardInfo implements HasTitle, Serializable { + + private static final long serialVersionUID = -6461562426034242608L; + + @ApiModelProperty(position = 1, value = "JSON object with Dashboard id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private UUID id; + @ApiModelProperty(position = 2, value = "Title of the dashboard.") + private String title; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/LastVisitedDashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/LastVisitedDashboardInfo.java new file mode 100644 index 0000000000..e49910eb43 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/LastVisitedDashboardInfo.java @@ -0,0 +1,37 @@ +/** + * 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 io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode(callSuper = true) +@ApiModel +@Data +public class LastVisitedDashboardInfo extends AbstractUserDashboardInfo implements Serializable { + + private static final long serialVersionUID = -6461562426034242608L; + + @ApiModelProperty(position = 3, value = "Starred flag") + private boolean starred; + @ApiModelProperty(position = 4, value = "Last visit timestamp") + private long lastVisited; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/StarredDashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/StarredDashboardInfo.java new file mode 100644 index 0000000000..1e281bd95d --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/StarredDashboardInfo.java @@ -0,0 +1,36 @@ +/** + * 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 io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.HasTitle; +import org.thingsboard.server.common.data.id.DashboardId; + +import java.io.Serializable; + +@EqualsAndHashCode(callSuper = true) +@ApiModel +@Data +public class StarredDashboardInfo extends AbstractUserDashboardInfo implements Serializable { + + private static final long serialVersionUID = -7830828696329673361L; + @ApiModelProperty(position = 4, value = "Starred timestamp") + private long starredAt; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardAction.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardAction.java new file mode 100644 index 0000000000..f89e29a45f --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardAction.java @@ -0,0 +1,22 @@ +/** + * 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; + +public enum UserDashboardAction { + + VISIT, STAR, UNSTAR + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardsInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardsInfo.java new file mode 100644 index 0000000000..e5423f0d5d --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserDashboardsInfo.java @@ -0,0 +1,46 @@ +/** + * 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 io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@ApiModel +@Data +@AllArgsConstructor +public class UserDashboardsInfo implements Serializable { + + private static final long serialVersionUID = 2628320657987010348L; + public static final UserDashboardsInfo EMPTY = new UserDashboardsInfo(Collections.emptyList(), Collections.emptyList()); + + @ApiModelProperty(position = 1, value = "List of last visited dashboards.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private List last; + + @ApiModelProperty(position = 2, value = "List of starred dashboards.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private List starred; + + public UserDashboardsInfo() { + this(new ArrayList<>(), new ArrayList<>()); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/UserSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java similarity index 84% rename from common/data/src/main/java/org/thingsboard/server/common/data/security/UserSettings.java rename to common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java index 5a7fb19ffa..f1318dedfd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/UserSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettings.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.security; +package org.thingsboard.server.common.data.settings; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; @@ -40,10 +40,18 @@ 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 = "JSON object with user settings.", dataType = "com.fasterxml.jackson.databind.JsonNode") + @ApiModelProperty(position = 2, value = "Type of the settings.") + @NoXss + @Length(fieldName = "type", max = 50) + private transient String type; + + @ApiModelProperty(position = 3, value = "JSON object with user settings.", dataType = "com.fasterxml.jackson.databind.JsonNode") @NoXss @Length(fieldName = "settings", max = 100000) private transient JsonNode settings; 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 new file mode 100644 index 0000000000..72fb432fd4 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsCompositeKey.java @@ -0,0 +1,44 @@ +/** + * 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.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class UserSettingsCompositeKey implements Serializable { + + private static final long serialVersionUID = -7883642552545291489L; + + private UUID userId; + private String type; + + public UserSettingsCompositeKey(UserSettings userSettings) { + this.userId = userSettings.getUserId().getId(); + this.type = userSettings.getType(); + } + + @Override + public String toString() { + return userId.toString() + "_" + type; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index a0804e0c71..6197d8f908 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -94,6 +94,7 @@ public class ModelConstants { */ public static final String USER_SETTINGS_COLUMN_FAMILY_NAME = "user_settings"; public static final String USER_SETTINGS_USER_ID_PROPERTY = USER_ID_PROPERTY; + public static final String USER_SETTINGS_TYPE_PROPERTY = "type"; public static final String USER_SETTINGS_SETTINGS = "settings"; /** 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 d7abf7ea23..1c38017097 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 @@ -21,7 +21,8 @@ import lombok.NoArgsConstructor; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ToData; import org.thingsboard.server.dao.util.mapping.JsonStringType; @@ -29,6 +30,7 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.IdClass; import javax.persistence.Table; import java.util.UUID; @@ -37,19 +39,24 @@ import java.util.UUID; @TypeDef(name = "json", typeClass = JsonStringType.class) @Entity @Table(name = ModelConstants.USER_SETTINGS_COLUMN_FAMILY_NAME) +@IdClass(UserSettingsCompositeKey.class) public class UserSettingsEntity implements ToData { @Id @Column(name = ModelConstants.USER_SETTINGS_USER_ID_PROPERTY) private UUID userId; + @Id + @Column(name = ModelConstants.USER_SETTINGS_TYPE_PROPERTY) + private String type; @Type(type = "json") @Column(name = ModelConstants.USER_SETTINGS_SETTINGS) private JsonNode settings; public UserSettingsEntity(UserSettings userSettings) { this.userId = userSettings.getUserId().getId(); + this.type = userSettings.getType(); if (userSettings.getSettings() != null) { - this.settings= userSettings.getSettings(); + this.settings = userSettings.getSettings(); } } @@ -57,6 +64,7 @@ public class UserSettingsEntity implements ToData { public UserSettings toData() { UserSettings userSettings = new UserSettings(); userSettings.setUserId(new UserId(userId)); + userSettings.setType(type); if (settings != null) { userSettings.setSettings(settings); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDao.java index 13e8564206..e796faefdb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDao.java @@ -20,7 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.UserSettingsEntity; import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; @@ -41,13 +42,13 @@ public class JpaUserSettingsDao extends JpaAbstractDaoListeningExecutorService i } @Override - public UserSettings findById(TenantId tenantId, UserId userId) { - return DaoUtil.getData(userSettingsRepository.findById(userId.getId())); + public UserSettings findById(TenantId tenantId, UserId userId, String type) { + return DaoUtil.getData(userSettingsRepository.findById(new UserSettingsCompositeKey(userId.getId(), type))); } @Override - public void removeById(TenantId tenantId, UserId userId) { - userSettingsRepository.deleteById(userId.getId()); + public void removeById(TenantId tenantId, UserId userId, String type) { + userSettingsRepository.deleteById(new UserSettingsCompositeKey(userId.getId(), type)); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserSettingsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserSettingsRepository.java index 6b3e28abc9..f5f4603f14 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserSettingsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserSettingsRepository.java @@ -16,10 +16,11 @@ package org.thingsboard.server.dao.sql.user; import org.springframework.data.jpa.repository.JpaRepository; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; import org.thingsboard.server.dao.model.sql.UserSettingsEntity; import java.util.UUID; -public interface UserSettingsRepository extends JpaRepository { +public interface UserSettingsRepository extends JpaRepository { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsCaffeineCache.java index 3154e5d8c0..f8c55c5d94 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsCaffeineCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsCaffeineCache.java @@ -20,14 +20,13 @@ import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.thingsboard.server.cache.CaffeineTbTransactionalCache; import org.thingsboard.server.common.data.CacheConstants; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; -import org.thingsboard.server.dao.asset.AssetCacheKey; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) @Service("UserSettingsCache") -public class UserSettingsCaffeineCache extends CaffeineTbTransactionalCache { +public class UserSettingsCaffeineCache extends CaffeineTbTransactionalCache { public UserSettingsCaffeineCache(CacheManager cacheManager) { super(cacheManager, CacheConstants.USER_SETTINGS_CACHE); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsDao.java index 16a7675a64..8ebd6a534a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsDao.java @@ -17,14 +17,15 @@ package org.thingsboard.server.dao.user; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; public interface UserSettingsDao { UserSettings save(TenantId tenantId, UserSettings userSettings); - UserSettings findById(TenantId tenantId, UserId userId); + UserSettings findById(TenantId tenantId, UserSettingsCompositeKey key); - void removeById(TenantId tenantId, UserId userId); + void removeById(TenantId tenantId, UserSettingsCompositeKey key); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsEvictEvent.java index e0d2de7ece..bfe0142cc6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsEvictEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsEvictEvent.java @@ -17,8 +17,9 @@ package org.thingsboard.server.dao.user; import lombok.Data; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; @Data public class UserSettingsEvictEvent { - private final UserId userId; + private final UserSettingsCompositeKey key; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsRedisCache.java index a510e6c864..de321f3eb9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsRedisCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsRedisCache.java @@ -23,14 +23,13 @@ import org.thingsboard.server.cache.RedisTbTransactionalCache; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.cache.TbFSTRedisSerializer; import org.thingsboard.server.common.data.CacheConstants; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; -import org.thingsboard.server.dao.asset.AssetCacheKey; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") @Service("UserSettingsCache") -public class UserSettingsRedisCache extends RedisTbTransactionalCache { +public class UserSettingsRedisCache extends RedisTbTransactionalCache { public UserSettingsRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { super(CacheConstants.USER_SETTINGS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); 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 d94e060383..88321faf66 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 @@ -15,38 +15,35 @@ */ 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.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.fge.jackson.NodeType; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.PathNotFoundException; 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.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey; import org.thingsboard.server.dao.entity.AbstractCachedService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.ConstraintValidator; import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("UserSettingsDaoService") @Slf4j @RequiredArgsConstructor -public class UserSettingsServiceImpl extends AbstractCachedService implements UserSettingsService { +public class UserSettingsServiceImpl extends AbstractCachedService implements UserSettingsService { public static final String INCORRECT_USER_ID = "Incorrect userId "; private final UserSettingsDao userSettingsDao; @@ -58,33 +55,37 @@ public class UserSettingsServiceImpl extends AbstractCachedService userSettingsDao.findById(tenantId, userId), true); + var key = new UserSettingsCompositeKey(userId.getId(), type); + return cache.getAndPutInTransaction(key, + () -> userSettingsDao.findById(tenantId, key), true); } @Override - public void deleteUserSettings(TenantId tenantId, UserId userId, List jsonPaths) { + public void deleteUserSettings(TenantId tenantId, UserId userId, String type, List jsonPaths) { log.trace("Executing deleteUserSettings for user [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); - UserSettings userSettings = userSettingsDao.findById(tenantId, userId); + var key = new UserSettingsCompositeKey(userId.getId(), type); + UserSettings userSettings = userSettingsDao.findById(tenantId, key); if (userSettings == null) { return; } @@ -95,7 +96,7 @@ public class UserSettingsServiceImpl extends AbstractCachedService keys = new ArrayList<>(); - keys.add(event.getUserId()); - cache.evict(keys); + cache.evict(event.getKey()); } private void validateJsonKeys(JsonNode userSettings) { diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4e60c7105e..4197dc2b07 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -850,9 +850,11 @@ CREATE TABLE IF NOT EXISTS notification ( ) PARTITION BY RANGE (created_time); CREATE TABLE IF NOT EXISTS user_settings ( - user_id uuid NOT NULL CONSTRAINT user_settings_pkey PRIMARY KEY, + user_id uuid NOT NULL, + type VARCHAR(50) NOT NULL, settings varchar(10000), - CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE + CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE, + CONSTRAINT user_settings_pkey PRIMARY KEY (user_id, type) ); DROP VIEW IF EXISTS alarm_info CASCADE; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java index 14917f6807..c7ff515fb5 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java @@ -23,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -32,7 +31,7 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.user.UserService; 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 4260221a73..b5b578947d 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 @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.Authority; -import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.dao.AbstractJpaDaoTest; import org.thingsboard.server.dao.service.AbstractServiceTest; import org.thingsboard.server.dao.user.UserDao; @@ -66,17 +66,18 @@ public class JpaUserSettingsDaoTest extends AbstractJpaDaoTest { public void testFindSettingsByUserId() { UserSettings userSettings = createUserSettings(user.getId()); - UserSettings retrievedUserSettings = userSettingsDao.findById(SYSTEM_TENANT_ID, user.getId()); + UserSettings retrievedUserSettings = userSettingsDao.findById(SYSTEM_TENANT_ID, user.getId(), UserSettings.GENERAL); assertEquals(retrievedUserSettings.getSettings(), userSettings.getSettings()); - userSettingsDao.removeById(SYSTEM_TENANT_ID, user.getId()); + userSettingsDao.removeById(SYSTEM_TENANT_ID, user.getId(), UserSettings.GENERAL); - UserSettings retrievedUserSettings2 = userSettingsDao.findById(SYSTEM_TENANT_ID, user.getId()); + UserSettings retrievedUserSettings2 = userSettingsDao.findById(SYSTEM_TENANT_ID, user.getId(), UserSettings.GENERAL); assertNull(retrievedUserSettings2); } private UserSettings createUserSettings(UserId userId) { UserSettings userSettings = new UserSettings(); + userSettings.setType(UserSettings.GENERAL); userSettings.setSettings(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); userSettings.setUserId(userId); return userSettingsDao.save(SYSTEM_TENANT_ID, userSettings);