44 changed files with 1983 additions and 7 deletions
@ -0,0 +1,32 @@ |
|||||
|
-- |
||||
|
-- Copyright © 2016-2019 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. |
||||
|
-- |
||||
|
|
||||
|
CREATE TABLE IF NOT EXISTS thingsboard.edge ( |
||||
|
id timeuuid, |
||||
|
tenant_id timeuuid, |
||||
|
name text, |
||||
|
search_text text, |
||||
|
configuration text, |
||||
|
additional_info text, |
||||
|
PRIMARY KEY (id, tenant_id) |
||||
|
); |
||||
|
|
||||
|
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_search_text AS |
||||
|
SELECT * |
||||
|
from thingsboard.edge |
||||
|
WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL |
||||
|
PRIMARY KEY ( tenant_id, search_text, id ) |
||||
|
WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); |
||||
@ -0,0 +1,24 @@ |
|||||
|
-- |
||||
|
-- Copyright © 2016-2019 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. |
||||
|
-- |
||||
|
|
||||
|
CREATE TABLE IF NOT EXISTS edge ( |
||||
|
id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, |
||||
|
additional_info varchar, |
||||
|
configuration varchar(10000000), |
||||
|
name varchar(255), |
||||
|
search_text varchar(255), |
||||
|
tenant_id varchar(31) |
||||
|
); |
||||
@ -0,0 +1,163 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.controller; |
||||
|
|
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMethod; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
import org.springframework.web.bind.annotation.ResponseStatus; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
import org.thingsboard.server.common.data.audit.ActionType; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TextPageData; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
import org.thingsboard.server.service.security.permission.Operation; |
||||
|
import org.thingsboard.server.service.security.permission.Resource; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/api") |
||||
|
public class EdgeController extends BaseController { |
||||
|
|
||||
|
private static final String EDGE_ID = "edgeId"; |
||||
|
|
||||
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public Edge getEdgeById(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { |
||||
|
checkParameter(EDGE_ID, strEdgeId); |
||||
|
try { |
||||
|
EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); |
||||
|
return checkEdgeId(edgeId, Operation.READ); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/edge", method = RequestMethod.POST) |
||||
|
@ResponseBody |
||||
|
public Edge saveEdge(@RequestBody Edge edge) throws ThingsboardException { |
||||
|
try { |
||||
|
edge.setTenantId(getCurrentUser().getTenantId()); |
||||
|
boolean created = edge.getId() == null; |
||||
|
|
||||
|
Operation operation = created ? Operation.CREATE : Operation.WRITE; |
||||
|
|
||||
|
accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, |
||||
|
edge.getId(), edge); |
||||
|
|
||||
|
Edge result = checkNotNull(edgeService.saveEdge(edge)); |
||||
|
|
||||
|
logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null); |
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
logEntityAction(emptyId(EntityType.EDGE), edge, |
||||
|
null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/edges", params = {"limit"}, method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public TextPageData<Edge> getEdges( |
||||
|
@RequestParam int limit, |
||||
|
@RequestParam(required = false) String textSearch, |
||||
|
@RequestParam(required = false) String idOffset, |
||||
|
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
||||
|
try { |
||||
|
accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ); |
||||
|
TenantId tenantId = getCurrentUser().getTenantId(); |
||||
|
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
||||
|
return checkNotNull(edgeService.findTenantEdges(tenantId, pageLink)); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) |
||||
|
@ResponseStatus(value = HttpStatus.OK) |
||||
|
public void deleteEdge(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { |
||||
|
checkParameter(EDGE_ID, strEdgeId); |
||||
|
try { |
||||
|
EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); |
||||
|
Edge edge = checkEdgeId(edgeId, Operation.DELETE); |
||||
|
edgeService.deleteEdge(getTenantId(), edgeId); |
||||
|
|
||||
|
logEntityAction(edgeId, edge, |
||||
|
null, |
||||
|
ActionType.DELETED, null, strEdgeId); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
|
||||
|
logEntityAction(emptyId(EntityType.EDGE), |
||||
|
null, |
||||
|
null, |
||||
|
ActionType.DELETED, e, strEdgeId); |
||||
|
|
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public List<Edge> getEdgesByIds( |
||||
|
@RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { |
||||
|
checkArrayParameter("edgeIds", strEdgeIds); |
||||
|
try { |
||||
|
accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ); |
||||
|
SecurityUser user = getCurrentUser(); |
||||
|
TenantId tenantId = user.getTenantId(); |
||||
|
List<EdgeId> edgeIds = new ArrayList<>(); |
||||
|
for (String strEdgeId : strEdgeIds) { |
||||
|
edgeIds.add(new EdgeId(toUUID(strEdgeId))); |
||||
|
} |
||||
|
List<Edge> edges = checkNotNull(edgeService.findEdgesByIdsAsync(tenantId, edgeIds).get()); |
||||
|
return filterEdgesByReadPermission(edges); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private List<Edge> filterEdgesByReadPermission(List<Edge> edges) { |
||||
|
return edges.stream().filter(edge -> { |
||||
|
try { |
||||
|
accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ, edge.getId(), edge); |
||||
|
return true; |
||||
|
} catch (ThingsboardException e) { |
||||
|
return false; |
||||
|
} |
||||
|
}).collect(Collectors.toList()); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,206 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.controller; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||
|
import org.apache.commons.lang3.RandomStringUtils; |
||||
|
import org.junit.After; |
||||
|
import org.junit.Assert; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
import org.thingsboard.server.common.data.Tenant; |
||||
|
import org.thingsboard.server.common.data.User; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.page.TextPageData; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.common.data.security.Authority; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import static org.hamcrest.Matchers.containsString; |
||||
|
import static org.junit.Assert.assertEquals; |
||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||
|
|
||||
|
public abstract class BaseEdgeControllerTest extends AbstractControllerTest { |
||||
|
|
||||
|
private IdComparator<Edge> idComparator; |
||||
|
private Tenant savedTenant; |
||||
|
private User tenantAdmin; |
||||
|
|
||||
|
@Before |
||||
|
public void beforeTest() throws Exception { |
||||
|
loginSysAdmin(); |
||||
|
idComparator = new IdComparator<>(); |
||||
|
|
||||
|
savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); |
||||
|
Assert.assertNotNull(savedTenant); |
||||
|
|
||||
|
tenantAdmin = new User(); |
||||
|
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
||||
|
tenantAdmin.setTenantId(savedTenant.getId()); |
||||
|
tenantAdmin.setEmail("tenant2@thingsboard.org"); |
||||
|
tenantAdmin.setFirstName("Joe"); |
||||
|
tenantAdmin.setLastName("Downs"); |
||||
|
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void afterTest() throws Exception { |
||||
|
loginSysAdmin(); |
||||
|
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) |
||||
|
.andExpect(status().isOk()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFindEdgeById() throws Exception { |
||||
|
Edge savedEdge = getNewSavedEdge("Test edge"); |
||||
|
Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); |
||||
|
Assert.assertNotNull(foundEdge); |
||||
|
assertEquals(savedEdge, foundEdge); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSaveEdge() throws Exception { |
||||
|
Edge savedEdge = getNewSavedEdge("Test edge"); |
||||
|
|
||||
|
Assert.assertNotNull(savedEdge); |
||||
|
Assert.assertNotNull(savedEdge.getId()); |
||||
|
Assert.assertTrue(savedEdge.getCreatedTime() > 0); |
||||
|
assertEquals(savedTenant.getId(), savedEdge.getTenantId()); |
||||
|
|
||||
|
savedEdge.setName("New test edge"); |
||||
|
doPost("/api/edge", savedEdge, Edge.class); |
||||
|
Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); |
||||
|
|
||||
|
assertEquals(foundEdge.getName(), savedEdge.getName()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteEdge() throws Exception { |
||||
|
Edge edge = getNewSavedEdge("Test edge"); |
||||
|
Edge savedEdge = doPost("/api/edge", edge, Edge.class); |
||||
|
|
||||
|
doDelete("/api/edge/" + savedEdge.getId().getId().toString()) |
||||
|
.andExpect(status().isOk()); |
||||
|
|
||||
|
doGet("/api/edge/" + savedEdge.getId().getId().toString()) |
||||
|
.andExpect(status().isNotFound()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSaveEdgeWithEmptyName() throws Exception { |
||||
|
Edge edge = new Edge(); |
||||
|
doPost("/api/edge", edge) |
||||
|
.andExpect(status().isBadRequest()) |
||||
|
.andExpect(statusReason(containsString("Edge name should be specified!"))); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testGetEdges() throws Exception { |
||||
|
|
||||
|
List<Edge> edges = new ArrayList<>(); |
||||
|
for (int i = 0; i < 178; i++) { |
||||
|
edges.add(getNewSavedEdge("Test edge " + i)); |
||||
|
} |
||||
|
List<Edge> loadedEdges = loadListOf(new TextPageLink(23), "/api/edges?"); |
||||
|
|
||||
|
Collections.sort(edges, idComparator); |
||||
|
Collections.sort(loadedEdges, idComparator); |
||||
|
|
||||
|
assertEquals(edges, loadedEdges); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testGetEdgesByName() throws Exception { |
||||
|
String name1 = "Entity edge1"; |
||||
|
List<Edge> namesOfEdge1 = fillListOf(143, name1); |
||||
|
List<Edge> loadedNamesOfEdge1 = loadListOf(new TextPageLink(15, name1), "/api/edges?"); |
||||
|
Collections.sort(namesOfEdge1, idComparator); |
||||
|
Collections.sort(loadedNamesOfEdge1, idComparator); |
||||
|
assertEquals(namesOfEdge1, loadedNamesOfEdge1); |
||||
|
|
||||
|
String name2 = "Entity edge2"; |
||||
|
List<Edge> namesOfEdge2 = fillListOf(75, name2); |
||||
|
List<Edge> loadedNamesOfEdge2 = loadListOf(new TextPageLink(4, name2), "/api/edges?"); |
||||
|
Collections.sort(namesOfEdge2, idComparator); |
||||
|
Collections.sort(loadedNamesOfEdge2, idComparator); |
||||
|
assertEquals(namesOfEdge2, loadedNamesOfEdge2); |
||||
|
|
||||
|
for (Edge edge : loadedNamesOfEdge1) { |
||||
|
doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk()); |
||||
|
} |
||||
|
TextPageData<Edge> pageData = doGetTypedWithPageLink("/api/edges?", |
||||
|
new TypeReference<TextPageData<Edge>>() { |
||||
|
}, new TextPageLink(4, name1)); |
||||
|
Assert.assertFalse(pageData.hasNext()); |
||||
|
assertEquals(0, pageData.getData().size()); |
||||
|
|
||||
|
for (Edge edge : loadedNamesOfEdge2) { |
||||
|
doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk()); |
||||
|
} |
||||
|
pageData = doGetTypedWithPageLink("/api/edges?", new TypeReference<TextPageData<Edge>>() { |
||||
|
}, new TextPageLink(4, name2)); |
||||
|
Assert.assertFalse(pageData.hasNext()); |
||||
|
assertEquals(0, pageData.getData().size()); |
||||
|
} |
||||
|
|
||||
|
private Edge getNewSavedEdge(String name) throws Exception { |
||||
|
Edge edge = createEdge(name); |
||||
|
return doPost("/api/edge", edge, Edge.class); |
||||
|
} |
||||
|
|
||||
|
private Edge createEdge(String name) { |
||||
|
Edge edge = new Edge(); |
||||
|
edge.setTenantId(savedTenant.getId()); |
||||
|
edge.setName(name); |
||||
|
return edge; |
||||
|
} |
||||
|
|
||||
|
private Tenant getNewTenant(String title) { |
||||
|
Tenant tenant = new Tenant(); |
||||
|
tenant.setTitle(title); |
||||
|
return tenant; |
||||
|
} |
||||
|
|
||||
|
private List<Edge> fillListOf(int limit, String partOfName) throws Exception { |
||||
|
List<Edge> edgeNames = new ArrayList<>(); |
||||
|
for (int i = 0; i < limit; i++) { |
||||
|
String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); |
||||
|
fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); |
||||
|
Edge edge = getNewSavedEdge(fullName); |
||||
|
edgeNames.add(doPost("/api/edge", edge, Edge.class)); |
||||
|
} |
||||
|
return edgeNames; |
||||
|
} |
||||
|
|
||||
|
private List<Edge> loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception { |
||||
|
List<Edge> loadedItems = new ArrayList<>(); |
||||
|
TextPageData<Edge> pageData; |
||||
|
do { |
||||
|
pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<TextPageData<Edge>>() { |
||||
|
}, pageLink); |
||||
|
loadedItems.addAll(pageData.getData()); |
||||
|
if (pageData.hasNext()) { |
||||
|
pageLink = pageData.getNextPageLink(); |
||||
|
} |
||||
|
} while (pageData.hasNext()); |
||||
|
|
||||
|
return loadedItems; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.controller.nosql; |
||||
|
|
||||
|
import org.thingsboard.server.controller.BaseEdgeControllerTest; |
||||
|
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
||||
|
|
||||
|
@DaoNoSqlTest |
||||
|
public class EdgeControllerNoSqlTest extends BaseEdgeControllerTest { |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.controller.sql; |
||||
|
|
||||
|
import org.thingsboard.server.controller.BaseEdgeControllerTest; |
||||
|
import org.thingsboard.server.dao.service.DaoSqlTest; |
||||
|
|
||||
|
@DaoSqlTest |
||||
|
public class EdgeControllerSqlTest extends BaseEdgeControllerTest { |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.edge; |
||||
|
|
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TextPageData; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public interface EdgeService { |
||||
|
|
||||
|
Edge saveEdge(Edge edge); |
||||
|
|
||||
|
Edge findEdgeById(TenantId tenantId, EdgeId edgeId); |
||||
|
|
||||
|
ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId); |
||||
|
|
||||
|
ListenableFuture<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> edgeIds); |
||||
|
|
||||
|
List<Edge> findAllEdges(TenantId tenantId); |
||||
|
|
||||
|
TextPageData<Edge> findTenantEdges(TenantId tenantId, TextPageLink pageLink); |
||||
|
|
||||
|
void deleteEdge(TenantId tenantId, EdgeId edgeId); |
||||
|
|
||||
|
void deleteEdgesByTenantId(TenantId tenantId); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.common.data.edge; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import lombok.ToString; |
||||
|
import org.thingsboard.server.common.data.HasCustomerId; |
||||
|
import org.thingsboard.server.common.data.HasName; |
||||
|
import org.thingsboard.server.common.data.HasTenantId; |
||||
|
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
||||
|
import org.thingsboard.server.common.data.id.CustomerId; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
|
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@ToString |
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements HasName, HasTenantId, HasCustomerId { |
||||
|
|
||||
|
private static final long serialVersionUID = 4934987555236873728L; |
||||
|
|
||||
|
private TenantId tenantId; |
||||
|
private CustomerId customerId; |
||||
|
private String name; |
||||
|
private transient JsonNode configuration; |
||||
|
private transient JsonNode additionalInfo; |
||||
|
|
||||
|
public Edge() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public Edge(EdgeId id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public Edge(Edge edge) { |
||||
|
super(edge); |
||||
|
this.tenantId = edge.getTenantId(); |
||||
|
this.name = edge.getName(); |
||||
|
this.configuration = edge.getConfiguration(); |
||||
|
this.additionalInfo = edge.getAdditionalInfo(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getSearchText() { |
||||
|
return getName(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 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.common.data.id; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
|
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
public class EdgeId extends UUIDBased implements EntityId { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@JsonCreator |
||||
|
public EdgeId(@JsonProperty("id") UUID id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public static EdgeId fromString(String integrationId) { |
||||
|
return new EdgeId(UUID.fromString(integrationId)); |
||||
|
} |
||||
|
|
||||
|
@JsonIgnore |
||||
|
@Override |
||||
|
public EntityType getEntityType() { |
||||
|
return EntityType.EDGE; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,156 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.edge; |
||||
|
|
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.thingsboard.server.common.data.Tenant; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TextPageData; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.dao.entity.AbstractEntityService; |
||||
|
import org.thingsboard.server.dao.exception.DataValidationException; |
||||
|
import org.thingsboard.server.dao.service.DataValidator; |
||||
|
import org.thingsboard.server.dao.service.PaginatedRemover; |
||||
|
import org.thingsboard.server.dao.tenant.TenantDao; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.DaoUtil.toUUIDs; |
||||
|
import static org.thingsboard.server.dao.service.Validator.validateId; |
||||
|
import static org.thingsboard.server.dao.service.Validator.validateIds; |
||||
|
import static org.thingsboard.server.dao.service.Validator.validatePageLink; |
||||
|
|
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class BaseEdgeService extends AbstractEntityService implements EdgeService { |
||||
|
|
||||
|
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; |
||||
|
public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; |
||||
|
public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; |
||||
|
|
||||
|
@Autowired |
||||
|
private EdgeDao edgeDao; |
||||
|
|
||||
|
@Autowired |
||||
|
private TenantDao tenantDao; |
||||
|
|
||||
|
@Override |
||||
|
public Edge saveEdge(Edge edge) { |
||||
|
log.trace("Executing saveEdge [{}]", edge); |
||||
|
edgeValidator.validate(edge, Edge::getTenantId); |
||||
|
return edgeDao.save(edge.getTenantId(), edge); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) { |
||||
|
log.trace("Executing findEdgeById [{}]", edgeId); |
||||
|
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); |
||||
|
return edgeDao.findById(tenantId, edgeId.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) { |
||||
|
log.trace("Executing findEdgeByIdAsync [{}]", edgeId); |
||||
|
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); |
||||
|
return edgeDao.findByIdAsync(tenantId, edgeId.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> edgeIds) { |
||||
|
log.trace("Executing findEdgesByIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds); |
||||
|
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
||||
|
validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); |
||||
|
return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Edge> findAllEdges(TenantId tenantId) { |
||||
|
log.trace("Executing findAllEdges"); |
||||
|
return edgeDao.find(tenantId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TextPageData<Edge> findTenantEdges(TenantId tenantId, TextPageLink pageLink) { |
||||
|
log.trace("Executing findTenantEdges, tenantId [{}], pageLink [{}]", tenantId, pageLink); |
||||
|
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
||||
|
validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); |
||||
|
List<Edge> edges = edgeDao.findByTenantIdAndPageLink(tenantId.getId(), pageLink); |
||||
|
return new TextPageData<>(edges, pageLink); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void deleteEdge(TenantId tenantId, EdgeId edgeId) { |
||||
|
log.trace("Executing deleteEdge [{}]", edgeId); |
||||
|
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); |
||||
|
deleteEntityRelations(tenantId, edgeId); |
||||
|
edgeDao.removeById(tenantId, edgeId.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void deleteEdgesByTenantId(TenantId tenantId) { |
||||
|
log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId); |
||||
|
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
||||
|
tenantEdgesRemover.removeEntities(tenantId, tenantId); |
||||
|
} |
||||
|
|
||||
|
private DataValidator<Edge> edgeValidator = |
||||
|
new DataValidator<Edge>() { |
||||
|
|
||||
|
@Override |
||||
|
protected void validateCreate(TenantId tenantId, Edge edge) { |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void validateUpdate(TenantId tenantId, Edge edge) { |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void validateDataImpl(TenantId tenantId, Edge edge) { |
||||
|
if (StringUtils.isEmpty(edge.getName())) { |
||||
|
throw new DataValidationException("Edge name should be specified!"); |
||||
|
} |
||||
|
if (edge.getTenantId() == null || edge.getTenantId().isNullUid()) { |
||||
|
throw new DataValidationException("Edge should be assigned to tenant!"); |
||||
|
} else { |
||||
|
Tenant tenant = tenantDao.findById(tenantId, edge.getTenantId().getId()); |
||||
|
if (tenant == null) { |
||||
|
throw new DataValidationException("Edge is referencing to non-existent tenant!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
private PaginatedRemover<TenantId, Edge> tenantEdgesRemover = |
||||
|
new PaginatedRemover<TenantId, Edge>() { |
||||
|
|
||||
|
@Override |
||||
|
protected List<Edge> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { |
||||
|
return edgeDao.findByTenantIdAndPageLink(id.getId(), pageLink); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void removeEntity(TenantId tenantId, Edge entity) { |
||||
|
deleteEdge(tenantId, new EdgeId(entity.getId().getId())); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.edge; |
||||
|
|
||||
|
import com.datastax.driver.core.querybuilder.Select; |
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.dao.DaoUtil; |
||||
|
import org.thingsboard.server.dao.model.nosql.EdgeEntity; |
||||
|
import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; |
||||
|
import org.thingsboard.server.dao.util.NoSqlDao; |
||||
|
|
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
||||
|
import static com.datastax.driver.core.querybuilder.QueryBuilder.in; |
||||
|
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; |
||||
|
|
||||
|
@Component |
||||
|
@Slf4j |
||||
|
@NoSqlDao |
||||
|
public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity, Edge> implements EdgeDao { |
||||
|
|
||||
|
@Override |
||||
|
protected Class<EdgeEntity> getColumnFamilyClass() { |
||||
|
return EdgeEntity.class; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected String getColumnFamilyName() { |
||||
|
return EDGE_COLUMN_FAMILY_NAME; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) { |
||||
|
log.debug("Try to find edges by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
||||
|
List<EdgeEntity> edgeEntities = findPageWithTextSearch(new TenantId(tenantId), EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
||||
|
Collections.singletonList(eq(EDGE_TENANT_ID_PROPERTY, tenantId)), pageLink); |
||||
|
|
||||
|
log.trace("Found edges [{}] by tenantId [{}] and pageLink [{}]", edgeEntities, tenantId, pageLink); |
||||
|
return DaoUtil.convertDataList(edgeEntities); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds) { |
||||
|
log.debug("Try to find edges by tenantId [{}] and edge Ids [{}]", tenantId, edgeIds); |
||||
|
Select select = select().from(getColumnFamilyName()); |
||||
|
Select.Where query = select.where(); |
||||
|
query.and(eq(EDGE_TENANT_ID_PROPERTY, tenantId)); |
||||
|
query.and(in(ID_PROPERTY, edgeIds)); |
||||
|
return findListByStatementAsync(new TenantId(tenantId), query); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.edge; |
||||
|
|
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.dao.Dao; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
/** |
||||
|
* The Interface EdgeDao. |
||||
|
* |
||||
|
*/ |
||||
|
public interface EdgeDao extends Dao<Edge> { |
||||
|
|
||||
|
/** |
||||
|
* Find edges by tenantId and page link. |
||||
|
* |
||||
|
* @param tenantId the tenantId |
||||
|
* @param pageLink the page link |
||||
|
* @return the list of edge objects |
||||
|
*/ |
||||
|
List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink); |
||||
|
|
||||
|
/** |
||||
|
* Find edges by tenantId and edge Ids. |
||||
|
* |
||||
|
* @param tenantId the tenantId |
||||
|
* @param edgeIds the edge Ids |
||||
|
* @return the list of edge objects |
||||
|
*/ |
||||
|
ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds); |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.model.nosql; |
||||
|
|
||||
|
import com.datastax.driver.core.utils.UUIDs; |
||||
|
import com.datastax.driver.mapping.annotations.ClusteringColumn; |
||||
|
import com.datastax.driver.mapping.annotations.Column; |
||||
|
import com.datastax.driver.mapping.annotations.PartitionKey; |
||||
|
import com.datastax.driver.mapping.annotations.Table; |
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.model.SearchTextEntity; |
||||
|
import org.thingsboard.server.dao.model.type.JsonCodec; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ADDITIONAL_INFO_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; |
||||
|
|
||||
|
@Data |
||||
|
@Table(name = EDGE_COLUMN_FAMILY_NAME) |
||||
|
public class EdgeEntity implements SearchTextEntity<Edge> { |
||||
|
|
||||
|
@PartitionKey |
||||
|
@Column(name = ID_PROPERTY) |
||||
|
private UUID id; |
||||
|
|
||||
|
@ClusteringColumn |
||||
|
@Column(name = EDGE_TENANT_ID_PROPERTY) |
||||
|
private UUID tenantId; |
||||
|
|
||||
|
@Column(name = EDGE_NAME_PROPERTY) |
||||
|
private String name; |
||||
|
|
||||
|
@Column(name = SEARCH_TEXT_PROPERTY) |
||||
|
private String searchText; |
||||
|
|
||||
|
@Column(name = EDGE_CONFIGURATION_PROPERTY, codec = JsonCodec.class) |
||||
|
private JsonNode configuration; |
||||
|
|
||||
|
@Column(name = EDGE_ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
||||
|
private JsonNode additionalInfo; |
||||
|
|
||||
|
public EdgeEntity() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public EdgeEntity(Edge edge) { |
||||
|
if (edge.getId() != null) { |
||||
|
this.id = edge.getId().getId(); |
||||
|
} |
||||
|
if (edge.getTenantId() != null) { |
||||
|
this.tenantId = edge.getTenantId().getId(); |
||||
|
} |
||||
|
this.name = edge.getName(); |
||||
|
this.configuration = edge.getConfiguration(); |
||||
|
this.additionalInfo = edge.getAdditionalInfo(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getSearchTextSource() { |
||||
|
return getName(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Edge toData() { |
||||
|
Edge edge = new Edge(new EdgeId(id)); |
||||
|
edge.setCreatedTime(UUIDs.unixTimestamp(id)); |
||||
|
if (tenantId != null) { |
||||
|
edge.setTenantId(new TenantId(tenantId)); |
||||
|
} |
||||
|
edge.setName(name); |
||||
|
edge.setConfiguration(configuration); |
||||
|
edge.setAdditionalInfo(additionalInfo); |
||||
|
return edge; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,108 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.model.sql; |
||||
|
|
||||
|
import com.datastax.driver.core.utils.UUIDs; |
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.hibernate.annotations.Type; |
||||
|
import org.hibernate.annotations.TypeDef; |
||||
|
import org.thingsboard.server.common.data.UUIDConverter; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.id.EdgeId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.model.BaseSqlEntity; |
||||
|
import org.thingsboard.server.dao.model.ModelConstants; |
||||
|
import org.thingsboard.server.dao.model.SearchTextEntity; |
||||
|
import org.thingsboard.server.dao.util.mapping.JsonStringType; |
||||
|
|
||||
|
import javax.persistence.Column; |
||||
|
import javax.persistence.Entity; |
||||
|
import javax.persistence.Table; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@Entity |
||||
|
@TypeDef(name = "json", typeClass = JsonStringType.class) |
||||
|
@Table(name = EDGE_COLUMN_FAMILY_NAME) |
||||
|
public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<Edge> { |
||||
|
|
||||
|
@Column(name = EDGE_TENANT_ID_PROPERTY) |
||||
|
private String tenantId; |
||||
|
|
||||
|
@Column(name = EDGE_NAME_PROPERTY) |
||||
|
private String name; |
||||
|
|
||||
|
@Column(name = SEARCH_TEXT_PROPERTY) |
||||
|
private String searchText; |
||||
|
|
||||
|
@Type(type = "json") |
||||
|
@Column(name = ModelConstants.EDGE_CONFIGURATION_PROPERTY) |
||||
|
private JsonNode configuration; |
||||
|
|
||||
|
@Type(type = "json") |
||||
|
@Column(name = ModelConstants.EDGE_ADDITIONAL_INFO_PROPERTY) |
||||
|
private JsonNode additionalInfo; |
||||
|
|
||||
|
public EdgeEntity() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public EdgeEntity(Edge edge) { |
||||
|
if (edge.getId() != null) { |
||||
|
this.setId(edge.getId().getId()); |
||||
|
} |
||||
|
if (edge.getTenantId() != null) { |
||||
|
this.tenantId = UUIDConverter.fromTimeUUID(edge.getTenantId().getId()); |
||||
|
} |
||||
|
this.name = edge.getName(); |
||||
|
this.configuration = edge.getConfiguration(); |
||||
|
this.additionalInfo = edge.getAdditionalInfo(); |
||||
|
} |
||||
|
|
||||
|
public String getSearchText() { |
||||
|
return searchText; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getSearchTextSource() { |
||||
|
return name; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setSearchText(String searchText) { |
||||
|
this.searchText = searchText; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Edge toData() { |
||||
|
Edge edge = new Edge(new EdgeId(UUIDConverter.fromString(id))); |
||||
|
edge.setCreatedTime(UUIDs.unixTimestamp(UUIDConverter.fromString(id))); |
||||
|
if (tenantId != null) { |
||||
|
edge.setTenantId(new TenantId(UUIDConverter.fromString(tenantId))); |
||||
|
} |
||||
|
edge.setName(name); |
||||
|
edge.setConfiguration(configuration); |
||||
|
edge.setAdditionalInfo(additionalInfo); |
||||
|
return edge; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.sql.edge; |
||||
|
|
||||
|
import org.springframework.data.domain.Pageable; |
||||
|
import org.springframework.data.jpa.repository.Query; |
||||
|
import org.springframework.data.repository.CrudRepository; |
||||
|
import org.springframework.data.repository.query.Param; |
||||
|
import org.thingsboard.server.dao.model.sql.EdgeEntity; |
||||
|
import org.thingsboard.server.dao.util.SqlDao; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@SqlDao |
||||
|
public interface EdgeRepository extends CrudRepository<EdgeEntity, String> { |
||||
|
|
||||
|
@Query("SELECT a FROM EdgeEntity a WHERE a.tenantId = :tenantId " + |
||||
|
"AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + |
||||
|
"AND a.id > :idOffset ORDER BY a.id") |
||||
|
List<EdgeEntity> findByTenantIdAndPageLink(@Param("tenantId") String tenantId, |
||||
|
@Param("textSearch") String textSearch, |
||||
|
@Param("idOffset") String idOffset, |
||||
|
Pageable pageable); |
||||
|
|
||||
|
List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.sql.edge; |
||||
|
|
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.data.domain.PageRequest; |
||||
|
import org.springframework.data.repository.CrudRepository; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.data.UUIDConverter; |
||||
|
import org.thingsboard.server.common.data.edge.Edge; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.dao.DaoUtil; |
||||
|
import org.thingsboard.server.dao.edge.EdgeDao; |
||||
|
import org.thingsboard.server.dao.model.sql.EdgeEntity; |
||||
|
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; |
||||
|
import org.thingsboard.server.dao.util.SqlDao; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Objects; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; |
||||
|
import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs; |
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; |
||||
|
|
||||
|
@Component |
||||
|
@SqlDao |
||||
|
public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> implements EdgeDao { |
||||
|
|
||||
|
@Autowired |
||||
|
private EdgeRepository edgeRepository; |
||||
|
|
||||
|
@Override |
||||
|
public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) { |
||||
|
return DaoUtil.convertDataList(edgeRepository |
||||
|
.findByTenantIdAndPageLink( |
||||
|
fromTimeUUID(tenantId), |
||||
|
Objects.toString(pageLink.getTextSearch(), ""), |
||||
|
pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), |
||||
|
new PageRequest(0, pageLink.getLimit()))); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds) { |
||||
|
return service.submit(() -> DaoUtil.convertDataList(edgeRepository.findEdgesByTenantIdAndIdIn(UUIDConverter.fromTimeUUID(tenantId), fromTimeUUIDs(edgeIds)))); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Class<EdgeEntity> getEntityClass() { |
||||
|
return EdgeEntity.class; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected CrudRepository<EdgeEntity, String> getCrudRepository() { |
||||
|
return edgeRepository; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,111 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 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. |
||||
|
*/ |
||||
|
export default angular.module('thingsboard.api.edge', []) |
||||
|
.factory('edgeService', EdgeService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EdgeService($http, $q) { |
||||
|
|
||||
|
var service = { |
||||
|
getEdges: getEdges, |
||||
|
getEdgesByIds: getEdgesByIds, |
||||
|
getEdge: getEdge, |
||||
|
deleteEdge: deleteEdge, |
||||
|
saveEdge: saveEdge |
||||
|
}; |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function getEdges(pageLink, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/edges?limit=' + pageLink.limit; |
||||
|
if (angular.isDefined(pageLink.textSearch)) { |
||||
|
url += '&textSearch=' + pageLink.textSearch; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.idOffset)) { |
||||
|
url += '&idOffset=' + pageLink.idOffset; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.textOffset)) { |
||||
|
url += '&textOffset=' + pageLink.textOffset; |
||||
|
} |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEdgesByIds(edgeIds, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var ids = ''; |
||||
|
for (var i=0;i<edgeIds.length;i++) { |
||||
|
if (i>0) { |
||||
|
ids += ','; |
||||
|
} |
||||
|
ids += edgeIds[i]; |
||||
|
} |
||||
|
var url = '/api/edges?edgeIds=' + ids; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
var entities = response.data; |
||||
|
entities.sort(function (entity1, entity2) { |
||||
|
var id1 = entity1.id.id; |
||||
|
var id2 = entity2.id.id; |
||||
|
var index1 = edgeIds.indexOf(id1); |
||||
|
var index2 = edgeIds.indexOf(id2); |
||||
|
return index1 - index2; |
||||
|
}); |
||||
|
deferred.resolve(entities); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEdge(edgeId, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/edge/' + edgeId; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function saveEdge(edge) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/edge'; |
||||
|
$http.post(url, edge).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteEdge(edgeId) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/edge/' + edgeId; |
||||
|
$http.delete(url).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 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. |
||||
|
|
||||
|
--> |
||||
|
<md-dialog aria-label="{{ 'edge.add' | translate }}" tb-help="'edges'" help-container-id="help-container" style="width: 600px;"> |
||||
|
<form name="theForm" ng-submit="vm.add()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>edge.add</h2> |
||||
|
<span flex></span> |
||||
|
<div id="help-container"></div> |
||||
|
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
||||
|
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
||||
|
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
||||
|
<md-dialog-content> |
||||
|
<div class="md-dialog-content"> |
||||
|
<tb-edge edge="vm.item" is-edit="true" is-create="true" the-form="theForm"></tb-edge> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> |
||||
|
{{ 'action.add' | translate }} |
||||
|
</md-button> |
||||
|
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> |
||||
|
</md-dialog-actions> |
||||
|
</form> |
||||
|
</md-dialog> |
||||
|
|
||||
@ -0,0 +1,21 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 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. |
||||
|
|
||||
|
--> |
||||
|
<div flex layout="column"> |
||||
|
<div flex style="text-transform: uppercase;">{{ vm.types.edgeType[vm.item.type].name | translate }}</div> |
||||
|
<div class="tb-card-description">{{vm.item.additionalInfo.description}}</div> |
||||
|
</div> |
||||
@ -0,0 +1,49 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 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. |
||||
|
|
||||
|
--> |
||||
|
<md-button ng-click="onExportEdge({event: $event})" |
||||
|
ng-show="!isEdit" |
||||
|
class="md-raised md-primary">{{ 'edge.export' | translate }}</md-button> |
||||
|
<md-button ng-click="onDeleteEdge({event: $event})" |
||||
|
ng-if="'edge' | hasGenericPermission:'delete'" |
||||
|
ng-show="!isEdit" class="md-raised md-primary">{{ 'edge.delete' | translate }}</md-button> |
||||
|
|
||||
|
<div layout="row"> |
||||
|
<md-button ngclipboard data-clipboard-action="copy" |
||||
|
ngclipboard-success="onEdgeIdCopied(e)" |
||||
|
data-clipboard-text="{{edge.id.id}}" ng-show="!isEdit" |
||||
|
class="md-raised"> |
||||
|
<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon> |
||||
|
<span translate>edge.copyId</span> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
|
||||
|
<md-content class="md-padding" layout="column"> |
||||
|
<fieldset ng-disabled="$root.loading || !isEdit"> |
||||
|
<md-input-container class="md-block"> |
||||
|
<label translate>edge.name</label> |
||||
|
<input required name="name" ng-model="edge.name"> |
||||
|
<div ng-messages="theForm.name.$error"> |
||||
|
<div translate ng-message="required">edge.name-required</div> |
||||
|
</div> |
||||
|
</md-input-container> |
||||
|
<md-input-container class="md-block"> |
||||
|
<label translate>edge.description</label> |
||||
|
<textarea ng-model="edge.additionalInfo.description" rows="2"></textarea> |
||||
|
</md-input-container> |
||||
|
</fieldset> |
||||
|
</md-content> |
||||
@ -0,0 +1,166 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import addEdgeTemplate from './add-edge.tpl.html'; |
||||
|
import edgeCard from './edge-card.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export function EdgeCardController(types) { |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.types = types; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export function EdgeController($rootScope, userService, edgeService, $state, $stateParams, |
||||
|
$document, $mdDialog, $q, $translate, types, securityTypes, userPermissionsService) { |
||||
|
|
||||
|
var edgeActionsList = []; |
||||
|
|
||||
|
var edgeGroupActionsList = []; |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.types = types; |
||||
|
|
||||
|
vm.edgeGridConfig = { |
||||
|
|
||||
|
resource: securityTypes.resource.edge, |
||||
|
|
||||
|
deleteItemTitleFunc: deleteEdgeTitle, |
||||
|
deleteItemContentFunc: deleteEdgeText, |
||||
|
deleteItemsTitleFunc: deleteEdgesTitle, |
||||
|
deleteItemsActionTitleFunc: deleteEdgesActionTitle, |
||||
|
deleteItemsContentFunc: deleteEdgesText, |
||||
|
|
||||
|
saveItemFunc: saveEdge, |
||||
|
|
||||
|
getItemTitleFunc: getEdgeTitle, |
||||
|
|
||||
|
itemCardController: 'EdgeCardController', |
||||
|
itemCardTemplateUrl: edgeCard, |
||||
|
parentCtl: vm, |
||||
|
|
||||
|
actionsList: edgeActionsList, |
||||
|
groupActionsList: edgeGroupActionsList, |
||||
|
|
||||
|
onGridInited: gridInited, |
||||
|
|
||||
|
addItemTemplateUrl: addEdgeTemplate, |
||||
|
|
||||
|
addItemText: function() { return $translate.instant('edge.add-edge-text') }, |
||||
|
noItemsText: function() { return $translate.instant('edge.no-edges-text') }, |
||||
|
itemDetailsText: function() { return $translate.instant('edge.edge-details') } |
||||
|
}; |
||||
|
|
||||
|
if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { |
||||
|
vm.edgeGridConfig.items = $stateParams.items; |
||||
|
} |
||||
|
|
||||
|
if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) { |
||||
|
vm.edgeGridConfig.topIndex = $stateParams.topIndex; |
||||
|
} |
||||
|
|
||||
|
initController(); |
||||
|
|
||||
|
function initController() { |
||||
|
var fetchEdgesFunction = function (pageLink, edgeType) { |
||||
|
return edgeService.getEdges(pageLink, true, edgeType); |
||||
|
}; |
||||
|
var deleteEdgeFunction = function (edgeId) { |
||||
|
return edgeService.deleteEdge(edgeId); |
||||
|
}; |
||||
|
var refreshEdgesParamsFunction = function() { |
||||
|
return {"topIndex": vm.topIndex}; |
||||
|
}; |
||||
|
|
||||
|
edgeActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, item) { |
||||
|
vm.grid.deleteItem($event, item); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.delete') }, |
||||
|
details: function() { return $translate.instant('edge.delete') }, |
||||
|
icon: "delete", |
||||
|
isEnabled: function() { |
||||
|
return userPermissionsService.hasGenericPermission(securityTypes.resource.edge, securityTypes.operation.delete); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
edgeGroupActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event) { |
||||
|
vm.grid.deleteItems($event); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('edge.delete-edges') }, |
||||
|
details: deleteEdgesActionTitle, |
||||
|
icon: "delete" |
||||
|
} |
||||
|
); |
||||
|
vm.edgeGridConfig.refreshParamsFunc = refreshEdgesParamsFunction; |
||||
|
vm.edgeGridConfig.fetchItemsFunc = fetchEdgesFunction; |
||||
|
vm.edgeGridConfig.deleteItemFunc = deleteEdgeFunction; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
function deleteEdgeTitle(edge) { |
||||
|
return $translate.instant('edge.delete-edge-title', {edgeName: edge.name}); |
||||
|
} |
||||
|
|
||||
|
function deleteEdgeText() { |
||||
|
return $translate.instant('edge.delete-edge-text'); |
||||
|
} |
||||
|
|
||||
|
function deleteEdgesTitle(selectedCount) { |
||||
|
return $translate.instant('edge.delete-edges-title', {count: selectedCount}, 'messageformat'); |
||||
|
} |
||||
|
|
||||
|
function deleteEdgesActionTitle(selectedCount) { |
||||
|
return $translate.instant('edge.delete-edges-action-title', {count: selectedCount}, 'messageformat'); |
||||
|
} |
||||
|
|
||||
|
function deleteEdgesText () { |
||||
|
return $translate.instant('edge.delete-edges-text'); |
||||
|
} |
||||
|
|
||||
|
function gridInited(grid) { |
||||
|
vm.grid = grid; |
||||
|
} |
||||
|
|
||||
|
function getEdgeTitle(edge) { |
||||
|
return edge ? edge.name : ''; |
||||
|
} |
||||
|
|
||||
|
function saveEdge(edge) { |
||||
|
var deferred = $q.defer(); |
||||
|
edgeService.saveEdge(edge).then( |
||||
|
function success(savedEdge) { |
||||
|
$rootScope.$broadcast('edgeSaved'); |
||||
|
deferred.resolve(savedEdge); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import edgeFieldsetTemplate from './edge-fieldset.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, toast, types) { |
||||
|
var linker = function (scope, element) { |
||||
|
var template = $templateCache.get(edgeFieldsetTemplate); |
||||
|
element.html(template); |
||||
|
|
||||
|
scope.types = types; |
||||
|
|
||||
|
scope.onEdgeIdCopied = function() { |
||||
|
toast.showSuccess($translate.instant('edge.idCopiedMessage'), 750, angular.element(element).parent().parent(), 'bottom left'); |
||||
|
}; |
||||
|
|
||||
|
$compile(element.contents())(scope); |
||||
|
|
||||
|
}; |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
link: linker, |
||||
|
scope: { |
||||
|
edge: '=', |
||||
|
isEdit: '=', |
||||
|
theForm: '=', |
||||
|
isCreate: '<', |
||||
|
onExportEdge: '&', |
||||
|
onDeleteEdge: '&' |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import edgesTemplate from './edges.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export default function EdgeRoutes($stateProvider) { |
||||
|
|
||||
|
$stateProvider |
||||
|
.state('home.edges', { |
||||
|
url: '/edges', |
||||
|
params: {'topIndex': 0}, |
||||
|
module: 'private', |
||||
|
auth: ['TENANT_ADMIN'], |
||||
|
views: { |
||||
|
"content@home": { |
||||
|
templateUrl: edgesTemplate, |
||||
|
controllerAs: 'vm', |
||||
|
controller: 'EdgeController' |
||||
|
} |
||||
|
}, |
||||
|
data: { |
||||
|
searchEnabled: true, |
||||
|
pageTitle: 'edge.edges' |
||||
|
}, |
||||
|
ncyBreadcrumb: { |
||||
|
label: '{"icon": "transform", "label": "edge.edges"}' |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 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. |
||||
|
|
||||
|
--> |
||||
|
<tb-grid grid-configuration="vm.edgeGridConfig"> |
||||
|
<details-buttons tb-help="'edges'" help-container-id="help-container"> |
||||
|
<div id="help-container"></div> |
||||
|
</details-buttons> |
||||
|
<md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}" |
||||
|
id="tabs" md-border-bottom flex class="tb-absolute-fill"> |
||||
|
<md-tab label="{{ 'edge.details' | translate }}"> |
||||
|
<tb-edge edge="vm.grid.operatingItem()" |
||||
|
is-edit="vm.grid.detailsConfig.isDetailsEditMode" |
||||
|
the-form="vm.grid.detailsForm" |
||||
|
on-delete-edge="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-edge> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && ('edge' | hasGenericPermission:'readAttributes')" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> |
||||
|
<tb-attribute-table flex |
||||
|
readonly="!('edge' | hasGenericPermission:'writeAttributes')" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.edge}}" |
||||
|
entity-name="vm.grid.operatingItem().name" |
||||
|
default-attribute-scope="{{vm.types.attributesScope.server.value}}"> |
||||
|
</tb-attribute-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && ('edge' | hasGenericPermission:'readTelemetry')" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}"> |
||||
|
<tb-attribute-table flex |
||||
|
readonly="!('edge' | hasGenericPermission:'writeTelemetry')" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.edge}}" |
||||
|
entity-name="vm.grid.operatingItem().name" |
||||
|
default-attribute-scope="{{vm.types.latestTelemetry.value}}" |
||||
|
disable-attribute-scope-selection="true"> |
||||
|
</tb-attribute-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && ('alarm' | hasGenericPermission:'read')" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}"> |
||||
|
<tb-alarm-table flex entity-type="vm.types.entityType.edge" |
||||
|
entity-id="vm.grid.operatingItem().id.id"> |
||||
|
</tb-alarm-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.events' | translate }}"> |
||||
|
<tb-event-table flex entity-type="vm.types.entityType.edge" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
tenant-id="vm.grid.operatingItem().tenantId.id" |
||||
|
default-event-type="{{vm.types.eventType.error.value}}"> |
||||
|
</tb-event-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> |
||||
|
<tb-relation-table flex |
||||
|
readonly="!('edge' | hasGenericPermission:'write')" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.edge}}"> |
||||
|
</tb-relation-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && ('auditLog' | hasGenericPermission:'read')" md-on-select="vm.grid.triggerResize()" label="{{ 'audit-log.audit-logs' | translate }}"> |
||||
|
<tb-audit-log-table flex entity-type="vm.types.entityType.edge" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
audit-log-mode="{{vm.types.auditLogMode.entity}}"> |
||||
|
</tb-audit-log-table> |
||||
|
</md-tab> |
||||
|
</md-tabs> |
||||
|
</tb-grid> |
||||
@ -0,0 +1,25 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 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 EdgeRoutes from './edge.routes'; |
||||
|
import {EdgeController, EdgeCardController} from './edge.controller'; |
||||
|
import EdgeDirective from './edge.directive'; |
||||
|
|
||||
|
export default angular.module('thingsboard.edge', []) |
||||
|
.config(EdgeRoutes) |
||||
|
.controller('EdgeController', EdgeController) |
||||
|
.controller('EdgeCardController', EdgeCardController) |
||||
|
.directive('tbEdge', EdgeDirective) |
||||
|
.name; |
||||
Loading…
Reference in new issue