Merge branch 'feature/entities-version-control' of github.com:thingsboard/thingsboard into feature/entities-version-control

This commit is contained in:
Igor Kulikov 2022-06-13 12:20:32 +03:00
commit a1b0817e06
16 changed files with 174 additions and 118 deletions

View File

@ -36,6 +36,7 @@ import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import java.util.Collection;
import java.util.Comparator;
@ -74,9 +75,9 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
}
@Override
public <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(SecurityUser user, EntityExportData<E> exportData, EntityImportSettings importSettings,
public <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(EntitiesImportCtx ctx, EntityExportData<E> exportData,
boolean saveReferences, boolean sendEvents) throws ThingsboardException {
if (!rateLimitService.checkEntityImportLimit(user.getTenantId())) {
if (!rateLimitService.checkEntityImportLimit(ctx.getTenantId())) {
throw new ThingsboardException("Rate limit for entities import is exceeded", ThingsboardErrorCode.TOO_MANY_REQUESTS);
}
if (exportData.getEntity() == null || exportData.getEntity().getId() == null) {
@ -86,7 +87,7 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
EntityType entityType = exportData.getEntityType();
EntityImportService<I, E, EntityExportData<E>> importService = getImportService(entityType);
EntityImportResult<E> importResult = importService.importEntity(user, exportData, importSettings);
EntityImportResult<E> importResult = importService.importEntity(ctx, exportData);
if (saveReferences) {
importResult.getSaveReferencesCallback().run();

View File

@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import java.util.Comparator;
@ -31,7 +32,7 @@ public interface EntitiesExportImportService {
<E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportEntity(SecurityUser user, I entityId, EntityExportSettings exportSettings) throws ThingsboardException;
<E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(SecurityUser user, EntityExportData<E> exportData, EntityImportSettings importSettings,
<E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(EntitiesImportCtx ctx, EntityExportData<E> exportData,
boolean saveReferences, boolean sendEvents) throws ThingsboardException;

View File

@ -151,23 +151,6 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
entityRemover.accept(tenantId, id);
}
@Override
public void checkPermission(SecurityUser user, HasId<? extends EntityId> entity, EntityType entityType, Operation operation) throws ThingsboardException {
if (entity instanceof HasTenantId) {
accessControlService.checkPermission(user, Resource.of(entityType), operation, entity.getId(), (HasTenantId) entity);
} else {
accessControlService.checkPermission(user, Resource.of(entityType), operation);
}
}
@Override
public void checkPermission(SecurityUser user, EntityId entityId, Operation operation) throws ThingsboardException {
HasId<EntityId> entity = findEntityByTenantIdAndId(user.getTenantId(), entityId);
checkPermission(user, entity, entityId.getEntityType(), operation);
}
@SuppressWarnings("unchecked")
private <E> Dao<E> getDao(EntityType entityType) {
return (Dao<E>) daos.get(entityType);

View File

@ -40,9 +40,4 @@ public interface ExportableEntitiesService {
<I extends EntityId> void removeById(TenantId tenantId, I id);
void checkPermission(SecurityUser user, HasId<? extends EntityId> entity, EntityType entityType, Operation operation) throws ThingsboardException;
void checkPermission(SecurityUser user, EntityId entityId, Operation operation) throws ThingsboardException;
}

View File

@ -66,7 +66,6 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
if (entity == null) {
throw new IllegalArgumentException(entityId.getEntityType() + " [" + entityId.getId() + "] not found");
}
exportableEntitiesService.checkPermission(user, entity, entity.getId().getEntityType(), Operation.READ);
exportData.setEntity(entity);
exportData.setEntityType(entityId.getEntityType());
@ -90,22 +89,14 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
List<EntityRelation> relations = new ArrayList<>();
List<EntityRelation> inboundRelations = relationService.findByTo(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
for (EntityRelation relation : inboundRelations) {
exportableEntitiesService.checkPermission(user, relation.getFrom(), Operation.READ);
}
relations.addAll(inboundRelations);
List<EntityRelation> outboundRelations = relationService.findByFrom(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
for (EntityRelation relation : outboundRelations) {
exportableEntitiesService.checkPermission(user, relation.getTo(), Operation.READ);
}
relations.addAll(outboundRelations);
return relations;
}
private Map<String, List<AttributeExportData>> exportAttributes(SecurityUser user, E entity) throws ThingsboardException {
exportableEntitiesService.checkPermission(user, entity, entity.getId().getEntityType(), Operation.READ_ATTRIBUTES);
List<String> scopes;
if (entity.getId().getEntityType() == EntityType.DEVICE) {
scopes = List.of(DataConstants.SERVER_SCOPE, DataConstants.SHARED_SCOPE);

View File

@ -23,10 +23,11 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
public interface EntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> {
EntityImportResult<E> importEntity(SecurityUser user, D exportData, EntityImportSettings importSettings) throws ThingsboardException;
EntityImportResult<E> importEntity(EntitiesImportCtx ctx, D exportData) throws ThingsboardException;
EntityType getEntityType();

View File

@ -28,6 +28,7 @@ import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@Service
@TbCoreComponent
@ -43,7 +44,7 @@ public class AssetImportService extends BaseEntityImportService<AssetId, Asset,
}
@Override
protected Asset prepareAndSave(TenantId tenantId, Asset asset, EntityExportData<Asset> exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected Asset prepareAndSave(EntitiesImportCtx ctx, Asset asset, EntityExportData<Asset> exportData, IdProvider idProvider) {
return assetService.saveAsset(asset);
}

View File

@ -53,6 +53,7 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import java.util.ArrayList;
@ -81,54 +82,53 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@Transactional(rollbackFor = Exception.class)
@Override
public EntityImportResult<E> importEntity(SecurityUser user, D exportData, EntityImportSettings importSettings) throws ThingsboardException {
public EntityImportResult<E> importEntity(EntitiesImportCtx ctx, D exportData) throws ThingsboardException {
E entity = exportData.getEntity();
E existingEntity = findExistingEntity(user.getTenantId(), entity, importSettings);
E existingEntity = findExistingEntity(ctx, entity);
entity.setExternalId(entity.getId());
EntityImportResult<E> importResult = new EntityImportResult<>();
IdProvider idProvider = new IdProvider(user, importSettings, importResult);
setOwner(user.getTenantId(), entity, idProvider);
IdProvider idProvider = new IdProvider(ctx, importResult);
setOwner(ctx.getTenantId(), entity, idProvider);
if (existingEntity == null) {
entity.setId(null);
exportableEntitiesService.checkPermission(user, entity, getEntityType(), Operation.CREATE);
} else {
entity.setId(existingEntity.getId());
entity.setCreatedTime(existingEntity.getCreatedTime());
exportableEntitiesService.checkPermission(user, existingEntity, getEntityType(), Operation.WRITE);
}
E savedEntity = prepareAndSave(user.getTenantId(), entity, exportData, idProvider, importSettings);
E savedEntity = prepareAndSave(ctx, entity, exportData, idProvider);
importResult.setSavedEntity(savedEntity);
importResult.setOldEntity(existingEntity);
importResult.setEntityType(getEntityType());
processAfterSaved(user, importResult, exportData, idProvider, importSettings);
processAfterSaved(ctx, importResult, exportData, idProvider);
ctx.putInternalId(exportData.getExternalId(), savedEntity.getId());
return importResult;
}
protected abstract void setOwner(TenantId tenantId, E entity, IdProvider idProvider);
protected abstract E prepareAndSave(TenantId tenantId, E entity, D exportData, IdProvider idProvider, EntityImportSettings importSettings);
protected abstract E prepareAndSave(EntitiesImportCtx ctx, E entity, D exportData, IdProvider idProvider);
protected void processAfterSaved(SecurityUser user, EntityImportResult<E> importResult, D exportData,
IdProvider idProvider, EntityImportSettings importSettings) throws ThingsboardException {
protected void processAfterSaved(EntitiesImportCtx ctx, EntityImportResult<E> importResult, D exportData, IdProvider idProvider) throws ThingsboardException {
E savedEntity = importResult.getSavedEntity();
E oldEntity = importResult.getOldEntity();
importResult.addSendEventsCallback(() -> {
onEntitySaved(user, savedEntity, oldEntity);
onEntitySaved(ctx.getUser(), savedEntity, oldEntity);
});
if (importSettings.isUpdateRelations() && exportData.getRelations() != null) {
importRelations(user, exportData.getRelations(), importResult);
if (ctx.isUpdateRelations() && exportData.getRelations() != null) {
importRelations(ctx.getUser(), exportData.getRelations(), importResult);
}
if (importSettings.isSaveAttributes() && exportData.getAttributes() != null) {
importAttributes(user, exportData.getAttributes(), importResult);
if (ctx.isSaveAttributes() && exportData.getAttributes() != null) {
importAttributes(ctx.getUser(), exportData.getAttributes(), importResult);
}
}
@ -138,12 +138,10 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
for (EntityRelation relation : relations) {
if (!relation.getTo().equals(entity.getId())) {
HasId<EntityId> to = findInternalEntity(user.getTenantId(), relation.getTo());
exportableEntitiesService.checkPermission(user, to, to.getId().getEntityType(), Operation.WRITE);
relation.setTo(to.getId());
}
if (!relation.getFrom().equals(entity.getId())) {
HasId<EntityId> from = findInternalEntity(user.getTenantId(), relation.getFrom());
exportableEntitiesService.checkPermission(user, from, from.getId().getEntityType(), Operation.WRITE);
relation.setFrom(from.getId());
}
}
@ -155,15 +153,6 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
for (EntityRelation existingRelation : existingRelations) {
if (!relations.contains(existingRelation)) {
EntityId otherEntity = null;
if (!existingRelation.getTo().equals(entity.getId())) {
otherEntity = existingRelation.getTo();
} else if (!existingRelation.getFrom().equals(entity.getId())) {
otherEntity = existingRelation.getFrom();
}
if (otherEntity != null) {
exportableEntitiesService.checkPermission(user, otherEntity, Operation.WRITE);
}
relationService.deleteRelation(user.getTenantId(), existingRelation);
importResult.addSendEventsCallback(() -> {
entityActionService.logEntityAction(user, existingRelation.getFrom(), null, null,
@ -234,12 +223,12 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@SuppressWarnings("unchecked")
protected E findExistingEntity(TenantId tenantId, E entity, EntityImportSettings importSettings) {
return (E) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(tenantId, entity.getId()))
.or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(tenantId, entity.getId())))
protected E findExistingEntity(EntitiesImportCtx ctx, E entity) {
return (E) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(ctx.getTenantId(), entity.getId()))
.or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entity.getId())))
.or(() -> {
if (importSettings.isFindExistingByName()) {
return Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndName(tenantId, getEntityType(), entity.getName()));
if (ctx.isFindExistingByName()) {
return Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndName(ctx.getTenantId(), getEntityType(), entity.getName()));
} else {
return Optional.empty();
}
@ -255,22 +244,27 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}
@SuppressWarnings("unchecked")
@RequiredArgsConstructor
protected class IdProvider {
private final SecurityUser user;
private final EntityImportSettings importSettings;
private final EntitiesImportCtx ctx;
private final EntityImportResult<E> importResult;
public <ID extends EntityId> ID getInternalId(ID externalId) {
return getInternalId(externalId, true);
}
}
public <ID extends EntityId> ID getInternalId(ID externalId, boolean throwExceptionIfNotFound) {
if (externalId == null || externalId.isNullUid()) return null;
EntityId localId = ctx.getInternalId(externalId);
if (localId != null) {
return (ID) localId;
}
HasId<ID> entity;
try {
entity = findInternalEntity(user.getTenantId(), externalId);
entity = findInternalEntity(ctx.getTenantId(), externalId);
} catch (Exception e) {
if (throwExceptionIfNotFound) {
throw e;
@ -279,17 +273,26 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
return null;
}
}
try {
exportableEntitiesService.checkPermission(user, entity, entity.getId().getEntityType(), Operation.READ);
} catch (ThingsboardException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
ctx.putInternalId(externalId, entity.getId());
return entity.getId();
}
public Optional<EntityId> getInternalIdByUuid(UUID externalUuid) {
if (externalUuid.equals(EntityId.NULL_UUID)) return Optional.empty();
for (EntityType entityType : EntityType.values()) {
EntityId externalId;
try {
externalId = EntityIdFactory.getByTypeAndUuid(entityType, externalUuid);
} catch (Exception e) {
continue;
}
EntityId internalId = ctx.getInternalId(externalId);
if (internalId != null) {
return Optional.of(internalId);
}
}
for (EntityType entityType : EntityType.values()) {
EntityId externalId;
try {
@ -301,12 +304,13 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
EntityId internalId = getInternalId(externalId, false);
if (internalId != null) {
return Optional.of(internalId);
} else if (importSettings.isResetExternalIdsOfAnotherTenant()) {
} else if (ctx.isResetExternalIdsOfAnotherTenant()) {
try {
if (exportableEntitiesService.findEntityById(externalId) != null) {
return Optional.of(EntityIdFactory.getByTypeAndUuid(entityType, EntityId.NULL_UUID));
}
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
}

View File

@ -29,6 +29,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@Service
@TbCoreComponent
@ -44,13 +45,13 @@ public class CustomerImportService extends BaseEntityImportService<CustomerId, C
}
@Override
protected Customer prepareAndSave(TenantId tenantId, Customer customer, EntityExportData<Customer> exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected Customer prepareAndSave(EntitiesImportCtx ctx, Customer customer, EntityExportData<Customer> exportData, IdProvider idProvider) {
if (!customer.isPublic()) {
return customerService.saveCustomer(customer);
} else {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Customer publicCustomer = customerService.findOrCreatePublicCustomer(ctx.getTenantId());
publicCustomer.setExternalId(customer.getExternalId());
return customerDao.save(tenantId, publicCustomer);
return customerDao.save(ctx.getTenantId(), publicCustomer);
}
}

View File

@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.utils.RegexUtils;
import java.util.ArrayList;
@ -58,16 +59,17 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
}
@Override
protected Dashboard findExistingEntity(TenantId tenantId, Dashboard dashboard, EntityImportSettings importSettings) {
Dashboard existingDashboard = super.findExistingEntity(tenantId, dashboard, importSettings);
if (existingDashboard == null && importSettings.isFindExistingByName()) {
existingDashboard = dashboardService.findTenantDashboardsByTitle(tenantId, dashboard.getName()).stream().findFirst().orElse(null);
protected Dashboard findExistingEntity(EntitiesImportCtx ctx, Dashboard dashboard) {
Dashboard existingDashboard = super.findExistingEntity(ctx, dashboard);
if (existingDashboard == null && ctx.isFindExistingByName()) {
existingDashboard = dashboardService.findTenantDashboardsByTitle(ctx.getTenantId(), dashboard.getName()).stream().findFirst().orElse(null);
}
return existingDashboard;
}
@Override
protected Dashboard prepareAndSave(TenantId tenantId, Dashboard dashboard, EntityExportData<Dashboard> exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected Dashboard prepareAndSave(EntitiesImportCtx ctx, Dashboard dashboard, EntityExportData<Dashboard> exportData, IdProvider idProvider) {
var tenantId = ctx.getTenantId();
JsonNode configuration = dashboard.getConfiguration();
JsonNode entityAliases = configuration.get("entityAliases");
if (entityAliases != null && entityAliases.isObject()) {

View File

@ -27,6 +27,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.ie.DeviceExportData;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@Service
@TbCoreComponent
@ -42,11 +43,11 @@ public class DeviceImportService extends BaseEntityImportService<DeviceId, Devic
}
@Override
protected Device prepareAndSave(TenantId tenantId, Device device, DeviceExportData exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected Device prepareAndSave(EntitiesImportCtx ctx, Device device, DeviceExportData exportData, IdProvider idProvider) {
device.setDeviceProfileId(idProvider.getInternalId(device.getDeviceProfileId()));
device.setFirmwareId(idProvider.getInternalId(device.getFirmwareId()));
device.setSoftwareId(idProvider.getInternalId(device.getSoftwareId()));
if (exportData.getCredentials() != null && importSettings.isSaveCredentials()) {
if (exportData.getCredentials() != null && ctx.isSaveCredentials()) {
exportData.getCredentials().setId(null);
exportData.getCredentials().setDeviceId(null);
return deviceService.saveDeviceWithCredentials(device, exportData.getCredentials());

View File

@ -30,6 +30,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import java.util.Objects;
@ -47,7 +48,7 @@ public class DeviceProfileImportService extends BaseEntityImportService<DevicePr
}
@Override
protected DeviceProfile prepareAndSave(TenantId tenantId, DeviceProfile deviceProfile, EntityExportData<DeviceProfile> exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected DeviceProfile prepareAndSave(EntitiesImportCtx ctx, DeviceProfile deviceProfile, EntityExportData<DeviceProfile> exportData, IdProvider idProvider) {
deviceProfile.setDefaultRuleChainId(idProvider.getInternalId(deviceProfile.getDefaultRuleChainId()));
deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId()));
deviceProfile.setFirmwareId(idProvider.getInternalId(deviceProfile.getFirmwareId()));

View File

@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections;
@ -52,16 +53,16 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
}
@Override
protected RuleChain findExistingEntity(TenantId tenantId, RuleChain ruleChain, EntityImportSettings importSettings) {
RuleChain existingRuleChain = super.findExistingEntity(tenantId, ruleChain, importSettings);
if (existingRuleChain == null && importSettings.isFindExistingByName()) {
existingRuleChain = ruleChainService.findTenantRuleChainsByTypeAndName(tenantId, ruleChain.getType(), ruleChain.getName()).stream().findFirst().orElse(null);
protected RuleChain findExistingEntity(EntitiesImportCtx ctx, RuleChain ruleChain) {
RuleChain existingRuleChain = super.findExistingEntity(ctx, ruleChain);
if (existingRuleChain == null && ctx.isFindExistingByName()) {
existingRuleChain = ruleChainService.findTenantRuleChainsByTypeAndName(ctx.getTenantId(), ruleChain.getType(), ruleChain.getName()).stream().findFirst().orElse(null);
}
return existingRuleChain;
}
@Override
protected RuleChain prepareAndSave(TenantId tenantId, RuleChain ruleChain, RuleChainExportData exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected RuleChain prepareAndSave(EntitiesImportCtx ctx, RuleChain ruleChain, RuleChainExportData exportData, IdProvider idProvider) {
RuleChainMetaData metaData = exportData.getMetaData();
Optional.ofNullable(metaData.getNodes()).orElse(Collections.emptyList())
.forEach(ruleNode -> {
@ -85,8 +86,8 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
ruleChain = ruleChainService.saveRuleChain(ruleChain);
exportData.getMetaData().setRuleChainId(ruleChain.getId());
ruleChainService.saveRuleChainMetaData(tenantId, exportData.getMetaData());
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
ruleChainService.saveRuleChainMetaData(ctx.getTenantId(), exportData.getMetaData());
return ruleChainService.findRuleChainById(ctx.getTenantId(), ruleChain.getId());
}
@Override

View File

@ -32,6 +32,7 @@ import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import java.util.Map;
import java.util.stream.Collectors;
@ -50,17 +51,17 @@ public class WidgetsBundleImportService extends BaseEntityImportService<WidgetsB
}
@Override
protected WidgetsBundle prepareAndSave(TenantId tenantId, WidgetsBundle widgetsBundle, WidgetsBundleExportData exportData, IdProvider idProvider, EntityImportSettings importSettings) {
protected WidgetsBundle prepareAndSave(EntitiesImportCtx ctx, WidgetsBundle widgetsBundle, WidgetsBundleExportData exportData, IdProvider idProvider) {
WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle);
if (widgetsBundle.getId() == null) {
for (WidgetTypeDetails widget : exportData.getWidgets()) {
widget.setId(null);
widget.setTenantId(tenantId);
widget.setTenantId(ctx.getTenantId());
widget.setBundleAlias(savedWidgetsBundle.getAlias());
widgetTypeService.saveWidgetType(widget);
}
} else {
Map<String, WidgetTypeInfo> existingWidgets = widgetTypeService.findWidgetTypesInfosByTenantIdAndBundleAlias(tenantId, savedWidgetsBundle.getAlias()).stream()
Map<String, WidgetTypeInfo> existingWidgets = widgetTypeService.findWidgetTypesInfosByTenantIdAndBundleAlias(ctx.getTenantId(), savedWidgetsBundle.getAlias()).stream()
.collect(Collectors.toMap(BaseWidgetType::getAlias, w -> w));
for (WidgetTypeDetails widget : exportData.getWidgets()) {
WidgetTypeInfo existingWidget;
@ -70,13 +71,13 @@ public class WidgetsBundleImportService extends BaseEntityImportService<WidgetsB
} else {
widget.setId(null);
}
widget.setTenantId(tenantId);
widget.setTenantId(ctx.getTenantId());
widget.setBundleAlias(savedWidgetsBundle.getAlias());
widgetTypeService.saveWidgetType(widget);
}
existingWidgets.values().stream()
.map(BaseWidgetType::getId)
.forEach(widgetTypeId -> widgetTypeService.deleteWidgetType(tenantId, widgetTypeId));
.forEach(widgetTypeId -> widgetTypeService.deleteWidgetType(ctx.getTenantId(), widgetTypeId));
}
return savedWidgetsBundle;
}

View File

@ -77,6 +77,7 @@ import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesServic
import org.thingsboard.server.service.sync.ie.importing.impl.MissingEntityException;
import org.thingsboard.server.service.sync.vc.autocommit.TbAutoCommitSettingsService;
import org.thingsboard.server.service.sync.vc.data.CommitGitRequest;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.service.sync.vc.repository.TbRepositorySettingsService;
import javax.annotation.PostConstruct;
@ -244,13 +245,13 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
private VersionLoadResult loadSingleEntity(SecurityUser user, VersionLoadConfig config, EntityExportData entityData) {
try {
EntityImportResult<?> importResult = exportImportService.importEntity(user, entityData,
EntityImportSettings.builder()
var ctx = new EntitiesImportCtx(user, EntityImportSettings.builder()
.updateRelations(config.isLoadRelations())
.saveAttributes(config.isLoadAttributes())
.saveCredentials(config.isLoadCredentials())
.findExistingByName(false)
.build(), true, true);
.build());
EntityImportResult<?> importResult = exportImportService.importEntity(ctx, entityData, true, true);
return VersionLoadResult.success(EntityTypeLoadResult.builder()
.entityType(importResult.getEntityType())
.created(importResult.getOldEntity() == null ? 1 : 0)
@ -269,6 +270,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
List<ThrowingRunnable> saveReferencesCallbacks = new ArrayList<>();
List<ThrowingRunnable> sendEventsCallbacks = new ArrayList<>();
EntitiesImportCtx ctx = new EntitiesImportCtx(user);
List<EntityType> entityTypes = request.getEntityTypes().keySet().stream()
.sorted(exportImportService.getEntityTypeComparatorForImport()).collect(Collectors.toList());
for (EntityType entityType : entityTypes) {
@ -285,21 +288,20 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
EntityImportSettings importSettings = EntityImportSettings.builder()
ctx.setSettings(EntityImportSettings.builder()
.updateRelations(config.isLoadRelations())
.saveAttributes(config.isLoadAttributes())
.findExistingByName(config.isFindExistingEntityByName())
.build();
.build());
for (EntityExportData entityData : entityDataList) {
EntityImportResult<?> importResult;
try {
importResult = exportImportService.importEntity(user, entityData,
importSettings, false, false);
importResult = exportImportService.importEntity(ctx, entityData, false, false);
} catch (Exception e) {
throw new LoadEntityException(entityData, e);
}
if (importResult.getUpdatedAllExternalIds() != null && !importResult.getUpdatedAllExternalIds()) {
toReimport.put(entityData.getEntity().getExternalId(), importSettings);
toReimport.put(entityData.getEntity().getExternalId(), ctx.getSettings());
continue;
}
@ -324,8 +326,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
try {
EntityExportData entityData = gitServiceQueue.getEntity(user.getTenantId(), request.getVersionId(), externalId).get();
importSettings.setResetExternalIdsOfAnotherTenant(true);
EntityImportResult<?> importResult = exportImportService.importEntity(user, entityData,
importSettings, false, false);
ctx.setSettings(importSettings);
EntityImportResult<?> importResult = exportImportService.importEntity(ctx, entityData, false, false);
EntityTypeLoadResult stats = results.get(externalId.getEntityType());
if (importResult.getOldEntity() == null) stats.setCreated(stats.getCreated() + 1);
@ -347,11 +349,6 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
return exportableEntitiesService.findEntitiesByTenantId(user.getTenantId(), entityType, pageLink);
}, 100, entity -> {
if (importedEntities.get(entityType) == null || !importedEntities.get(entityType).contains(entity.getId())) {
try {
exportableEntitiesService.checkPermission(user, entity, entityType, Operation.DELETE);
} catch (ThingsboardException e) {
throw new RuntimeException(e);
}
exportableEntitiesService.removeById(user.getTenantId(), entity.getId());
sendEventsCallbacks.add(() -> {

View File

@ -0,0 +1,75 @@
/**
* 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.vc.data;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.HashMap;
import java.util.Map;
@Data
public class EntitiesImportCtx {
private final SecurityUser user;
private EntityImportSettings settings;
private final Map<EntityId, EntityId> externalToInternalIdMap = new HashMap<>();
public EntitiesImportCtx(SecurityUser user) {
this(user, null);
}
public EntitiesImportCtx(SecurityUser user, EntityImportSettings settings) {
this.user = user;
this.settings = settings;
}
public TenantId getTenantId() {
return user.getTenantId();
}
public boolean isFindExistingByName() {
return getSettings().isFindExistingByName();
}
public boolean isUpdateRelations() {
return getSettings().isUpdateRelations();
}
public boolean isSaveAttributes() {
return getSettings().isSaveAttributes();
}
public boolean isSaveCredentials() {
return getSettings().isSaveCredentials();
}
public boolean isResetExternalIdsOfAnotherTenant() {
return getSettings().isResetExternalIdsOfAnotherTenant();
}
public EntityId getInternalId(EntityId externalId) {
return externalToInternalIdMap.get(externalId);
}
public void putInternalId(EntityId externalId, EntityId internalId) {
externalToInternalIdMap.put(externalId, internalId);
}
}