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 c86851fb88..6d08505fa8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -24,7 +24,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -33,6 +35,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.rule.engine.api.MailService; +import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; @@ -43,6 +46,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.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.user.TbUserService; @@ -378,4 +382,46 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Save user settings (saveUserSettings)", + notes = "Save user settings for specified user id. " ) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @PostMapping(value = "/user/{userId}/settings") + public UserSettings saveUserSettings(@ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId, @RequestBody UserSettings userSettings) throws ThingsboardException { + checkParameter(USER_ID, strUserId); + + UserId userId = new UserId(toUUID(strUserId)); + User user = checkUserId(userId, Operation.WRITE); + + userSettings.setUserId(userId); + return userService.saveUserSettings(user.getTenantId(), userId, userSettings); + } + + @ApiOperation(value = "Get user settings (getUserSettings)", + notes = "Fetch the User settings based on the provided User Id. " ) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @GetMapping(value = "/user/{userId}/settings") + public UserSettings getUserSettings(@ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId) throws ThingsboardException { + checkParameter(USER_ID, strUserId); + + UserId userId = new UserId(toUUID(strUserId)); + User user = checkUserId(userId, Operation.READ); + + return checkNotNull(userService.findUserSettings(user.getTenantId(), user.getId()), "No user settingd found"); + } + + @ApiOperation(value = "Delete user settings (deleteUserSettings)", + notes = "Delete user settings based on the provided User Id. " ) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/user/{userId}/settings", method = RequestMethod.DELETE) + public void deleteUserSettings(@ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId) throws ThingsboardException { + checkParameter(USER_ID, strUserId); + + UserId userId = new UserId(toUUID(strUserId)); + User user = checkUserId(userId, Operation.WRITE); + + userService.deleteUserSettings(user.getTenantId(), userId); + } } 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 c7934d13aa..87c69cb34b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -29,6 +29,8 @@ import org.springframework.context.annotation.Primary; import org.springframework.http.HttpHeaders; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.ResultActions; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +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; @@ -40,6 +42,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.UserSettings; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.user.UserDao; import org.thingsboard.server.service.mail.TestMailService; @@ -741,6 +744,52 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { assertThat(getErrorMessage(result)).containsIgnoringCase("invalid sort property"); } + @Test + public void testSaveUserSettings() throws Exception { + loginSysAdmin(); + + User user = createUser(); + User savedUser = doPost("/api/user", user, User.class); + + UserSettings userSettings = createUserSettings(); + UserSettings savedSettings = doPost("/api/user/" + savedUser.getId() + "/settings", userSettings, UserSettings.class); + Assert.assertEquals(savedSettings.getSettings(), savedSettings.getSettings()); + + UserSettings retrievedSettings = doGet("/api/user/" + savedUser.getId() + "/settings", UserSettings.class); + Assert.assertEquals(retrievedSettings.getSettings(), retrievedSettings.getSettings()); + + doDelete("/api/user/" + savedUser.getId() + "/settings"); + doGet("/api/user/" + savedUser.getId() + "/settings").andExpect(status().isNotFound()); + } + + @Test + public void testShouldNotSaveSettingsForOtherUser() throws Exception { + loginSysAdmin(); + + User user = createUser(); + User savedUser = doPost("/api/user", user, User.class); + + loginCustomerUser(); + UserSettings userSettings = createUserSettings(); + doPost("/api/user/" + savedUser.getId() + "/settings", userSettings) + .andExpect(status().isForbidden()); + } + @Test + public void testShouldDeleteSettingsAfterUserDeletion() throws Exception { + loginSysAdmin(); + + User user = createUser(); + User savedUser = doPost("/api/user", user, User.class); + + UserSettings userSettings = createUserSettings(); + UserSettings savedSettings = doPost("/api/user/" + savedUser.getId() + "/settings", userSettings, UserSettings.class); + Assert.assertEquals(savedSettings.getSettings(), savedSettings.getSettings()); + + doDelete("/api/user/" + savedUser.getId()) + .andExpect(status().isOk()); + doGet("/api/user/" + savedUser.getId() + "/settings").andExpect(status().isNotFound()); + } + private User createUser() throws Exception { loginSysAdmin(); String email = "tenant2@thingsboard.org"; @@ -752,4 +801,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { user.setLastName("Downs"); return doPost("/api/user", user, User.class); } + + private UserSettings createUserSettings() { + UserSettings userSettings = new UserSettings(); + userSettings.setSettings(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); + return userSettings; + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 9cce5e38b1..fa1ccd2130 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.UserCredentials; +import org.thingsboard.server.common.data.security.UserSettings; public interface UserService { @@ -73,4 +74,10 @@ public interface UserService { void setLastLoginTs(TenantId tenantId, UserId userId); + UserSettings saveUserSettings(TenantId tenantId, UserId userId, UserSettings userSettings); + + UserSettings findUserSettings(TenantId tenantId, UserId userId); + + void deleteUserSettings(TenantId tenantId, UserId userId); + } 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/security/UserSettings.java new file mode 100644 index 0000000000..a5f95ae9f3 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/UserSettings.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.security; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; + +import java.io.Serializable; + +@ApiModel +@Data +@EqualsAndHashCode +public class UserSettings implements Serializable { + + private static final long serialVersionUID = 2628320657987010348L; + + @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") + @NoXss + @Length(fieldName = "settings", max = 10000) + private transient JsonNode settings; + +} 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 1bd173d42b..90d4abd292 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 @@ -86,6 +86,13 @@ public class ModelConstants { public static final String USER_CREDENTIALS_BY_ACTIVATE_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_activate_token"; public static final String USER_CREDENTIALS_BY_RESET_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_reset_token"; + /** + * User settings constants. + */ + 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_SETTINGS = "settings"; + /** * Cassandra admin_settings constants. */ 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 new file mode 100644 index 0000000000..59a0aeb081 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserSettingsEntity.java @@ -0,0 +1,78 @@ +/** + * 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.dao.model.sql; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.id.UserAuthSettingsId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.security.UserAuthSettings; +import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoFaSettings; +import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; +import org.thingsboard.server.dao.model.BaseEntity; +import org.thingsboard.server.dao.model.BaseSqlEntity; +import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.model.ToData; +import org.thingsboard.server.dao.util.mapping.JsonStringType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + +@EqualsAndHashCode +@Data +@NoArgsConstructor +@TypeDef(name = "json", typeClass = JsonStringType.class) +@Entity +@Table(name = ModelConstants.USER_SETTINGS_COLUMN_FAMILY_NAME) +public class UserSettingsEntity implements ToData { + + @Id + @Column(name = ModelConstants.USER_SETTINGS_USER_ID_PROPERTY) + private UUID userId; + @Type(type = "json") + @Column(name = ModelConstants.USER_SETTINGS_SETTINGS) + private JsonNode settings; + + + public UserSettingsEntity(UserSettings userSettings) { + this.userId = userSettings.getUserId().getId(); + if (userSettings.getSettings() != null) { + this.settings= userSettings.getSettings(); + } + } + + @Override + public UserSettings toData() { + UserSettings userSettings = new UserSettings(); + userSettings.setUserId(new UserId(userId)); + if (settings != null) { + userSettings.setSettings(settings); + } + return userSettings; + } + +} 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 new file mode 100644 index 0000000000..9296cae178 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDao.java @@ -0,0 +1,65 @@ +/** + * 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.dao.sql.user; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.JpaRepository; +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.UserCredentials; +import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; +import org.thingsboard.server.dao.model.sql.RelationEntity; +import org.thingsboard.server.dao.model.sql.UserCredentialsEntity; +import org.thingsboard.server.dao.model.sql.UserSettingsEntity; +import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; +import org.thingsboard.server.dao.user.UserCredentialsDao; +import org.thingsboard.server.dao.user.UserSettingsDao; +import org.thingsboard.server.dao.util.SqlDao; + +import java.util.UUID; + +/** + * Created by Valerii Sosliuk on 4/22/2017. + */ +@Slf4j +@Component +@SqlDao +public class JpaUserSettingsDao extends JpaAbstractDaoListeningExecutorService implements UserSettingsDao { + + @Autowired + private UserSettingsRepository userSettingsRepository; + + @Override + public UserSettings saveSettings(TenantId tenantId, UserSettings userSettings) { + return DaoUtil.getData(userSettingsRepository.save(new UserSettingsEntity(userSettings))); + } + + @Override + public UserSettings findByUserId(TenantId tenantId, UserId userId) { + return DaoUtil.getData(userSettingsRepository.findById(userId.getId())); + } + + @Override + public void removeByUserId(TenantId tenantId, UserId userId) { + userSettingsRepository.deleteById(userId.getId()); + } + +} 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 new file mode 100644 index 0000000000..b4df8e72a6 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserSettingsRepository.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.dao.sql.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.dao.model.sql.UserCredentialsEntity; +import org.thingsboard.server.dao.model.sql.UserSettingsEntity; + +import java.util.UUID; + +/** + * Created by Valerii Sosliuk on 4/22/2017. + */ +public interface UserSettingsRepository extends JpaRepository { + + UserSettingsEntity save(UserSettings saveSettings); + + UserSettingsEntity findByUserId(UUID userId); + + UserSettingsEntity deleteByUserId(UUID userId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index c97d01e2d4..9721934d26 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.UserCredentials; +import org.thingsboard.server.common.data.security.UserSettings; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -72,6 +73,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private final UserDao userDao; private final UserCredentialsDao userCredentialsDao; private final UserAuthSettingsDao userAuthSettingsDao; + private final UserSettingsDao userSettingsDao; private final DataValidator userValidator; private final DataValidator userCredentialsValidator; private final ApplicationEventPublisher eventPublisher; @@ -322,6 +324,27 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic return failedLoginAttempts; } + @Override + public UserSettings saveUserSettings(TenantId tenantId, UserId userId, UserSettings userSettings) { + log.trace("Executing saveUserSettings [{}], [{}]", userId, userSettings); + validateId(userId, INCORRECT_USER_ID + userId); + return userSettingsDao.saveSettings(tenantId, userSettings); + } + + @Override + public UserSettings findUserSettings(TenantId tenantId, UserId userId) { + log.trace("Executing findUserSettings [{}]", userId); + validateId(userId, INCORRECT_USER_ID + userId); + return userSettingsDao.findByUserId(tenantId, userId); + } + + @Override + public void deleteUserSettings(TenantId tenantId, UserId userId) { + log.trace("Executing deleteUserSettings for user [{}]", userId); + validateId(userId, INCORRECT_USER_ID + userId); + userSettingsDao.removeByUserId(tenantId, userId); + } + private int increaseFailedLoginAttempts(User user) { JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { 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 new file mode 100644 index 0000000000..5e162a8ad7 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserSettingsDao.java @@ -0,0 +1,32 @@ +/** + * 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.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.UserAuthSettings; +import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.dao.Dao; + +public interface UserSettingsDao { + + UserSettings saveSettings(TenantId tenantId, UserSettings userSettings); + + UserSettings findByUserId(TenantId tenantId, UserId userId); + + void removeByUserId(TenantId tenantId, UserId userId); + +} diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index c21d1bff38..b6ccbc4c2e 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -776,3 +776,9 @@ CREATE TABLE IF NOT EXISTS user_auth_settings ( user_id uuid UNIQUE NOT NULL CONSTRAINT fk_user_auth_settings_user_id REFERENCES tb_user(id), two_fa_settings varchar ); + +CREATE TABLE IF NOT EXISTS user_settings ( + user_id uuid NOT NULL CONSTRAINT user_settings_pkey PRIMARY KEY, + settings varchar(10000), + CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE +); \ No newline at end of file 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 6ad50508d7..25992d914a 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 @@ -19,16 +19,20 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; +import org.thingsboard.server.common.data.security.UserSettings; import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; @@ -40,6 +44,7 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; + private UserSettings userSettings; @Before public void before() { @@ -65,7 +70,10 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { customerUser.setTenantId(tenantId); customerUser.setCustomerId(savedCustomer.getId()); customerUser.setEmail("customer@thingsboard.org"); - userService.saveUser(customerUser); + customerUser = userService.saveUser(customerUser); + + userSettings = createUserSettings(); + userSettings = userService.saveUserSettings(TenantId.SYS_TENANT_ID, customerUser.getId(), userSettings); } @After @@ -105,6 +113,14 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { Assert.assertNotNull(userCredentials); } + @Test + public void testFindUserSettings() { + User user = userService.findUserByEmail(SYSTEM_TENANT_ID,"customer@thingsboard.org"); + Assert.assertNotNull(user); + UserSettings userSettings = userService.findUserSettings(SYSTEM_TENANT_ID, user.getId()); + Assert.assertEquals(userSettings.getSettings(), userSettings.getSettings()); + } + @Test public void testSaveUser() { User tenantAdminUser = userService.findUserByEmail(SYSTEM_TENANT_ID,"tenant@thingsboard.org"); @@ -474,4 +490,10 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { tenantService.deleteTenant(tenantId); } + private UserSettings createUserSettings() { + UserSettings userSettings = new UserSettings(); + userSettings.setSettings(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); + return userSettings; + } + } 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 new file mode 100644 index 0000000000..8dd703dc84 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserSettingsDaoTest.java @@ -0,0 +1,105 @@ +/** + * 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.dao.sql.user; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.service.AbstractServiceTest; +import org.thingsboard.server.dao.user.UserDao; +import org.thingsboard.server.dao.user.UserSettingsDao; + +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +import static org.thingsboard.server.dao.service.AbstractServiceTest.SYSTEM_TENANT_ID; + +/** + * Created by Valerii Sosliuk on 4/22/2017. + */ +public class JpaUserSettingsDaoTest extends AbstractJpaDaoTest { + + private UUID tenantId; + private User user; + + @Autowired + private UserSettingsDao userSettingsDao; + + @Autowired + private UserDao userDao; + + @Before + public void setUp() { + tenantId = Uuids.timeBased(); + user = saveUser(tenantId, Uuids.timeBased()); + } + + @After + public void tearDown() { + userDao.removeById(user.getTenantId(), user.getUuidId()); + } + + @Test + public void testFindSettingsByTenantAdminUserId() { + UserSettings userSettings = createUserSettings(user.getId()); + + UserSettings retrievedUserSettings = userSettingsDao.findByUserId(SYSTEM_TENANT_ID, user.getId()); + assertEquals(retrievedUserSettings.getSettings(), userSettings.getSettings()); + + userSettingsDao.removeByUserId(SYSTEM_TENANT_ID, user.getId()); + + UserSettings retrievedUserSettings2 = userSettingsDao.findByUserId(SYSTEM_TENANT_ID, user.getId()); + assertNull(retrievedUserSettings2); + } + + private UserSettings createUserSettings(UserId userId) { + UserSettings userSettings = new UserSettings(); + userSettings.setSettings(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); + userSettings.setUserId(userId); + return userSettingsDao.saveSettings(SYSTEM_TENANT_ID, userSettings); + } + + private User saveUser(UUID tenantId, UUID customerId) { + User user = new User(); + UUID id = Uuids.timeBased(); + user.setId(new UserId(id)); + user.setTenantId(TenantId.fromUUID(tenantId)); + user.setCustomerId(new CustomerId(customerId)); + if (customerId == NULL_UUID) { + user.setAuthority(Authority.TENANT_ADMIN); + } else { + user.setAuthority(Authority.CUSTOMER_USER); + } + String idString = id.toString(); + String email = idString.substring(0, idString.indexOf('-')) + "@thingsboard.org"; + user.setEmail(email); + return userDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, user); + } +}