Browse Source

Merge pull request #11134 from thingsboard/fix/dashboard-deletion-error

Proper error message when deleting dashboard referenced by asset profile
pull/11152/head
Viacheslav Klimov 2 years ago
committed by GitHub
parent
commit
4249ad8934
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 25
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  2. 31
      application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java
  3. 15
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

25
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -22,6 +22,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -358,29 +359,33 @@ public abstract class BaseController {
private ThingsboardException handleException(Exception exception, boolean logException) { private ThingsboardException handleException(Exception exception, boolean logException) {
if (logException && logControllerErrorStackTrace) { if (logException && logControllerErrorStackTrace) {
log.error("Error [{}]", exception.getMessage(), exception); try {
} SecurityUser user = getCurrentUser();
log.error("[{}][{}] Error", user.getTenantId(), user.getId(), exception);
String cause = ""; } catch (Exception e) {
if (exception.getCause() != null) { log.error("Error", exception);
cause = exception.getCause().getClass().getCanonicalName(); }
} }
Throwable cause = exception.getCause();
if (exception instanceof ThingsboardException) { if (exception instanceof ThingsboardException) {
return (ThingsboardException) exception; return (ThingsboardException) exception;
} else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException } else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException
|| exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { || exception instanceof DataValidationException || cause instanceof IncorrectParameterException) {
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (exception instanceof MessagingException) { } else if (exception instanceof MessagingException) {
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL);
} else if (exception instanceof AsyncRequestTimeoutException) { } else if (exception instanceof AsyncRequestTimeoutException) {
return new ThingsboardException("Request timeout", ThingsboardErrorCode.GENERAL); return new ThingsboardException("Request timeout", ThingsboardErrorCode.GENERAL);
} else if (exception instanceof DataAccessException) { } else if (exception instanceof DataAccessException) {
String errorType = exception.getClass().getSimpleName();
if (!logControllerErrorStackTrace) { // not to log the error twice if (!logControllerErrorStackTrace) { // not to log the error twice
log.warn("Database error: {} - {}", errorType, ExceptionUtils.getRootCauseMessage(exception)); log.warn("Database error: {} - {}", exception.getClass().getSimpleName(), ExceptionUtils.getRootCauseMessage(exception));
}
if (cause instanceof ConstraintViolationException) {
return new ThingsboardException(ExceptionUtils.getRootCause(exception).getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else {
return new ThingsboardException("Database error", ThingsboardErrorCode.GENERAL);
} }
return new ThingsboardException("Database error", ThingsboardErrorCode.GENERAL);
} }
return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL); return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL);
} }

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

@ -27,13 +27,16 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
@ -48,6 +51,7 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -547,6 +551,33 @@ public class DashboardControllerTest extends AbstractControllerTest {
testEntityDaoWithRelationsTransactionalException(dashboardDao, savedTenant.getId(), dashboardId, "/api/dashboard/" + dashboardId); testEntityDaoWithRelationsTransactionalException(dashboardDao, savedTenant.getId(), dashboardId, "/api/dashboard/" + dashboardId);
} }
@Test
public void whenDeletingDashboard_ifReferencedByDeviceProfile_thenReturnError() throws Exception {
Dashboard dashboard = createDashboard("test");
DeviceProfile deviceProfile = createDeviceProfile("test");
deviceProfile.setDefaultDashboardId(dashboard.getId());
doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
String response = doDelete("/api/dashboard/" + dashboard.getUuidId()).andExpect(status().isBadRequest())
.andReturn().getResponse().getContentAsString();
String errorMessage = JacksonUtil.toJsonNode(response).get("message").asText();
assertThat(errorMessage).containsIgnoringCase("referenced by a device profile");
}
@Test
public void whenDeletingDashboard_ifReferencedByAssetProfile_thenReturnError() throws Exception {
Dashboard dashboard = createDashboard("test");
AssetProfile assetProfile = createAssetProfile("test");
assetProfile.setDefaultDashboardId(dashboard.getId());
doPost("/api/assetProfile", assetProfile, AssetProfile.class);
String response = doDelete("/api/dashboard/" + dashboard.getUuidId()).andExpect(status().isBadRequest())
.andReturn().getResponse().getContentAsString();
String errorMessage = JacksonUtil.toJsonNode(response).get("message").asText();
assertThat(errorMessage).containsIgnoringCase("referenced by an asset profile");
}
private Dashboard createDashboard(String title) { private Dashboard createDashboard(String title) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle(title); dashboard.setTitle(title);

15
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -18,7 +18,6 @@ package org.thingsboard.server.dao.dashboard;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -57,6 +56,7 @@ import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.sql.JpaExecutorService; import org.thingsboard.server.dao.sql.JpaExecutorService;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
@ -235,13 +235,12 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
publishEvictEvent(new DashboardTitleEvictEvent(dashboardId)); publishEvictEvent(new DashboardTitleEvictEvent(dashboardId));
countService.publishCountEntityEvictEvent(tenantId, EntityType.DASHBOARD); countService.publishCountEntityEvictEvent(tenantId, EntityType.DASHBOARD);
eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(dashboardId).build()); eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(dashboardId).build());
} catch (Exception t) { } catch (Exception e) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); checkConstraintViolation(e, Map.of(
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_dashboard_device_profile")) { "fk_default_dashboard_device_profile", "The dashboard is referenced by a device profile",
throw new DataValidationException("The dashboard referenced by the device profiles cannot be deleted!"); "fk_default_dashboard_asset_profile", "The dashboard is referenced by an asset profile"
} else { ));
throw t; throw e;
}
} }
} }

Loading…
Cancel
Save