Pushed users from CE to edge

This commit is contained in:
Volodymyr Babak 2020-06-12 10:36:03 +03:00
parent ab1014bf16
commit e8afd97605
8 changed files with 133 additions and 348 deletions

View File

@ -306,88 +306,4 @@ public class UserController extends BaseController {
throw handleException(e); throw handleException(e);
} }
} }
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/user/{userId}", method = RequestMethod.POST)
@ResponseBody
public User assignUserToEdge(@PathVariable(EDGE_ID) String strEdgeId,
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(USER_ID, strUserId);
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
Edge edge = checkEdgeId(edgeId, Operation.READ);
UserId userId = new UserId(toUUID(strUserId));
checkUserId(userId, Operation.ASSIGN_TO_EDGE);
User savedUser = checkNotNull(userService.assignUserToEdge(getTenantId(), userId, edgeId));
logEntityAction(userId, savedUser,
savedUser.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strUserId, strEdgeId, edge.getName());
return savedUser;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.USER), null,
null,
ActionType.ASSIGNED_TO_EDGE, e, strUserId, strEdgeId);
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/user/{userId}", method = RequestMethod.DELETE)
@ResponseBody
public User unassignUserFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(USER_ID, strUserId);
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
Edge edge = checkEdgeId(edgeId, Operation.READ);
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.UNASSIGN_FROM_EDGE);
User savedUser = checkNotNull(userService.unassignUserFromEdge(getTenantId(), userId, edgeId));
logEntityAction(userId, savedUser,
savedUser.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strUserId, edge.getId().toString(), edge.getName());
return savedUser;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.USER), null,
null,
ActionType.UNASSIGNED_FROM_EDGE, e, strUserId);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/users", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public TimePageData<User> getEdgeUsers(
@PathVariable(EDGE_ID) String strEdgeId,
@RequestParam int limit,
@RequestParam(required = false) Long startTime,
@RequestParam(required = false) Long endTime,
@RequestParam(required = false, defaultValue = "false") boolean ascOrder,
@RequestParam(required = false) String offset) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
return checkNotNull(userService.findUsersByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
} catch (Exception e) {
throw handleException(e);
}
}
} }

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.init;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -30,6 +31,8 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
@ -121,53 +124,57 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
@Override @Override
public void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream) { public void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream) {
Set<EntityId> pushedEntityIds = new HashSet<>(); Set<EntityId> pushedEntityIds = new HashSet<>();
syncRuleChains(edge, pushedEntityIds, outputStream);
syncDevices(edge, pushedEntityIds, outputStream);
syncAssets(edge, pushedEntityIds, outputStream);
syncEntityViews(edge, pushedEntityIds, outputStream);
syncDashboards(edge, pushedEntityIds, outputStream);
syncUsers(ctx, edge, pushedEntityIds, outputStream); syncUsers(ctx, edge, pushedEntityIds, outputStream);
syncRelations(ctx, edge, pushedEntityIds, outputStream); List<ListenableFuture<Void>> futures = new ArrayList<>();
futures.add(syncRuleChains(ctx, edge, pushedEntityIds, outputStream));
futures.add(syncDevices(ctx, edge, pushedEntityIds, outputStream));
futures.add(syncAssets(ctx, edge, pushedEntityIds, outputStream));
futures.add(syncEntityViews(ctx, edge, pushedEntityIds, outputStream));
futures.add(syncDashboards(ctx, edge, pushedEntityIds, outputStream));
ListenableFuture<List<Void>> joinFuture = Futures.allAsList(futures);
Futures.transform(joinFuture, result -> {
syncRelations(ctx, edge, pushedEntityIds, outputStream);
return null;
}, MoreExecutors.directExecutor());
} }
private void syncRuleChains(Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private ListenableFuture<Void> syncRuleChains(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); ListenableFuture<TimePageData<RuleChain>> future = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
TimePageData<RuleChain> pageData; return Futures.transform(future, pageData -> {
do { try {
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (RuleChain ruleChain : pageData.getData()) {
for (RuleChain ruleChain : pageData.getData()) { RuleChainUpdateMsg ruleChainUpdateMsg =
RuleChainUpdateMsg ruleChainUpdateMsg = ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg(
ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg( edge.getRootRuleChainId(),
edge.getRootRuleChainId(), UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, ruleChain);
ruleChain); EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setRuleChainUpdateMsg(ruleChainUpdateMsg)
.setRuleChainUpdateMsg(ruleChainUpdateMsg) .build();
.build(); outputStream.onNext(ResponseMsg.newBuilder()
outputStream.onNext(ResponseMsg.newBuilder() .setEntityUpdateMsg(entityUpdateMsg)
.setEntityUpdateMsg(entityUpdateMsg) .build());
.build()); pushedEntityIds.add(ruleChain.getId());
pushedEntityIds.add(ruleChain.getId()); }
} }
} catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on sync!", e);
} }
if (pageData.hasNext()) { return null;
pageLink = pageData.getNextPageLink(); }, ctx.getDbCallbackExecutor());
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on sync!", e); log.error("Exception during loading edge rule chain(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncDevices(Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private ListenableFuture<Void> syncDevices(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); ListenableFuture<TimePageData<Device>> future = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
TimePageData<Device> pageData; return Futures.transform(future, pageData -> {
do {
pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
if (!pageData.getData().isEmpty()) { if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Device device : pageData.getData()) { for (Device device : pageData.getData()) {
@ -184,22 +191,19 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
pushedEntityIds.add(device.getId()); pushedEntityIds.add(device.getId());
} }
} }
if (pageData.hasNext()) { return null;
pageLink = pageData.getNextPageLink(); }, ctx.getDbCallbackExecutor());
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge device(s) on sync!", e); log.error("Exception during loading edge device(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncAssets(Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private ListenableFuture<Void> syncAssets(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); ListenableFuture<TimePageData<Asset>> future = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
TimePageData<Asset> pageData; return Futures.transform(future, pageData -> {
do { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Asset asset : pageData.getData()) { for (Asset asset : pageData.getData()) {
AssetUpdateMsg assetUpdateMsg = AssetUpdateMsg assetUpdateMsg =
@ -215,110 +219,112 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
pushedEntityIds.add(asset.getId()); pushedEntityIds.add(asset.getId());
} }
} }
if (pageData.hasNext()) { return null;
pageLink = pageData.getNextPageLink(); }, ctx.getDbCallbackExecutor());
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge asset(s) on sync!", e); log.error("Exception during loading edge asset(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncEntityViews(Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private ListenableFuture<Void> syncEntityViews(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); ListenableFuture<TimePageData<EntityView>> future = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
TimePageData<EntityView> pageData; return Futures.transform(future, pageData -> {
do { try {
pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (EntityView entityView : pageData.getData()) {
for (EntityView entityView : pageData.getData()) { EntityViewUpdateMsg entityViewUpdateMsg =
EntityViewUpdateMsg entityViewUpdateMsg = entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg(
entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg( UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, entityView);
entityView); EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setEntityViewUpdateMsg(entityViewUpdateMsg)
.setEntityViewUpdateMsg(entityViewUpdateMsg) .build();
.build(); outputStream.onNext(ResponseMsg.newBuilder()
outputStream.onNext(ResponseMsg.newBuilder() .setEntityUpdateMsg(entityUpdateMsg)
.setEntityUpdateMsg(entityUpdateMsg) .build());
.build()); pushedEntityIds.add(entityView.getId());
pushedEntityIds.add(entityView.getId()); }
} }
} catch (Exception e) {
log.error("Exception during loading edge entity view(s) on sync!", e);
} }
if (pageData.hasNext()) { return null;
pageLink = pageData.getNextPageLink(); }, ctx.getDbCallbackExecutor());
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge entity view(s) on sync!", e); log.error("Exception during loading edge entity view(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncDashboards(Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private ListenableFuture<Void> syncDashboards(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); ListenableFuture<TimePageData<DashboardInfo>> future = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
TimePageData<DashboardInfo> pageData; return Futures.transform(future, pageData -> {
do { try {
pageData = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (DashboardInfo dashboardInfo : pageData.getData()) {
for (DashboardInfo dashboardInfo : pageData.getData()) { Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId());
Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId()); DashboardUpdateMsg dashboardUpdateMsg =
DashboardUpdateMsg dashboardUpdateMsg = dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg(
dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg( UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, dashboard);
dashboard); EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setDashboardUpdateMsg(dashboardUpdateMsg)
.setDashboardUpdateMsg(dashboardUpdateMsg) .build();
.build(); outputStream.onNext(ResponseMsg.newBuilder()
outputStream.onNext(ResponseMsg.newBuilder() .setEntityUpdateMsg(entityUpdateMsg)
.setEntityUpdateMsg(entityUpdateMsg) .build());
.build()); pushedEntityIds.add(dashboard.getId());
pushedEntityIds.add(dashboard.getId()); }
} }
} catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on sync!", e);
} }
if (pageData.hasNext()) { return null;
pageLink = pageData.getNextPageLink(); }, ctx.getDbCallbackExecutor());
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on sync!", e); log.error("Exception during loading edge dashboard(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncUsers(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncUsers(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
try { try {
TimePageLink pageLink = new TimePageLink(100); TextPageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new TextPageLink(Integer.MAX_VALUE));
TimePageData<User> pageData; pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream);
do { if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) {
pageData = userService.findUsersByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new TextPageLink(Integer.MAX_VALUE));
if (!pageData.getData().isEmpty()) { pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream);
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); }
for (User user : pageData.getData()) {
UserUpdateMsg userUpdateMsg =
userUpdateMsgConstructor.constructUserUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
user);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserUpdateMsg(userUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(user.getId());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge user(s) on sync!", e); log.error("Exception during loading edge user(s) on sync!", e);
} }
} }
private void syncRelations(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void pushUsersToEdge(TextPageData<User> pageData, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
UserUpdateMsg userUpdateMsg =
userUpdateMsgConstructor.constructUserUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
user);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserUpdateMsg(userUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(user.getId());
}
}
}
private ListenableFuture<Void> syncRelations(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
if (!pushedEntityIds.isEmpty()) { if (!pushedEntityIds.isEmpty()) {
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>(); List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>();
for (EntityId entityId : pushedEntityIds) { for (EntityId entityId : pushedEntityIds) {
@ -326,7 +332,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
futures.add(syncRelations(edge, entityId, EntitySearchDirection.TO)); futures.add(syncRelations(edge, entityId, EntitySearchDirection.TO));
} }
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures); ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
Futures.transform(relationsListFuture, relationsList -> { return Futures.transform(relationsListFuture, relationsList -> {
try { try {
Set<EntityRelation> uniqueEntityRelations = new HashSet<>(); Set<EntityRelation> uniqueEntityRelations = new HashSet<>();
if (!relationsList.isEmpty()) { if (!relationsList.isEmpty()) {
@ -360,6 +366,8 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
} }
return null; return null;
}, ctx.getDbCallbackExecutor()); }, ctx.getDbCallbackExecutor());
} else {
return Futures.immediateFuture(null);
} }
} }
@ -369,7 +377,6 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
return relationService.findByQuery(edge.getTenantId(), query); return relationService.findByQuery(edge.getTenantId(), query);
} }
@Override @Override
public void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) { public void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) {
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {

View File

@ -18,14 +18,11 @@ package org.thingsboard.server.dao.user;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserCredentialsId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
public interface UserService { public interface UserService {
@ -69,10 +66,4 @@ public interface UserService {
void onUserLoginSuccessful(TenantId tenantId, UserId userId); void onUserLoginSuccessful(TenantId tenantId, UserId userId);
int onUserLoginIncorrectCredentials(TenantId tenantId, UserId userId); int onUserLoginIncorrectCredentials(TenantId tenantId, UserId userId);
User assignUserToEdge(TenantId tenantId, UserId userId, EdgeId edgeId);
User unassignUserFromEdge(TenantId tenantId, UserId userId, EdgeId edgeId);
ListenableFuture<TimePageData<User>> findUsersByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
} }

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,

View File

@ -15,31 +15,21 @@
*/ */
package org.thingsboard.server.dao.sql.user; package org.thingsboard.server.dao.sql.user;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.UserEntity; import org.thingsboard.server.dao.model.sql.UserEntity;
import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import org.thingsboard.server.dao.user.UserDao; import org.thingsboard.server.dao.user.UserDao;
import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.util.SqlDao;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -58,9 +48,6 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
@Autowired @Autowired
private UserRepository userRepository; private UserRepository userRepository;
@Autowired
private RelationDao relationDao;
@Override @Override
protected Class<UserEntity> getEntityClass() { protected Class<UserEntity> getEntityClass() {
return UserEntity.class; return UserEntity.class;
@ -102,17 +89,4 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
PageRequest.of(0, pageLink.getLimit()))); PageRequest.of(0, pageLink.getLimit())));
} }
@Override
public ListenableFuture<List<User>> findUsersByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
log.debug("Try to find users by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.USER, pageLink);
return Futures.transformAsync(relations, input -> {
List<ListenableFuture<User>> userFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
userFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
}
return Futures.successfulAsList(userFutures);
}, MoreExecutors.directExecutor());
}
} }

