/* * Copyright © 2016-2017 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. */ import thingsboardTypes from '../common/types.constant'; export default angular.module('thingsboard.api.entity', [thingsboardTypes]) .factory('entityService', EntityService) .name; /*@ngInject*/ function EntityService($http, $q, $filter, $translate, $log, userService, deviceService, assetService, tenantService, customerService, ruleService, pluginService, dashboardService, entityRelationService, attributeService, types, utils) { var service = { getEntity: getEntity, getEntities: getEntities, getEntitiesByNameFilter: getEntitiesByNameFilter, resolveAlias: resolveAlias, resolveAliasFilter: resolveAliasFilter, checkEntityAlias: checkEntityAlias, filterAliasByEntityTypes: filterAliasByEntityTypes, getEntityKeys: getEntityKeys, createDatasourcesFromSubscriptionsInfo: createDatasourcesFromSubscriptionsInfo, getRelatedEntities: getRelatedEntities, saveRelatedEntity: saveRelatedEntity, getRelatedEntity: getRelatedEntity, deleteRelatedEntity: deleteRelatedEntity, moveEntity: moveEntity, copyEntity: copyEntity }; return service; function getEntityPromise(entityType, entityId, config) { var promise; switch (entityType) { case types.entityType.device: promise = deviceService.getDevice(entityId, true, config); break; case types.entityType.asset: promise = assetService.getAsset(entityId, true, config); break; case types.entityType.tenant: promise = tenantService.getTenant(entityId); break; case types.entityType.customer: promise = customerService.getCustomer(entityId); break; case types.entityType.rule: promise = ruleService.getRule(entityId); break; case types.entityType.plugin: promise = pluginService.getPlugin(entityId); break; case types.entityType.dashboard: promise = dashboardService.getDashboardInfo(entityId); break; case types.entityType.user: promise = userService.getUser(entityId); break; case types.entityType.alarm: $log.error('Get Alarm Entity is not implemented!'); break; } return promise; } function getEntity(entityType, entityId, config) { var deferred = $q.defer(); var promise = getEntityPromise(entityType, entityId, config); if (promise) { promise.then( function success(result) { deferred.resolve(result); }, function fail() { deferred.reject(); } ); } else { deferred.reject(); } return deferred.promise; } function getEntitiesByIdsPromise(fetchEntityFunction, entityIds) { var tasks = []; var deferred = $q.defer(); for (var i=0;i 0) { deferred.resolve(result.data); } else { deferred.resolve(null); } }, function fail() { deferred.resolve(null); } ); } else { deferred.resolve(null); } return deferred.promise; } function entityToEntityInfo(entity) { return { name: entity.name, entityType: entity.id.entityType, id: entity.id.id }; } function entitiesToEntitiesInfo(entities) { var entitiesInfo = []; for (var d = 0; d < entities.length; d++) { entitiesInfo.push(entityToEntityInfo(entities[d])); } return entitiesInfo; } function resolveAlias(entityAlias, stateParams) { var deferred = $q.defer(); var filter = entityAlias.filter; resolveAliasFilter(filter, stateParams, 100).then( function (result) { var entities = result.entities; var aliasInfo = { alias: entityAlias.alias, resolveMultiple: filter.resolveMultiple }; var resolvedEntities = entitiesToEntitiesInfo(entities); aliasInfo.resolvedEntities = resolvedEntities; aliasInfo.currentEntity = null; if (aliasInfo.resolvedEntities.length) { aliasInfo.currentEntity = aliasInfo.resolvedEntities[0]; } deferred.resolve(aliasInfo); }, function fail() { deferred.reject(); } ); return deferred.promise; } function resolveAliasFilter(filter, stateParams, maxItems) { var deferred = $q.defer(); var result = { entities: [], stateEntity: false }; switch (filter.type) { case types.aliasFilterType.entityList.value: if (filter.stateEntity) { result.stateEntity = true; if (stateParams && stateParams.entityId) { getEntity(stateParams.entityId.entityType, stateParams.entityId.id).then( function success(entity) { result.entities = [entity]; deferred.resolve(result); }, function fail() { deferred.reject(); } ); } else { deferred.resolve(result); } } else { getEntities(filter.entityType, filter.entityList).then( function success(entities) { if (entities && entities.length) { result.entities = entities; deferred.resolve(result); } else { deferred.reject(); } }, function fail() { deferred.reject(); } ); } break; case types.aliasFilterType.entityName.value: getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( function success(entities) { if (entities && entities.length) { result.entities = entities; deferred.resolve(result); } else { deferred.reject(); } }, function fail() { deferred.reject(); } ); break; //TODO: } return deferred.promise; } function filterAliasByEntityTypes(entityAlias, entityTypes) { var filter = entityAlias.filter; switch (filter.type) { case types.aliasFilterType.entityList.value: if (filter.stateEntity) { return true; } else { return entityTypes.indexOf(filter.entityType) > -1 ? true : false; } case types.aliasFilterType.entityName.value: return entityTypes.indexOf(filter.entityType) > -1 ? true : false; } //TODO: return false; } function checkEntityAlias(entityAlias) { var deferred = $q.defer(); resolveAliasFilter(entityAlias.filter, null, 1).then( function success(result) { if (result.stateEntity) { deferred.resolve(true); } else { var entities = result.entities; if (entities && entities.length) { deferred.resolve(true); } else { deferred.resolve(false); } } }, function fail() { deferred.resolve(false); } ); return deferred.promise; } /*function processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred) { if (index < aliasIds.length) { var aliasId = aliasIds[index]; var entityAlias = entityAliases[aliasId]; var alias = entityAlias.alias; var filter = entityAlias.filter; resolveAliasFilter(filter, stateParams).then( function (entities) { if (entities && entities.length) { var entity = entities[0]; var resolvedAlias = {alias: alias, entityType: entity.id.entityType, entityId: entity.id.id}; resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entities); index++; processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); } else { if (!resolution.error) { resolution.error = 'dashboard.invalid-aliases-config'; } index++; processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); } } ); } else { deferred.resolve(resolution); } }*/ /*function processEntityAliases(entityAliases, stateParams) { var deferred = $q.defer(); var resolution = { aliasesInfo: {} }; var aliasIds = []; if (entityAliases) { for (var aliasId in entityAliases) { aliasIds.push(aliasId); } } processEntityAlias(0, aliasIds, entityAliases, stateParams, resolution, deferred); return deferred.promise; }*/ function getEntityKeys(entityType, entityId, query, type) { var deferred = $q.defer(); var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; if (type === types.dataKeyType.timeseries) { url += 'timeseries'; } else if (type === types.dataKeyType.attribute) { url += 'attributes'; } $http.get(url, null).then(function success(response) { var result = []; if (response.data) { if (query) { var dataKeys = response.data; var lowercaseQuery = angular.lowercase(query); for (var i=0; i 0) { for (var i = 0; i < entities.length; i++) { var entity = entities[i]; createDatasourceFromSubscription(subscriptionInfo, datasources, entity); } } index++; processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); }, function fail() { index++; processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); } ) } else { index++; processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); } } else if (subscriptionInfo.type === types.datasourceType.function) { createDatasourceFromSubscription(subscriptionInfo, datasources); index++; processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); } } else { deferred.resolve(datasources); } } function validateSubscriptionInfo(subscriptionInfo) { if (subscriptionInfo.type === 'device') { subscriptionInfo.type = types.datasourceType.entity; subscriptionInfo.entityType = types.entityType.device; if (subscriptionInfo.deviceId) { subscriptionInfo.entityId = subscriptionInfo.deviceId; } else if (subscriptionInfo.deviceName) { subscriptionInfo.entityName = subscriptionInfo.deviceName; } else if (subscriptionInfo.deviceNamePrefix) { subscriptionInfo.entityNamePrefix = subscriptionInfo.deviceNamePrefix; } else if (subscriptionInfo.deviceIds) { subscriptionInfo.entityIds = subscriptionInfo.deviceIds; } } return subscriptionInfo; } function createDatasourceFromSubscription(subscriptionInfo, datasources, entity) { var datasource; if (subscriptionInfo.type === types.datasourceType.entity) { datasource = { type: subscriptionInfo.type, entityName: entity.name ? entity.name : entity.title, name: entity.name ? entity.name : entity.title, entityType: subscriptionInfo.entityType, entityId: entity.id.id, dataKeys: [] } } else if (subscriptionInfo.type === types.datasourceType.function) { datasource = { type: subscriptionInfo.type, name: subscriptionInfo.name || types.datasourceType.function, dataKeys: [] } } datasources.push(datasource); if (subscriptionInfo.timeseries) { createDatasourceKeys(subscriptionInfo.timeseries, types.dataKeyType.timeseries, datasource, datasources); } if (subscriptionInfo.attributes) { createDatasourceKeys(subscriptionInfo.attributes, types.dataKeyType.attribute, datasource, datasources); } if (subscriptionInfo.functions) { createDatasourceKeys(subscriptionInfo.functions, types.dataKeyType.function, datasource, datasources); } } function createDatasourceKeys(keyInfos, type, datasource, datasources) { for (var i=0;i -1) { var deleteRelatedEntityPromise = deleteRelatedEntity(relationEntityId, deleteRelatedEntityTypes); deleteRelatedEntitiesTasks.push(deleteRelatedEntityPromise); } } deleteRelatedEntitiesTasks.push(deleteEntityPromise(entityId)); $q.all(deleteRelatedEntitiesTasks).then( function success() { deferred.resolve(); }, function fail() { deferred.reject(); } ); }, function fail() { deferred.reject(); } ) } else { deleteEntityPromise(entityId).then( function success() { deferred.resolve(); }, function fail() { deferred.reject(); } ); } return deferred.promise; } function moveEntity(entityId, prevParentId, targetParentId) { var deferred = $q.defer(); entityRelationService.deleteRelation(prevParentId.id, prevParentId.entityType, types.entityRelationType.contains, entityId.id, entityId.entityType).then( function success() { var relation = { from: targetParentId, to: entityId, type: types.entityRelationType.contains }; entityRelationService.saveRelation(relation).then( function success() { deferred.resolve(); }, function fail() { deferred.reject(); } ); }, function fail() { deferred.reject(); } ); return deferred.promise; } function copyEntity(entity, targetParentId, keys) { var deferred = $q.defer(); if (!entity.id && !entity.id.id) { deferred.reject(); } else { getRelatedEntity(entity.id, keys).then( function success(relatedEntity) { delete relatedEntity.id.id; relatedEntity.name = entity.name; saveRelatedEntity(relatedEntity, targetParentId, keys).then( function success(savedEntity) { deferred.resolve(savedEntity); }, function fail() { deferred.reject(); } ); }, function fail() { deferred.reject(); } ); } return deferred.promise; } function saveEntityPromise(entity) { var entityType = entity.id.entityType; if (!entity.id.id) { delete entity.id; } if (entityType == types.entityType.asset) { return assetService.saveAsset(entity); } else if (entityType == types.entityType.device) { return deviceService.saveDevice(entity); } } function addRelatedEntity(relatedEntity, parentEntityId, keys, deferred) { var entity = {}; entity.id = relatedEntity.id; entity.name = relatedEntity.name; entity.type = relatedEntity.type; saveEntityPromise(entity).then( function success(entity) { relatedEntity.id = entity.id; var relation = { from: parentEntityId, to: relatedEntity.id, type: types.entityRelationType.contains }; entityRelationService.saveRelation(relation).then( function success() { updateEntity(entity, relatedEntity, keys, deferred); }, function fail() { deferred.reject(); } ); }, function fail() { deferred.reject(); } ); } function updateRelatedEntity(relatedEntity, keys, deferred) { getEntityPromise(relatedEntity.id.entityType, relatedEntity.id.id, {ignoreLoading: true}).then( function success(entity) { updateEntity(entity, relatedEntity, keys, deferred); }, function fail() { deferred.reject(); } ); } function updateEntity(entity, relatedEntity, keys, deferred) { if (!angular.equals(entity.name, relatedEntity.name) || !angular.equals(entity.type, relatedEntity.type)) { entity.name = relatedEntity.name; entity.type = relatedEntity.type; saveEntityPromise(entity).then( function success (entity) { updateEntityAttributes(entity, relatedEntity, keys, deferred); }, function fail() { deferred.reject(); } ); } else { updateEntityAttributes(entity, relatedEntity, keys, deferred); } } function updateEntityAttributes(entity, relatedEntity, keys, deferred) { var attributes = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; attributes.push({key: key, value: relatedEntity[key]}); } attributeService.saveEntityAttributes(entity.id.entityType, entity.id.id, types.attributesScope.server.value, attributes) .then( function success() { deferred.resolve(relatedEntity); }, function fail() { deferred.reject(); } ); } function constructRelatedEntitiesSearchQuery(rootEntityId, entityType, entitySubTypes, maxLevel) { var searchQuery = { parameters: { rootId: rootEntityId.id, rootType: rootEntityId.entityType, direction: types.entitySearchDirection.from }, relationType: types.entityRelationType.contains }; if (maxLevel) { searchQuery.parameters.maxLevel = maxLevel; } else { searchQuery.parameters.maxLevel = 1; } if (entityType == types.entityType.asset) { searchQuery.assetTypes = entitySubTypes; } else if (entityType == types.entityType.device) { searchQuery.deviceTypes = entitySubTypes; } else { return null; //Not supported } return searchQuery; } function constructEntity(entity, keys, typeTranslatePrefix) { var deferred = $q.defer(); if (typeTranslatePrefix) { entity.typeName = $translate.instant(typeTranslatePrefix+'.'+entity.type); } else { entity.typeName = entity.type; } attributeService.getEntityAttributesValues(entity.id.entityType, entity.id.id, types.attributesScope.server.value, keys.join(','), {ignoreLoading: true}).then( function success(attributes) { if (attributes && attributes.length > 0) { for (var i=0;i 0) { return foundAttributes[0].value; } else { return null; } } }