diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 4aa1a0a5cb..ec158fe6ec 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -97,8 +97,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"}) - @ResponseStatus(value = HttpStatus.OK) - public void checkRelation(@RequestParam("fromId") String strFromId, + @ResponseBody + public EntityRelation getRelation(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, @@ -114,10 +114,7 @@ public class EntityRelationController extends BaseController { checkEntityId(fromId); checkEntityId(toId); RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); - Boolean found = relationService.checkRelation(fromId, toId, strRelationType, typeGroup).get(); - if (!found) { - throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); - } + return checkNotNull(relationService.getRelation(fromId, toId, strRelationType, typeGroup).get()); } catch (Exception e) { throw handleException(e); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java index 72f159ea2a..195a9d9c0c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java @@ -127,6 +127,19 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false); } + @Override + public ListenableFuture getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + BoundStatement stmt = getCheckRelationStmt().bind() + .setUUID(0, from.getId()) + .setString(1, from.getEntityType().name()) + .setUUID(2, to.getId()) + .setString(3, to.getEntityType().name()) + .set(4, typeGroup, relationTypeGroupCodec) + .setString(5, relationType); + return getFuture(executeAsyncRead(stmt), rs -> rs != null ? getEntityRelation(rs.one()) : null); + } + + @Override public ListenableFuture saveRelation(EntityRelation relation) { BoundStatement stmt = getSaveStmt().bind() diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index d9b2f442a8..3e16e81b18 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -55,6 +55,13 @@ public class BaseRelationService implements RelationService { return relationDao.checkRelation(from, to, relationType, typeGroup); } + @Override + public ListenableFuture getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + log.trace("Executing EntityRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup); + validate(from, to, relationType, typeGroup); + return relationDao.getRelation(from, to, relationType, typeGroup); + } + @Override public ListenableFuture saveRelation(EntityRelation relation) { log.trace("Executing saveRelation [{}]", relation); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index 3abadb8253..ec946d0ed1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -39,6 +39,8 @@ public interface RelationDao { ListenableFuture checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture saveRelation(EntityRelation relation); ListenableFuture deleteRelation(EntityRelation relation); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index bd2e785a5b..cdecf39154 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -30,6 +30,8 @@ public interface RelationService { ListenableFuture checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture saveRelation(EntityRelation relation); ListenableFuture deleteRelation(EntityRelation relation); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 365b90fd1c..e6a5c79c25 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -108,6 +108,18 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple return service.submit(() -> relationRepository.findOne(key) != null); } + @Override + public ListenableFuture getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + RelationCompositeKey key = + new RelationCompositeKey(from.getId(), + from.getEntityType().name(), + to.getId(), + to.getEntityType().name(), + relationType, + typeGroup.name()); + return service.submit(() -> DaoUtil.getData(relationRepository.findOne(key))); + } + @Override public ListenableFuture saveRelation(EntityRelation relation) { return service.submit(() -> relationRepository.save(new RelationEntity(relation)) != null); diff --git a/ui/src/app/api/entity-relation.service.js b/ui/src/app/api/entity-relation.service.js index 351c252c56..742aec7a8a 100644 --- a/ui/src/app/api/entity-relation.service.js +++ b/ui/src/app/api/entity-relation.service.js @@ -24,6 +24,7 @@ function EntityRelationService($http, $q) { saveRelation: saveRelation, deleteRelation: deleteRelation, deleteRelations: deleteRelations, + getRelation: getRelation, findByFrom: findByFrom, findInfoByFrom: findInfoByFrom, findByFromAndType: findByFromAndType, @@ -74,6 +75,20 @@ function EntityRelationService($http, $q) { return deferred.promise; } + function getRelation(fromId, fromType, relationType, toId, toType) { + var deferred = $q.defer(); + var url = '/api/relation?fromId=' + fromId; + url += '&fromType=' + fromType; + url += '&relationType=' + relationType; + url += '&toId=' + toId; + url += '&toType=' + toType; + $http.get(url).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } function findByFrom(fromId, fromType) { var deferred = $q.defer(); diff --git a/ui/src/app/entity/entity-autocomplete.directive.js b/ui/src/app/entity/entity-autocomplete.directive.js index 350bde9b3e..8f8153d67b 100644 --- a/ui/src/app/entity/entity-autocomplete.directive.js +++ b/ui/src/app/entity/entity-autocomplete.directive.js @@ -34,9 +34,23 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter scope.fetchEntities = function(searchText) { var deferred = $q.defer(); - entityService.getEntitiesByNameFilter(scope.entityType, searchText, 50, null, scope.entitySubtype).then(function success(result) { + var limit = 50; + if (scope.excludeEntityIds && scope.excludeEntityIds.length) { + limit += scope.excludeEntityIds.length; + } + entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, null, scope.entitySubtype).then(function success(result) { if (result) { - deferred.resolve(result); + if (scope.excludeEntityIds && scope.excludeEntityIds.length) { + var entities = []; + result.forEach(function(entity) { + if (scope.excludeEntityIds.indexOf(entity.id.id) == -1) { + entities.push(entity); + } + }); + deferred.resolve(entities); + } else { + deferred.resolve(result); + } } else { deferred.resolve([]); } @@ -165,7 +179,8 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter tbRequired: '=?', disabled:'=ngDisabled', entityType: '=', - entitySubtype: '=?' + entitySubtype: '=?', + excludeEntityIds: '=?' } }; }