View File

@ -16,30 +16,18 @@
package org.thingsboard.server.dao.user; package org.thingsboard.server.dao.user;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.nosql.UserEntity; import org.thingsboard.server.dao.model.nosql.UserEntity;
import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.dao.util.NoSqlDao; import org.thingsboard.server.dao.util.NoSqlDao;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -52,9 +40,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
@NoSqlDao @NoSqlDao
public class CassandraUserDao extends CassandraAbstractSearchTextDao<UserEntity, User> implements UserDao { public class CassandraUserDao extends CassandraAbstractSearchTextDao<UserEntity, User> implements UserDao {
@Autowired
private RelationDao relationDao;
@Override @Override
protected Class<UserEntity> getColumnFamilyClass() { protected Class<UserEntity> getColumnFamilyClass() {
return UserEntity.class; return UserEntity.class;
@ -100,17 +85,4 @@ public class CassandraUserDao extends CassandraAbstractSearchTextDao<UserEntity,
log.trace("Found customer users [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", userEntities, tenantId, customerId, pageLink); log.trace("Found customer users [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", userEntities, tenantId, customerId, pageLink);
return DaoUtil.convertDataList(userEntities); return DaoUtil.convertDataList(userEntities);
} }
@Override
public ListenableFuture<List<User>> findUsersByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
log.debug("Try to find users by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.USER, pageLink);
return Futures.transformAsync(relations, input -> {
List<ListenableFuture<User>> userFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
userFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
}
return Futures.successfulAsList(userFutures);
}, MoreExecutors.directExecutor());
}
} }

