From 4114c96571dbb35c1655cd77faa4bb4872c237c8 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 12 Sep 2023 12:32:35 +0300 Subject: [PATCH] Version control: fix ids replacement in dashboard config --- .../impl/BaseEntityExportService.java | 4 +- .../impl/DashboardExportService.java | 5 +- .../impl/BaseEntityImportService.java | 6 +-- .../impl/DashboardImportService.java | 4 +- .../sync/ie/ExportImportServiceSqlTest.java | 53 ++++++++++++++++--- .../thingsboard/common/util/JacksonUtil.java | 21 ++++---- 6 files changed, 66 insertions(+), 27 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java index abc90221be..3cf05ac503 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java @@ -48,8 +48,8 @@ public abstract class BaseEntityExportService getSupportedEntityTypes(); - protected void replaceUuidsRecursively(EntitiesExportCtx ctx, JsonNode node, Set skipFieldsSet, Pattern includedFieldsPattern) { - JacksonUtil.replaceUuidsRecursively(node, skipFieldsSet, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid)); + protected void replaceUuidsRecursively(EntitiesExportCtx ctx, JsonNode node, Set skippedRootFields, Pattern includedFieldsPattern) { + JacksonUtil.replaceUuidsRecursively(node, skippedRootFields, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid), true); } protected Stream toExternalIds(Collection internalIds, Function entityIdCreator, diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java index 0df1e83c7f..d1278bc585 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java @@ -26,8 +26,11 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; +import java.util.Collections; import java.util.Set; +import static org.thingsboard.server.service.sync.ie.importing.impl.DashboardImportService.WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN; + @Service @TbCoreComponent public class DashboardExportService extends BaseEntityExportService> { @@ -43,7 +46,7 @@ public class DashboardExportService extends BaseEntityExportService skipFieldsSet, Pattern includedFieldsPattern, + Set skippedRootFields, Pattern includedFieldsPattern, LinkedHashSet hints) { - JacksonUtil.replaceUuidsRecursively(json, skipFieldsSet, includedFieldsPattern, + JacksonUtil.replaceUuidsRecursively(json, skippedRootFields, includedFieldsPattern, uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints) - .map(EntityId::getId).orElse(uuid)); + .map(EntityId::getId).orElse(uuid), true); } } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java index eac229f774..658ecf744a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; @Service @@ -44,6 +45,7 @@ import java.util.stream.Collectors; public class DashboardImportService extends BaseEntityImportService> { private static final LinkedHashSet HINTS = new LinkedHashSet<>(Arrays.asList(EntityType.DASHBOARD, EntityType.DEVICE, EntityType.ASSET)); + public static final Pattern WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN = Pattern.compile(".*Id.*"); private final DashboardService dashboardService; @@ -68,7 +70,7 @@ public class DashboardImportService extends BaseEntityImportService asset1ExportData = exportEntity(tenantAdmin1, asset1.getId()); EntityExportData asset2ExportData = exportEntity(tenantAdmin1, asset2.getId()); EntityExportData dashboardExportData = exportEntity(tenantAdmin1, dashboard.getId()); + EntityExportData otherDashboardExportData = exportEntity(tenantAdmin1, otherDashboard.getId()); AssetProfile importedProfile = importEntity(tenantAdmin2, profileExportData).getSavedEntity(); Asset importedAsset1 = importEntity(tenantAdmin2, asset1ExportData).getSavedEntity(); Asset importedAsset2 = importEntity(tenantAdmin2, asset2ExportData).getSavedEntity(); + Dashboard importedOtherDashboard = importEntity(tenantAdmin2, otherDashboardExportData).getSavedEntity(); Dashboard importedDashboard = importEntity(tenantAdmin2, dashboardExportData).getSavedEntity(); Map.Entry entityAlias = importedDashboard.getConfiguration().get("entityAliases").fields().next(); @@ -311,6 +337,17 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest { .isEqualTo(existingDeviceProfile.getId().toString()); assertThat(aliasEntitiesIds).element(4).as("unresolved uuid was replaced with tenant id") .isEqualTo(tenantId2.toString()); + assertThat(entityAlias.getValue().get("filter").get("id").asText()).as("external asset 1 was replaced with imported one") + .isEqualTo(importedAsset1.getId().toString()); + + ObjectNode widgetConfig = importedDashboard.getWidgetsConfig().get(0); + assertThat(widgetConfig.get("id").asText()).as("widget id is not replaced") + .isEqualTo(widgetId); + JsonNode actionConfig = widgetConfig.get("config").get("actions").get("rowClick").get(0); + assertThat(actionConfig.get("id").asText()).as("action id is not replaced") + .isEqualTo(actionId); + assertThat(actionConfig.get("targetDashboardId").asText()).as("dashboard id is replaced with imported one") + .isEqualTo(importedOtherDashboard.getId().toString()); } diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 9f980f36c8..7c8d174af2 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.common.collect.Lists; import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.KvEntry; @@ -35,7 +36,6 @@ import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.Writer; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -228,27 +228,24 @@ public class JacksonUtil { return node; } - public static void replaceUuidsRecursively(JsonNode node, Set skipFieldsSet, Pattern includedFieldsPattern, UnaryOperator replacer) { + public static void replaceUuidsRecursively(JsonNode node, Set skippedRootFields, Pattern includedFieldsPattern, UnaryOperator replacer, boolean root) { if (node == null) { return; } if (node.isObject()) { ObjectNode objectNode = (ObjectNode) node; - List fieldNames = new ArrayList<>(objectNode.size()); - objectNode.fieldNames().forEachRemaining(fieldNames::add); + List fieldNames = Lists.newArrayList(objectNode.fieldNames()); for (String fieldName : fieldNames) { - if (skipFieldsSet.contains(fieldName)) { + if (root && skippedRootFields.contains(fieldName)) { continue; } - if (includedFieldsPattern != null) { - if (!RegexUtils.matches(fieldName, includedFieldsPattern)) { - continue; - } - } var child = objectNode.get(fieldName); if (child.isObject() || child.isArray()) { - replaceUuidsRecursively(child, skipFieldsSet, includedFieldsPattern, replacer); + replaceUuidsRecursively(child, skippedRootFields, includedFieldsPattern, replacer, false); } else if (child.isTextual()) { + if (includedFieldsPattern != null && !RegexUtils.matches(fieldName, includedFieldsPattern)) { + continue; + } String text = child.asText(); String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString()); if (!text.equals(newText)) { @@ -261,7 +258,7 @@ public class JacksonUtil { for (int i = 0; i < array.size(); i++) { JsonNode arrayElement = array.get(i); if (arrayElement.isObject() || arrayElement.isArray()) { - replaceUuidsRecursively(arrayElement, skipFieldsSet, includedFieldsPattern, replacer); + replaceUuidsRecursively(arrayElement, skippedRootFields, includedFieldsPattern, replacer, false); } else if (arrayElement.isTextual()) { String text = arrayElement.asText(); String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString());