diff --git a/application/src/main/java/org/thingsboard/server/service/sync/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/DefaultEntitiesExportImportService.java index f399dbdbea..eeaef01f63 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/DefaultEntitiesExportImportService.java @@ -20,9 +20,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.ExportableEntityDao; +import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.exporting.EntityExportService; import org.thingsboard.server.service.sync.exporting.EntityExportSettings; @@ -37,7 +40,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; @Service @@ -46,7 +48,7 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS private final Map> exportServices = new HashMap<>(); private final Map> importServices = new HashMap<>(); - private final Map> daos = new HashMap<>(); + private final Map> daos = new HashMap<>(); protected static final List SUPPORTED_ENTITY_TYPES = List.of( EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN, @@ -85,16 +87,22 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS @Override - public , I extends EntityId> E findEntityById(TenantId tenantId, I id) { - ExportableEntityDao dao = getDao(id.getEntityType()); + public & HasTenantId, I extends EntityId> E findEntityById(TenantId tenantId, I id) { + TenantEntityDao dao = (TenantEntityDao) getDao(id.getEntityType()); return dao.findByTenantIdAndId(tenantId.getId(), id.getId()); } @Override public , I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId) { - ExportableEntityDao dao = getDao(externalId.getEntityType()); - return Optional.ofNullable(dao.findByTenantIdAndExternalId(tenantId.getId(), externalId.getId())) - .orElseGet(() -> findEntityById(tenantId, externalId)); + EntityType entityType = externalId.getEntityType(); + if (SUPPORTED_ENTITY_TYPES.contains(entityType)) { + ExportableEntityDao dao = (ExportableEntityDao) getDao(entityType); + E entity = dao.findByTenantIdAndExternalId(tenantId.getId(), externalId.getId()); + if (entity != null) { + return entity; + } + } + return findEntityById(tenantId, externalId); } @@ -114,15 +122,14 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS return (EntityImportService) importServices.get(entityType); } - @SuppressWarnings("unchecked") - private ExportableEntityDao getDao(EntityType entityType) { - return (ExportableEntityDao) daos.get(entityType); + private TenantEntityDao getDao(EntityType entityType) { + return daos.get(entityType); } @Autowired private void setServices(Collection> exportServices, Collection> importServices, - Collection> daos) { + Collection> daos) { exportServices.forEach(entityExportService -> { this.exportServices.put(entityExportService.getEntityType(), entityExportService); }); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/exporting/ExportableEntitiesService.java b/application/src/main/java/org/thingsboard/server/service/sync/exporting/ExportableEntitiesService.java index 2135d2aca1..1c1cf6bf7f 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/exporting/ExportableEntitiesService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/exporting/ExportableEntitiesService.java @@ -16,12 +16,12 @@ package org.thingsboard.server.service.sync.exporting; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; -public interface ExportableEntitiesService { - - , I extends EntityId> E findEntityById(TenantId tenantId, I id); +public interface ExportableEntitiesService extends TenantEntitiesService { , I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/exporting/TenantEntitiesService.java b/application/src/main/java/org/thingsboard/server/service/sync/exporting/TenantEntitiesService.java new file mode 100644 index 0000000000..e3e25c21e8 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/exporting/TenantEntitiesService.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2022 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.sync.exporting; + +import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; +import org.thingsboard.server.common.data.id.TenantId; + +public interface TenantEntitiesService { + + & HasTenantId, I extends EntityId> E findEntityById(TenantId tenantId, I id); + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DashboardImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DashboardImportService.java index 9e7cffd272..5525ba8e6b 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DashboardImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DashboardImportService.java @@ -27,7 +27,9 @@ import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.exporting.data.DashboardExportData; +import java.util.Collections; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -49,8 +51,8 @@ public class DashboardImportService extends BaseEntityImportService existingAssignedCustomers = dashboardService.findDashboardById(tenantId, dashboard.getId()).getAssignedCustomers().stream() - .map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet()); + Set existingAssignedCustomers = Optional.ofNullable(dashboardService.findDashboardById(tenantId, dashboard.getId()).getAssignedCustomers()) + .orElse(Collections.emptySet()).stream().map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet()); Set newAssignedCustomers = idProvider.get(tenantId, Dashboard::getAssignedCustomers, ShortCustomerInfo::getCustomerId, ShortCustomerInfo::setCustomerId).stream() .map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet()); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceImportService.java index eafe9c0fdb..2dcf4f7e7f 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceImportService.java @@ -38,7 +38,13 @@ public class DeviceImportService extends BaseEntityImportService { - assertThat(importedAsset.getName()).isEqualTo(asset.getName()); - assertThat(importedAsset.getType()).isEqualTo(asset.getType()); - assertThat(importedAsset.getLabel()).isEqualTo(asset.getLabel()); - assertThat(importedAsset.getAdditionalInfo()).isEqualTo(asset.getAdditionalInfo()); - }); - - Customer customer = createCustomer(tenantId1, "Customer of tenant 1"); - testExportImportBetweenTenants(customer, importedCustomer -> { - assertThat(importedCustomer.getTitle()).isEqualTo(customer.getTitle()); - assertThat(importedCustomer.getCountry()).isEqualTo(customer.getCountry()); - assertThat(importedCustomer.getAddress()).isEqualTo(customer.getAddress()); - assertThat(importedCustomer.getEmail()).isEqualTo(customer.getEmail()); - }); - - DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile of tenant 1"); - DeviceProfileId importedDeviceProfileId = testExportImportBetweenTenants(deviceProfile, importedDeviceProfile -> { - assertThat(importedDeviceProfile.getName()).isEqualTo(deviceProfile.getName()); - assertThat(importedDeviceProfile.getType()).isEqualTo(deviceProfile.getType()); - assertThat(importedDeviceProfile.getTransportType()).isEqualTo(deviceProfile.getTransportType()); - assertThat(importedDeviceProfile.getProfileData()).isEqualTo(deviceProfile.getProfileData()); - assertThat(importedDeviceProfile.getDescription()).isEqualTo(deviceProfile.getDescription()); - }).getSavedEntity().getId(); - - Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device of tenant 1"); - DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId()); - this.testExportImportBetweenTenants(device, deviceExportData -> { - assertThat(deviceExportData.getCredentials()).isEqualTo(credentials); - }, importedDevice -> { - assertThat(importedDevice.getName()).isEqualTo(device.getName()); - assertThat(importedDevice.getType()).isEqualTo(device.getType()); - assertThat(importedDevice.getDeviceData()).isEqualTo(device.getDeviceData()); - assertThat(importedDevice.getDeviceProfileId()).isEqualTo(importedDeviceProfileId); - assertThat(importedDevice.getLabel()).isEqualTo(device.getLabel()); - - DeviceCredentials importedCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId2, importedDevice.getId()); - assertThat(importedCredentials.getCredentialsId()).isEqualTo(credentials.getCredentialsId()); - assertThat(importedCredentials.getCredentialsValue()).isEqualTo(credentials.getCredentialsValue()); - assertThat(importedCredentials.getCredentialsType()).isEqualTo(credentials.getCredentialsType()); - }); - - RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1"); - RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId()); - this.testExportImportBetweenTenants(ruleChain, ruleChainExportData -> { - assertThat(ruleChainExportData.getMetaData()).isEqualTo(metaData); - }, importedRuleChain -> { - assertThat(importedRuleChain.getType()).isEqualTo(ruleChain.getType()); - assertThat(importedRuleChain.getName()).isEqualTo(ruleChain.getName()); - assertThat(importedRuleChain.isDebugMode()).isEqualTo(ruleChain.isDebugMode()); - assertThat(importedRuleChain.getConfiguration()).isEqualTo(ruleChain.getConfiguration()); - RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId()); - assertThat(importedMetaData.getConnections()).isEqualTo(metaData.getConnections()); - assertThat(importedMetaData.getFirstNodeIndex()).isEqualTo(metaData.getFirstNodeIndex()); - for (int i = 0; i < metaData.getNodes().size(); i++) { - RuleNode initialNode = metaData.getNodes().get(i); - RuleNode importedNode = importedMetaData.getNodes().get(i); - assertThat(importedNode.getName()).isEqualTo(initialNode.getName()); - assertThat(importedNode.getType()).isEqualTo(initialNode.getType()); - assertThat(importedNode.getConfiguration()).isEqualTo(initialNode.getConfiguration()); - assertThat(importedNode.getAdditionalInfo()).isEqualTo(initialNode.getAdditionalInfo()); - } - }); - - Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard of tenant 1"); - testExportImportBetweenTenants(dashboard, importedDashboard -> { - assertThat(importedDashboard.getTitle()).isEqualTo(dashboard.getTitle()); - assertThat(importedDashboard.getConfiguration()).isEqualTo(dashboard.getConfiguration()); - assertThat(importedDashboard.getImage()).isEqualTo(dashboard.getImage()); - assertThat(importedDashboard.isMobileHide()).isEqualTo(dashboard.isMobileHide()); - }); - } - - private , D extends EntityExportData> EntityImportResult testExportImportBetweenTenants(E entity, Consumer exportDataRequirements, Consumer importedEntityRequirements) throws Exception { + public void testExportImportSingleAsset_betweenTenants() throws Exception { logInAsTenantAdmin1(); - D exportData = readResponse(doPost("/api/entities/export/" + entity.getId().getEntityType() + "/" + entity.getId()) - .andExpect(status().isOk()), new TypeReference() {}); - assertThat(exportData.getEntity()).isEqualTo(entity); - exportDataRequirements.accept(exportData); + Asset asset = createAsset(tenantId1, null, "AB", "Asset of tenant 1"); + EntityExportData exportData = exportSingleEntity(asset.getId()); + assertThat(exportData.getEntity()).isEqualTo(asset); logInAsTenantAdmin2(); - EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); - E importedEntity = (E) exportableEntitiesService.findEntityById(tenantId2, importResult.getSavedEntity().getId()); - assertThat(importedEntity).isNotNull(); - assertThat(importResult.getSavedEntity()).isEqualTo(importedEntity); - assertThat(importResult.getOldEntity()).isNull(); - - assertThat(importedEntity.getId()).isNotEqualTo(entity.getId()); - assertThat(importedEntity.getExternalId()).isEqualTo(entity.getId()); - assertThat(importedEntity.getTenantId()).isEqualTo(tenantId2); - importedEntityRequirements.accept(importedEntity); - return importResult; + checkImportedEntity(tenantId1, asset, tenantId2, importResult); + checkImportedAssetData(asset, importResult.getSavedEntity()); } - private > EntityImportResult testExportImportBetweenTenants(E entity, Consumer importedEntityRequirements) throws Exception { - return testExportImportBetweenTenants(entity, exportData -> {}, importedEntityRequirements); + @Test + public void testExportImportSingleAsset_sameTenant() throws Exception { + logInAsTenantAdmin1(); + Asset asset = createAsset(tenantId1, null, "AB", "Asset v1.0"); + EntityExportData exportData = exportSingleEntity(asset.getId()); + + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + + checkImportedEntity(tenantId1, asset, tenantId1, importResult); + checkImportedAssetData(asset, importResult.getSavedEntity()); + } + + @Test + public void testExportImportAsset_withCustomer_betweenTenants() throws Exception { + logInAsTenantAdmin1(); + Customer customer = createCustomer(tenantId1, "My customer"); + Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset"); + + EntityExportData customerExportData = exportSingleEntity(customer.getId()); + EntityExportData assetExportData = exportSingleEntity(asset.getId()); + + logInAsTenantAdmin2(); + Customer importedCustomer = importEntities(List.of(customerExportData)).get(0).getSavedEntity(); + Asset importedAsset = importEntities(List.of(assetExportData)).get(0).getSavedEntity(); + + assertThat(importedAsset.getCustomerId()).isEqualTo(importedCustomer.getId()); + } + + @Test + public void testExportImportAsset_withCustomer_sameTenant() throws Exception { + logInAsTenantAdmin1(); + Customer customer = createCustomer(tenantId1, "My customer"); + Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset"); + + Asset importedAsset = this.importEntities(List.of(exportSingleEntity(asset.getId()))).get(0).getSavedEntity(); + + assertThat(importedAsset.getCustomerId()).isEqualTo(asset.getCustomerId()); + } + + private void checkImportedAssetData(Asset initialAsset, Asset importedAsset) { + assertThat(importedAsset.getName()).isEqualTo(initialAsset.getName()); + assertThat(importedAsset.getType()).isEqualTo(initialAsset.getType()); + assertThat(importedAsset.getLabel()).isEqualTo(initialAsset.getLabel()); + assertThat(importedAsset.getAdditionalInfo()).isEqualTo(initialAsset.getAdditionalInfo()); + } + + + @Test + public void testExportImportSingleCustomer_betweenTenants() throws Exception { + logInAsTenantAdmin1(); + Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer of tenant 1"); + EntityExportData exportData = exportSingleEntity(customer.getId()); + assertThat(exportData.getEntity()).isEqualTo(customer); + + logInAsTenantAdmin2(); + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + + checkImportedEntity(tenantId1, customer, tenantId2, importResult); + checkImportedCustomerData(customer, importResult.getSavedEntity()); + } + + @Test + public void testExportImportSingleCustomer_sameTenant() throws Exception { + logInAsTenantAdmin1(); + Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer v1.0"); + EntityExportData exportData = exportSingleEntity(customer.getId()); + + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + + checkImportedEntity(tenantId1, customer, tenantId1, importResult); + checkImportedCustomerData(customer, importResult.getSavedEntity()); + } + + private void checkImportedCustomerData(Customer initialCustomer, Customer importedCustomer) { + assertThat(importedCustomer.getTitle()).isEqualTo(initialCustomer.getTitle()); + assertThat(importedCustomer.getCountry()).isEqualTo(initialCustomer.getCountry()); + assertThat(importedCustomer.getAddress()).isEqualTo(initialCustomer.getAddress()); + assertThat(importedCustomer.getEmail()).isEqualTo(initialCustomer.getEmail()); + } + + + @Test + public void testExportImportDeviceWithProfile_betweenTenants() throws Exception { + logInAsTenantAdmin1(); + DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile of tenant 1"); + Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device of tenant 1"); + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId()); + + EntityExportData profileExportData = exportSingleEntity(deviceProfile.getId()); + assertThat(profileExportData.getEntity()).isEqualTo(deviceProfile); + + EntityExportData deviceExportData = exportSingleEntity(device.getId()); + assertThat(deviceExportData.getEntity()).isEqualTo(device); + assertThat(((DeviceExportData) deviceExportData).getCredentials()).isEqualTo(credentials); + DeviceCredentials exportedCredentials = ((DeviceExportData) deviceExportData).getCredentials(); + exportedCredentials.setCredentialsId(credentials.getCredentialsId() + "a"); + + logInAsTenantAdmin2(); + EntityImportResult profileImportResult = importEntities(List.of(profileExportData)).get(0); + checkImportedEntity(tenantId1, deviceProfile, tenantId2, profileImportResult); + checkImportedDeviceProfileData(deviceProfile, profileImportResult.getSavedEntity()); + + + EntityImportResult deviceImportResult = importEntities(List.of(deviceExportData)).get(0); + Device importedDevice = deviceImportResult.getSavedEntity(); + checkImportedEntity(tenantId1, device, tenantId2, deviceImportResult); + checkImportedDeviceData(device, importedDevice); + + assertThat(importedDevice.getDeviceProfileId()).isEqualTo(profileImportResult.getSavedEntity().getId()); + + DeviceCredentials importedCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId2, importedDevice.getId()); + assertThat(importedCredentials.getId()).isNotEqualTo(credentials.getId()); + assertThat(importedCredentials.getCredentialsId()).isEqualTo(exportedCredentials.getCredentialsId()); + assertThat(importedCredentials.getCredentialsValue()).isEqualTo(credentials.getCredentialsValue()); + assertThat(importedCredentials.getCredentialsType()).isEqualTo(credentials.getCredentialsType()); + } + + @Test + public void testExportImportDevice_sameTenant() throws Exception { + logInAsTenantAdmin1(); + DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile v1.0"); + Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device v1.0"); + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId()); + + EntityExportData deviceExportData = exportSingleEntity(device.getId()); + + EntityImportResult importResult = importEntities(List.of(deviceExportData)).get(0); + Device importedDevice = importResult.getSavedEntity(); + + checkImportedEntity(tenantId1, device, tenantId1, importResult); + assertThat(importedDevice.getDeviceProfileId()).isEqualTo(device.getDeviceProfileId()); + assertThat(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId())).isEqualTo(credentials); + } + + private void checkImportedDeviceProfileData(DeviceProfile initialProfile, DeviceProfile importedProfile) { + assertThat(initialProfile.getName()).isEqualTo(importedProfile.getName()); + assertThat(initialProfile.getType()).isEqualTo(importedProfile.getType()); + assertThat(initialProfile.getTransportType()).isEqualTo(importedProfile.getTransportType()); + assertThat(initialProfile.getProfileData()).isEqualTo(importedProfile.getProfileData()); + assertThat(initialProfile.getDescription()).isEqualTo(importedProfile.getDescription()); + } + + private void checkImportedDeviceData(Device initialDevice, Device importedDevice) { + assertThat(importedDevice.getName()).isEqualTo(initialDevice.getName()); + assertThat(importedDevice.getType()).isEqualTo(initialDevice.getType()); + assertThat(importedDevice.getDeviceData()).isEqualTo(initialDevice.getDeviceData()); + assertThat(importedDevice.getLabel()).isEqualTo(initialDevice.getLabel()); + } + + + @Test + public void testExportImportSingleRuleChain_betweenTenants() throws Exception { + logInAsTenantAdmin1(); + RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1"); + RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId()); + + EntityExportData exportData = exportSingleEntity(ruleChain.getId()); + assertThat(exportData.getEntity()).isEqualTo(ruleChain); + assertThat(((RuleChainExportData) exportData).getMetaData()).isEqualTo(metaData); + + logInAsTenantAdmin2(); + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + RuleChain importedRuleChain = importResult.getSavedEntity(); + RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId()); + + checkImportedEntity(tenantId1, ruleChain, tenantId2, importResult); + checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData); + } + + @Test + public void testExportImportSingleRuleChain_sameTenant() throws Exception { + logInAsTenantAdmin1(); + RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain v1.0"); + RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId()); + + EntityExportData exportData = exportSingleEntity(ruleChain.getId()); + + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + RuleChain importedRuleChain = importResult.getSavedEntity(); + RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId1, importedRuleChain.getId()); + + checkImportedEntity(tenantId1, ruleChain, tenantId1, importResult); + checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData); + } + + private void checkImportedRuleChainData(RuleChain initialRuleChain, RuleChainMetaData initialMetaData, RuleChain importedRuleChain, RuleChainMetaData importedMetaData) { + assertThat(importedRuleChain.getType()).isEqualTo(initialRuleChain.getType()); + assertThat(importedRuleChain.getName()).isEqualTo(initialRuleChain.getName()); + assertThat(importedRuleChain.isDebugMode()).isEqualTo(initialRuleChain.isDebugMode()); + assertThat(importedRuleChain.getConfiguration()).isEqualTo(initialRuleChain.getConfiguration()); + + assertThat(importedMetaData.getConnections()).isEqualTo(initialMetaData.getConnections()); + assertThat(importedMetaData.getFirstNodeIndex()).isEqualTo(initialMetaData.getFirstNodeIndex()); + for (int i = 0; i < initialMetaData.getNodes().size(); i++) { + RuleNode initialNode = initialMetaData.getNodes().get(i); + RuleNode importedNode = importedMetaData.getNodes().get(i); + assertThat(importedNode.getRuleChainId()).isEqualTo(importedRuleChain.getId()); + assertThat(importedNode.getName()).isEqualTo(initialNode.getName()); + assertThat(importedNode.getType()).isEqualTo(initialNode.getType()); + assertThat(importedNode.getConfiguration()).isEqualTo(initialNode.getConfiguration()); + assertThat(importedNode.getAdditionalInfo()).isEqualTo(initialNode.getAdditionalInfo()); + } + } + + + @Test + public void testExportImportSingleDashboard_betweenTenants() throws Exception { + logInAsTenantAdmin1(); + Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1"); + + EntityExportData exportData = exportSingleEntity(dashboard.getId()); + assertThat(exportData.getEntity()).isEqualTo(dashboard); + + logInAsTenantAdmin2(); + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + checkImportedEntity(tenantId1, dashboard, tenantId2, importResult); + checkImportedDashboardData(dashboard, importResult.getSavedEntity()); + } + + @Test + public void testExportImportSingleDashboard_sameTenant() throws Exception { + logInAsTenantAdmin1(); + Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard v1.0"); + + EntityExportData exportData = exportSingleEntity(dashboard.getId()); + + EntityImportResult importResult = importEntities(List.of(exportData)).get(0); + checkImportedEntity(tenantId1, dashboard, tenantId1, importResult); + checkImportedDashboardData(dashboard, importResult.getSavedEntity()); + } + + private void checkImportedDashboardData(Dashboard initialDashboard, Dashboard importedDashboard) { + assertThat(importedDashboard.getTitle()).isEqualTo(initialDashboard.getTitle()); + assertThat(importedDashboard.getConfiguration()).isEqualTo(initialDashboard.getConfiguration()); + assertThat(importedDashboard.getImage()).isEqualTo(initialDashboard.getImage()); + assertThat(importedDashboard.isMobileHide()).isEqualTo(initialDashboard.isMobileHide()); + if (initialDashboard.getAssignedCustomers() != null) { + assertThat(importedDashboard.getAssignedCustomers()).containsAll(initialDashboard.getAssignedCustomers()); + } + } + + + private > void checkImportedEntity(TenantId tenantId1, E initialEntity, TenantId tenantId2, EntityImportResult importResult) { + E importedEntity = importResult.getSavedEntity(); + + assertThat(initialEntity.getTenantId()).isEqualTo(tenantId1); + assertThat(importedEntity.getTenantId()).isEqualTo(tenantId2); + + assertThat(importedEntity.getExternalId()).isEqualTo(initialEntity.getId()); + + boolean sameTenant = tenantId1.equals(tenantId2); + if (!sameTenant) { + assertThat(importedEntity.getId()).isNotEqualTo(initialEntity.getId()); + } else { + assertThat(importedEntity.getId()).isEqualTo(initialEntity.getId()); + assertThat(importResult.getOldEntity()).isEqualTo(initialEntity); + } } @@ -217,6 +391,12 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp } } + private , I extends EntityId> EntityExportData exportSingleEntity(I entityId) throws Exception { + return readResponse(doPost("/api/entities/export/" + entityId.getEntityType() + "/" + entityId.getId().toString()) + .andExpect(status().isOk()), new TypeReference>() {}); + } + + private void logInAsTenantAdmin1() throws Exception { login(tenantAdmin1.getEmail(), "12345678"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java index 5b2b5a2366..9f2cd51952 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java @@ -15,16 +15,12 @@ */ package org.thingsboard.server.dao; -import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ExportableEntity; import java.util.UUID; -public interface ExportableEntityDao { +public interface ExportableEntityDao> extends TenantEntityDao { T findByTenantIdAndExternalId(UUID tenantId, UUID externalId); - T findByTenantIdAndId(UUID tenantId, UUID id); - - EntityType getEntityType(); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityRepository.java b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityRepository.java index b6a303a941..1ce43ffe12 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityRepository.java @@ -17,10 +17,8 @@ package org.thingsboard.server.dao; import java.util.UUID; -public interface ExportableEntityRepository { +public interface ExportableEntityRepository extends TenantEntityRepository { D findByTenantIdAndExternalId(UUID tenantId, UUID externalId); - D findByTenantIdAndId(UUID tenantId, UUID id); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java index 17367c2cc7..53ffb7882a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java @@ -15,9 +15,18 @@ */ package org.thingsboard.server.dao; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.TenantId; -public interface TenantEntityDao { +import java.util.UUID; + +public interface TenantEntityDao { Long countByTenantId(TenantId tenantId); + + T findByTenantIdAndId(UUID tenantId, UUID id); + + EntityType getEntityType(); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityRepository.java b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityRepository.java new file mode 100644 index 0000000000..8997f65ca8 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityRepository.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 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; + +import java.util.UUID; + +public interface TenantEntityRepository { + + D findByTenantIdAndId(UUID tenantId, UUID id); + + Long countByTenantId(UUID tenantId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java index 495886bcc4..c7cf6f38e9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java @@ -34,7 +34,7 @@ import java.util.UUID; * The Interface AssetDao. * */ -public interface AssetDao extends Dao, TenantEntityDao, ExportableEntityDao { +public interface AssetDao extends Dao, ExportableEntityDao { /** * Find asset info by id. diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java index 89672d2a73..df589711b9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java @@ -29,7 +29,7 @@ import java.util.UUID; /** * The Interface CustomerDao. */ -public interface CustomerDao extends Dao, TenantEntityDao, ExportableEntityDao { +public interface CustomerDao extends Dao, ExportableEntityDao { /** * Save or update customer object diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java index 90353f49b3..ef6a739391 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java @@ -24,7 +24,7 @@ import org.thingsboard.server.dao.TenantEntityDao; /** * The Interface DashboardDao. */ -public interface DashboardDao extends Dao, TenantEntityDao, ExportableEntityDao { +public interface DashboardDao extends Dao, ExportableEntityDao { /** * Save or update dashboard object diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 90f2b218a7..688e7246d4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -36,7 +36,7 @@ import java.util.UUID; * The Interface DeviceDao. * */ -public interface DeviceDao extends Dao, TenantEntityDao, ExportableEntityDao { +public interface DeviceDao extends Dao, ExportableEntityDao { /** * Find device info by id. diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java index 445210ca3b..a24df5794c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java @@ -21,6 +21,6 @@ import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; -public interface OtaPackageDao extends Dao, TenantEntityWithDataDao { +public interface OtaPackageDao extends Dao, TenantEntityWithDataDao, TenantEntityDao { Long sumDataSizeByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 59f287eadd..47f69cc99d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -30,7 +30,7 @@ import java.util.UUID; /** * Created by igor on 3/12/18. */ -public interface RuleChainDao extends Dao, TenantEntityDao, ExportableEntityDao { +public interface RuleChainDao extends Dao, ExportableEntityDao { /** * Find rule chains by tenantId and page link. diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java index 1300fcdfa5..893f22503d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java @@ -38,5 +38,4 @@ public interface CustomerRepository extends JpaRepository, CustomerEntity findByTenantIdAndTitle(UUID tenantId, String title); - Long countByTenantId(UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 539377a647..26e49e9c66 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -116,6 +116,11 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao { +public interface OtaPackageRepository extends JpaRepository, TenantEntityRepository { @Query(value = "SELECT COALESCE(SUM(ota.data_size), 0) FROM ota_package ota WHERE ota.tenant_id = :tenantId AND ota.data IS NOT NULL", nativeQuery = true) Long sumDataSizeByTenantId(@Param("tenantId") UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 888951778c..2b1bca32b3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -63,8 +63,6 @@ public interface RuleChainRepository extends JpaRepository findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index 6b2de9872a..42d331cab5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java @@ -18,6 +18,8 @@ package org.thingsboard.server.dao.sql.user; 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.EntityType; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -96,4 +98,15 @@ public class JpaUserDao extends JpaAbstractSearchTextDao imple public Long countByTenantId(TenantId tenantId) { return userRepository.countByTenantId(tenantId.getId()); } + + @Override + public User findByTenantIdAndId(UUID tenantId, UUID id) { + return DaoUtil.getData(userRepository.findByTenantIdAndId(tenantId, id)); + } + + @Override + public EntityType getEntityType() { + return EntityType.USER; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index 51f6138cc1..98b7cf0d00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -21,6 +21,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.TenantEntityDao; +import org.thingsboard.server.dao.TenantEntityRepository; import org.thingsboard.server.dao.model.sql.UserEntity; import java.util.UUID; @@ -28,7 +30,7 @@ import java.util.UUID; /** * @author Valerii Sosliuk */ -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository, TenantEntityRepository { UserEntity findByEmail(String email); @@ -47,5 +49,4 @@ public interface UserRepository extends JpaRepository { @Param("searchText") String searchText, Pageable pageable); - Long countByTenantId(UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java index b906b3278d..7e27c1bf00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java @@ -24,7 +24,7 @@ import org.thingsboard.server.dao.TenantEntityDao; import java.util.UUID; -public interface UserDao extends Dao, TenantEntityDao { +public interface UserDao extends Dao, TenantEntityDao { /** * Save or update user object