View File

@ -15,11 +15,9 @@
*/ */
package org.thingsboard.server.dao.user; package org.thingsboard.server.dao.user;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.Dao;
import java.util.List; import java.util.List;
@ -42,7 +40,7 @@ public interface UserDao extends Dao<User> {
* @return the user entity * @return the user entity
*/ */
User findByEmail(TenantId tenantId, String email); User findByEmail(TenantId tenantId, String email);
/** /**
* Find tenant admin users by tenantId and page link. * Find tenant admin users by tenantId and page link.
* *
@ -51,7 +49,7 @@ public interface UserDao extends Dao<User> {
* @return the list of user entities * @return the list of user entities
*/ */
List<User> findTenantAdmins(UUID tenantId, TextPageLink pageLink); List<User> findTenantAdmins(UUID tenantId, TextPageLink pageLink);
/** /**
* Find customer users by tenantId, customerId and page link. * Find customer users by tenantId, customerId and page link.
* *
@ -61,15 +59,4 @@ public interface UserDao extends Dao<User> {
* @return the list of user entities * @return the list of user entities
*/ */
List<User> findCustomerUsers(UUID tenantId, UUID customerId, TextPageLink pageLink); List<User> findCustomerUsers(UUID tenantId, UUID customerId, TextPageLink pageLink);
/**
* Find users by tenantId, edgeId and page link.
*
* @param tenantId the tenantId
* @param edgeId the edgeId
* @param pageLink the page link
* @return the list of user objects
*/
ListenableFuture<List<User>> findUsersByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink);
} }

View File

@ -18,10 +18,7 @@ package org.thingsboard.server.dao.user;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -31,18 +28,12 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserCredentialsId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.customer.CustomerDao;
@ -55,11 +46,9 @@ import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.dao.tenant.TenantDao;
import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validatePageLink;
@ -327,57 +316,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
return failedLoginAttempts; return failedLoginAttempts;
} }
@Override
public User assignUserToEdge(TenantId tenantId, UserId userId, EdgeId edgeId) {
User user = findUserById(tenantId, userId);
Edge edge = edgeService.findEdgeById(tenantId, edgeId);
if (edge == null) {
throw new DataValidationException("Can't assign user to non-existent edge!");
}
if (!edge.getTenantId().getId().equals(user.getTenantId().getId())) {
throw new DataValidationException("Can't assign user to edge from different tenant!");
}
try {
createRelation(tenantId, new EntityRelation(edgeId, userId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to create user relation. Edge Id: [{}]", userId, edgeId);
throw new RuntimeException(e);
}
return user;
}
@Override
public User unassignUserFromEdge(TenantId tenantId, UserId userId, EdgeId edgeId) {
User user = findUserById(tenantId, userId);
Edge edge = edgeService.findEdgeById(tenantId, edgeId);
if (edge == null) {
throw new DataValidationException("Can't unassign user from non-existent edge!");
}
try {
deleteRelation(tenantId, new EntityRelation(edgeId, userId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to delete user relation. Edge Id: [{}]", userId, edgeId);
throw new RuntimeException(e);
}
return user;
}
@Override
public ListenableFuture<TimePageData<User>> findUsersByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
log.trace("Executing findUsersByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
ListenableFuture<List<User>> users = userDao.findUsersByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
return Futures.transform(users, new Function<List<User>, TimePageData<User>>() {
@Nullable
@Override
public TimePageData<User> apply(@Nullable List<User> users) {
return new TimePageData<>(users, pageLink);
}
}, MoreExecutors.directExecutor());
}
private int increaseFailedLoginAttempts(User user) { private int increaseFailedLoginAttempts(User user) {
JsonNode additionalInfo = user.getAdditionalInfo(); JsonNode additionalInfo = user.getAdditionalInfo();
if (!(additionalInfo instanceof ObjectNode)) { if (!(additionalInfo instanceof ObjectNode)) {