Commit 063a1093e0179ae7840d0f8e3bce3afdeeb08dad
1 parent
b90f0ea0
Ability to assign dashboards to multiple customers - DAO Layer.
Showing
32 changed files
with
830 additions
and
420 deletions
... | ... | @@ -87,3 +87,26 @@ CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id_partitions ( |
87 | 87 | PRIMARY KEY (( tenant_id ), partition) |
88 | 88 | ) WITH CLUSTERING ORDER BY ( partition ASC ) |
89 | 89 | AND compaction = { 'class' : 'LeveledCompactionStrategy' }; |
90 | + | |
91 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.dashboard_by_tenant_and_search_text; | |
92 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.dashboard_by_customer_and_search_text; | |
93 | + | |
94 | +DROP TABLE IF EXISTS thingsboard.dashboard; | |
95 | + | |
96 | +CREATE TABLE IF NOT EXISTS thingsboard.dashboard ( | |
97 | + id timeuuid, | |
98 | + tenant_id timeuuid, | |
99 | + title text, | |
100 | + search_text text, | |
101 | + assigned_customers text, | |
102 | + configuration text, | |
103 | + PRIMARY KEY (id, tenant_id) | |
104 | +); | |
105 | + | |
106 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.dashboard_by_tenant_and_search_text AS | |
107 | + SELECT * | |
108 | + from thingsboard.dashboard | |
109 | + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL | |
110 | + PRIMARY KEY ( tenant_id, search_text, id ) | |
111 | + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); | |
112 | + | ... | ... |
... | ... | @@ -29,3 +29,13 @@ CREATE TABLE IF NOT EXISTS audit_log ( |
29 | 29 | action_failure_details varchar(1000000) |
30 | 30 | ); |
31 | 31 | |
32 | +DROP TABLE IF EXISTS dashboard; | |
33 | + | |
34 | +CREATE TABLE IF NOT EXISTS dashboard ( | |
35 | + id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, | |
36 | + configuration varchar(10000000), | |
37 | + assigned_customers varchar(1000000), | |
38 | + search_text varchar(255), | |
39 | + tenant_id varchar(31), | |
40 | + title varchar(255) | |
41 | +); | ... | ... |
... | ... | @@ -423,7 +423,7 @@ public abstract class BaseController { |
423 | 423 | try { |
424 | 424 | validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
425 | 425 | Dashboard dashboard = dashboardService.findDashboardById(dashboardId); |
426 | - checkDashboard(dashboard, true); | |
426 | + checkDashboard(dashboard); | |
427 | 427 | return dashboard; |
428 | 428 | } catch (Exception e) { |
429 | 429 | throw handleException(e, false); |
... | ... | @@ -435,27 +435,23 @@ public abstract class BaseController { |
435 | 435 | validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
436 | 436 | DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(dashboardId); |
437 | 437 | SecurityUser authUser = getCurrentUser(); |
438 | - checkDashboard(dashboardInfo, authUser.getAuthority() != Authority.SYS_ADMIN); | |
438 | + checkDashboard(dashboardInfo); | |
439 | 439 | return dashboardInfo; |
440 | 440 | } catch (Exception e) { |
441 | 441 | throw handleException(e, false); |
442 | 442 | } |
443 | 443 | } |
444 | 444 | |
445 | - private void checkDashboard(DashboardInfo dashboard, boolean checkCustomerId) throws ThingsboardException { | |
445 | + private void checkDashboard(DashboardInfo dashboard) throws ThingsboardException { | |
446 | 446 | checkNotNull(dashboard); |
447 | 447 | checkTenantId(dashboard.getTenantId()); |
448 | 448 | SecurityUser authUser = getCurrentUser(); |
449 | 449 | if (authUser.getAuthority() == Authority.CUSTOMER_USER) { |
450 | - if (dashboard.getCustomerId() == null || dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
450 | + if (dashboard.getAssignedCustomers() == null || !dashboard.getAssignedCustomers().containsKey(authUser.getCustomerId().toString())) { | |
451 | 451 | throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, |
452 | 452 | ThingsboardErrorCode.PERMISSION_DENIED); |
453 | 453 | } |
454 | 454 | } |
455 | - if (checkCustomerId && | |
456 | - dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
457 | - checkCustomerId(dashboard.getCustomerId()); | |
458 | - } | |
459 | 455 | } |
460 | 456 | |
461 | 457 | ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { | ... | ... |
... | ... | @@ -28,6 +28,8 @@ import org.thingsboard.server.common.data.id.DashboardId; |
28 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 29 | import org.thingsboard.server.common.data.page.TextPageData; |
30 | 30 | import org.thingsboard.server.common.data.page.TextPageLink; |
31 | +import org.thingsboard.server.common.data.page.TimePageData; | |
32 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
31 | 33 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
32 | 34 | import org.thingsboard.server.dao.model.ModelConstants; |
33 | 35 | import org.thingsboard.server.exception.ThingsboardException; |
... | ... | @@ -80,7 +82,7 @@ public class DashboardController extends BaseController { |
80 | 82 | Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); |
81 | 83 | |
82 | 84 | logEntityAction(savedDashboard.getId(), savedDashboard, |
83 | - savedDashboard.getCustomerId(), | |
85 | + null, | |
84 | 86 | dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
85 | 87 | |
86 | 88 | return savedDashboard; |
... | ... | @@ -103,7 +105,7 @@ public class DashboardController extends BaseController { |
103 | 105 | dashboardService.deleteDashboard(dashboardId); |
104 | 106 | |
105 | 107 | logEntityAction(dashboardId, dashboard, |
106 | - dashboard.getCustomerId(), | |
108 | + null, | |
107 | 109 | ActionType.DELETED, null, strDashboardId); |
108 | 110 | |
109 | 111 | } catch (Exception e) { |
... | ... | @@ -134,7 +136,7 @@ public class DashboardController extends BaseController { |
134 | 136 | Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId)); |
135 | 137 | |
136 | 138 | logEntityAction(dashboardId, savedDashboard, |
137 | - savedDashboard.getCustomerId(), | |
139 | + customerId, | |
138 | 140 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName()); |
139 | 141 | |
140 | 142 | |
... | ... | @@ -150,23 +152,22 @@ public class DashboardController extends BaseController { |
150 | 152 | } |
151 | 153 | |
152 | 154 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
153 | - @RequestMapping(value = "/customer/dashboard/{dashboardId}", method = RequestMethod.DELETE) | |
155 | + @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) | |
154 | 156 | @ResponseBody |
155 | - public Dashboard unassignDashboardFromCustomer(@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | |
157 | + public Dashboard unassignDashboardFromCustomer(@PathVariable("customerId") String strCustomerId, | |
158 | + @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | |
159 | + checkParameter("customerId", strCustomerId); | |
156 | 160 | checkParameter(DASHBOARD_ID, strDashboardId); |
157 | 161 | try { |
162 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
163 | + Customer customer = checkCustomerId(customerId); | |
158 | 164 | DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
159 | 165 | Dashboard dashboard = checkDashboardId(dashboardId); |
160 | - if (dashboard.getCustomerId() == null || dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
161 | - throw new IncorrectParameterException("Dashboard isn't assigned to any customer!"); | |
162 | - } | |
163 | - | |
164 | - Customer customer = checkCustomerId(dashboard.getCustomerId()); | |
165 | 166 | |
166 | - Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId)); | |
167 | + Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId)); | |
167 | 168 | |
168 | 169 | logEntityAction(dashboardId, dashboard, |
169 | - dashboard.getCustomerId(), | |
170 | + customerId, | |
170 | 171 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName()); |
171 | 172 | |
172 | 173 | return savedDashboard; |
... | ... | @@ -192,7 +193,7 @@ public class DashboardController extends BaseController { |
192 | 193 | Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, publicCustomer.getId())); |
193 | 194 | |
194 | 195 | logEntityAction(dashboardId, savedDashboard, |
195 | - savedDashboard.getCustomerId(), | |
196 | + publicCustomer.getId(), | |
196 | 197 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, publicCustomer.getId().toString(), publicCustomer.getName()); |
197 | 198 | |
198 | 199 | return savedDashboard; |
... | ... | @@ -206,6 +207,33 @@ public class DashboardController extends BaseController { |
206 | 207 | } |
207 | 208 | } |
208 | 209 | |
210 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
211 | + @RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.DELETE) | |
212 | + @ResponseBody | |
213 | + public Dashboard unassignDashboardFromPublicCustomer(@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | |
214 | + checkParameter(DASHBOARD_ID, strDashboardId); | |
215 | + try { | |
216 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
217 | + Dashboard dashboard = checkDashboardId(dashboardId); | |
218 | + Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId()); | |
219 | + | |
220 | + Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, publicCustomer.getId())); | |
221 | + | |
222 | + logEntityAction(dashboardId, dashboard, | |
223 | + publicCustomer.getId(), | |
224 | + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, publicCustomer.getId().toString(), publicCustomer.getName()); | |
225 | + | |
226 | + return savedDashboard; | |
227 | + } catch (Exception e) { | |
228 | + | |
229 | + logEntityAction(emptyId(EntityType.DASHBOARD), null, | |
230 | + null, | |
231 | + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDashboardId); | |
232 | + | |
233 | + throw handleException(e); | |
234 | + } | |
235 | + } | |
236 | + | |
209 | 237 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
210 | 238 | @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = { "limit" }, method = RequestMethod.GET) |
211 | 239 | @ResponseBody |
... | ... | @@ -245,19 +273,20 @@ public class DashboardController extends BaseController { |
245 | 273 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
246 | 274 | @RequestMapping(value = "/customer/{customerId}/dashboards", params = { "limit" }, method = RequestMethod.GET) |
247 | 275 | @ResponseBody |
248 | - public TextPageData<DashboardInfo> getCustomerDashboards( | |
276 | + public TimePageData<DashboardInfo> getCustomerDashboards( | |
249 | 277 | @PathVariable("customerId") String strCustomerId, |
250 | 278 | @RequestParam int limit, |
251 | - @RequestParam(required = false) String textSearch, | |
252 | - @RequestParam(required = false) String idOffset, | |
253 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
279 | + @RequestParam(required = false) Long startTime, | |
280 | + @RequestParam(required = false) Long endTime, | |
281 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
282 | + @RequestParam(required = false) String offset) throws ThingsboardException { | |
254 | 283 | checkParameter("customerId", strCustomerId); |
255 | 284 | try { |
256 | 285 | TenantId tenantId = getCurrentUser().getTenantId(); |
257 | 286 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
258 | 287 | checkCustomerId(customerId); |
259 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
260 | - return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
288 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
289 | + return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).get()); | |
261 | 290 | } catch (Exception e) { |
262 | 291 | throw handleException(e); |
263 | 292 | } | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Profile; |
24 | 24 | import org.springframework.stereotype.Service; |
25 | 25 | import org.thingsboard.server.dao.cassandra.CassandraCluster; |
26 | 26 | import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; |
27 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
27 | 28 | import org.thingsboard.server.dao.util.NoSqlDao; |
28 | 29 | import org.thingsboard.server.service.install.cql.CQLStatementsParser; |
29 | 30 | import org.thingsboard.server.service.install.cql.CassandraDbHelper; |
... | ... | @@ -33,6 +34,8 @@ import java.nio.file.Path; |
33 | 34 | import java.nio.file.Paths; |
34 | 35 | import java.util.List; |
35 | 36 | |
37 | +import static org.thingsboard.server.service.install.DatabaseHelper.*; | |
38 | + | |
36 | 39 | @Service |
37 | 40 | @NoSqlDao |
38 | 41 | @Profile("install") |
... | ... | @@ -40,12 +43,6 @@ import java.util.List; |
40 | 43 | public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { |
41 | 44 | |
42 | 45 | private static final String SCHEMA_UPDATE_CQL = "schema_update.cql"; |
43 | - public static final String DEVICE = "device"; | |
44 | - public static final String TENANT_ID = "tenant_id"; | |
45 | - public static final String CUSTOMER_ID = "customer_id"; | |
46 | - public static final String SEARCH_TEXT = "search_text"; | |
47 | - public static final String ADDITIONAL_INFO = "additional_info"; | |
48 | - public static final String ASSET = "asset"; | |
49 | 46 | |
50 | 47 | @Value("${install.data_dir}") |
51 | 48 | private String dataDir; |
... | ... | @@ -56,6 +53,9 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { |
56 | 53 | @Autowired |
57 | 54 | private CassandraInstallCluster installCluster; |
58 | 55 | |
56 | + @Autowired | |
57 | + private DashboardService dashboardService; | |
58 | + | |
59 | 59 | @Override |
60 | 60 | public void upgradeDatabase(String fromVersion) throws Exception { |
61 | 61 | |
... | ... | @@ -160,10 +160,32 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { |
160 | 160 | case "1.3.0": |
161 | 161 | break; |
162 | 162 | case "1.3.1": |
163 | + | |
164 | + cluster.getSession(); | |
165 | + | |
166 | + ks = cluster.getCluster().getMetadata().getKeyspace(cluster.getKeyspaceName()); | |
167 | + | |
168 | + log.info("Dumping dashboards ..."); | |
169 | + Path dashboardsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), DASHBOARD, | |
170 | + new String[]{ID, TENANT_ID, CUSTOMER_ID, TITLE, SEARCH_TEXT, ASSIGNED_CUSTOMERS, CONFIGURATION}, | |
171 | + new String[]{"", "", "", "", "", "", ""}, | |
172 | + "tb-dashboards"); | |
173 | + log.info("Dashboards dumped."); | |
174 | + | |
175 | + | |
163 | 176 | log.info("Updating schema ..."); |
164 | 177 | schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.4.0", SCHEMA_UPDATE_CQL); |
165 | 178 | loadCql(schemaUpdateFile); |
166 | 179 | log.info("Schema updated."); |
180 | + | |
181 | + log.info("Restoring dashboards ..."); | |
182 | + if (dashboardsDump != null) { | |
183 | + CassandraDbHelper.loadCf(ks, cluster.getSession(), DASHBOARD, | |
184 | + new String[]{ID, TENANT_ID, TITLE, SEARCH_TEXT, CONFIGURATION}, dashboardsDump); | |
185 | + DatabaseHelper.upgradeTo40_assignDashboards(dashboardsDump, dashboardService, false); | |
186 | + Files.deleteIfExists(dashboardsDump); | |
187 | + } | |
188 | + log.info("Dashboards restored."); | |
167 | 189 | break; |
168 | 190 | default: |
169 | 191 | throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.install; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.apache.commons.csv.CSVFormat; | |
21 | +import org.apache.commons.csv.CSVParser; | |
22 | +import org.apache.commons.lang3.StringUtils; | |
23 | +import com.fasterxml.jackson.databind.JsonNode; | |
24 | +import org.thingsboard.server.common.data.UUIDConverter; | |
25 | +import org.thingsboard.server.common.data.id.CustomerId; | |
26 | +import org.thingsboard.server.common.data.id.DashboardId; | |
27 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
28 | + | |
29 | +import java.io.IOException; | |
30 | +import java.nio.file.Files; | |
31 | +import java.nio.file.Path; | |
32 | +import java.util.*; | |
33 | + | |
34 | +/** | |
35 | + * Created by igor on 2/27/18. | |
36 | + */ | |
37 | +@Slf4j | |
38 | +public class DatabaseHelper { | |
39 | + | |
40 | + public static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N"); | |
41 | + | |
42 | + public static final String DEVICE = "device"; | |
43 | + public static final String TENANT_ID = "tenant_id"; | |
44 | + public static final String CUSTOMER_ID = "customer_id"; | |
45 | + public static final String SEARCH_TEXT = "search_text"; | |
46 | + public static final String ADDITIONAL_INFO = "additional_info"; | |
47 | + public static final String ASSET = "asset"; | |
48 | + public static final String DASHBOARD = "dashboard"; | |
49 | + public static final String ID = "id"; | |
50 | + public static final String TITLE = "title"; | |
51 | + public static final String ASSIGNED_CUSTOMERS = "assigned_customers"; | |
52 | + public static final String CONFIGURATION = "configuration"; | |
53 | + | |
54 | + public static final ObjectMapper objectMapper = new ObjectMapper(); | |
55 | + | |
56 | + public static void upgradeTo40_assignDashboards(Path dashboardsDump, DashboardService dashboardService, boolean sql) throws Exception { | |
57 | + String[] columns = new String[]{ID, TENANT_ID, CUSTOMER_ID, TITLE, SEARCH_TEXT, ASSIGNED_CUSTOMERS, CONFIGURATION}; | |
58 | + try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(dashboardsDump), CSV_DUMP_FORMAT.withHeader(columns))) { | |
59 | + csvParser.forEach(record -> { | |
60 | + String customerIdString = record.get(CUSTOMER_ID); | |
61 | + String assignedCustomersString = record.get(ASSIGNED_CUSTOMERS); | |
62 | + DashboardId dashboardId = new DashboardId(toUUID(record.get(ID), sql)); | |
63 | + List<CustomerId> customerIds = new ArrayList<>(); | |
64 | + if (!StringUtils.isEmpty(assignedCustomersString)) { | |
65 | + try { | |
66 | + JsonNode assignedCustomersJson = objectMapper.readTree(assignedCustomersString); | |
67 | + Map<String,String> assignedCustomers = objectMapper.treeToValue(assignedCustomersJson, HashMap.class); | |
68 | + assignedCustomers.forEach((strCustomerId, title) -> { | |
69 | + customerIds.add(new CustomerId(UUID.fromString(strCustomerId))); | |
70 | + }); | |
71 | + } catch (IOException e) { | |
72 | + log.error("Unable to parse assigned customers field", e); | |
73 | + } | |
74 | + } | |
75 | + if (!StringUtils.isEmpty(customerIdString)) { | |
76 | + customerIds.add(new CustomerId(toUUID(customerIdString, sql))); | |
77 | + } | |
78 | + for (CustomerId customerId : customerIds) { | |
79 | + dashboardService.assignDashboardToCustomer(dashboardId, customerId); | |
80 | + } | |
81 | + }); | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + private static UUID toUUID(String src, boolean sql) { | |
86 | + if (sql) { | |
87 | + return UUIDConverter.fromString(src); | |
88 | + } else { | |
89 | + return UUID.fromString(src); | |
90 | + } | |
91 | + } | |
92 | + | |
93 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -339,8 +339,10 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
339 | 339 | JsonNode dashboardJson = objectMapper.readTree(path.toFile()); |
340 | 340 | Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class); |
341 | 341 | dashboard.setTenantId(tenantId); |
342 | - dashboard.setCustomerId(customerId); | |
343 | - dashboardService.saveDashboard(dashboard); | |
342 | + Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); | |
343 | + if (customerId != null && !customerId.isNullUid()) { | |
344 | + dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId); | |
345 | + } | |
344 | 346 | } catch (Exception e) { |
345 | 347 | log.error("Unable to load dashboard from json: [{}]", path.toString()); |
346 | 348 | throw new RuntimeException("Unable to load dashboard from json", e); | ... | ... |
... | ... | @@ -17,18 +17,26 @@ |
17 | 17 | package org.thingsboard.server.service.install; |
18 | 18 | |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
20 | 21 | import org.springframework.beans.factory.annotation.Value; |
21 | 22 | import org.springframework.context.annotation.Profile; |
22 | 23 | import org.springframework.stereotype.Service; |
24 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
23 | 25 | import org.thingsboard.server.dao.util.SqlDao; |
26 | +import org.thingsboard.server.service.install.cql.CassandraDbHelper; | |
27 | +import org.thingsboard.server.service.install.sql.SqlDbHelper; | |
24 | 28 | |
25 | 29 | import java.nio.charset.Charset; |
26 | 30 | import java.nio.file.Files; |
27 | 31 | import java.nio.file.Path; |
28 | 32 | import java.nio.file.Paths; |
29 | 33 | import java.sql.Connection; |
34 | +import java.sql.DatabaseMetaData; | |
30 | 35 | import java.sql.DriverManager; |
31 | 36 | |
37 | +import static org.thingsboard.server.service.install.DatabaseHelper.*; | |
38 | +import static org.thingsboard.server.service.install.DatabaseHelper.CONFIGURATION; | |
39 | + | |
32 | 40 | @Service |
33 | 41 | @Profile("install") |
34 | 42 | @Slf4j |
... | ... | @@ -49,6 +57,9 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
49 | 57 | @Value("${spring.datasource.password}") |
50 | 58 | private String dbPassword; |
51 | 59 | |
60 | + @Autowired | |
61 | + private DashboardService dashboardService; | |
62 | + | |
52 | 63 | @Override |
53 | 64 | public void upgradeDatabase(String fromVersion) throws Exception { |
54 | 65 | switch (fromVersion) { |
... | ... | @@ -62,13 +73,30 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
62 | 73 | log.info("Schema updated."); |
63 | 74 | break; |
64 | 75 | case "1.3.1": |
65 | - log.info("Updating schema ..."); | |
66 | - schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.4.0", SCHEMA_UPDATE_SQL); | |
67 | 76 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
77 | + | |
78 | + log.info("Dumping dashboards ..."); | |
79 | + Path dashboardsDump = SqlDbHelper.dumpTableIfExists(conn, DASHBOARD, | |
80 | + new String[]{ID, TENANT_ID, CUSTOMER_ID, TITLE, SEARCH_TEXT, ASSIGNED_CUSTOMERS, CONFIGURATION}, | |
81 | + new String[]{"", "", "", "", "", "", ""}, | |
82 | + "tb-dashboards"); | |
83 | + log.info("Dashboards dumped."); | |
84 | + | |
85 | + log.info("Updating schema ..."); | |
86 | + schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.4.0", SCHEMA_UPDATE_SQL); | |
68 | 87 | String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8")); |
69 | 88 | conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script |
89 | + log.info("Schema updated."); | |
90 | + | |
91 | + log.info("Restoring dashboards ..."); | |
92 | + if (dashboardsDump != null) { | |
93 | + SqlDbHelper.loadTable(conn, DASHBOARD, | |
94 | + new String[]{ID, TENANT_ID, TITLE, SEARCH_TEXT, CONFIGURATION}, dashboardsDump); | |
95 | + DatabaseHelper.upgradeTo40_assignDashboards(dashboardsDump, dashboardService, true); | |
96 | + Files.deleteIfExists(dashboardsDump); | |
97 | + } | |
98 | + log.info("Dashboards restored."); | |
70 | 99 | } |
71 | - log.info("Schema updated."); | |
72 | 100 | break; |
73 | 101 | default: |
74 | 102 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); | ... | ... |
... | ... | @@ -17,7 +17,6 @@ |
17 | 17 | package org.thingsboard.server.service.install.cql; |
18 | 18 | |
19 | 19 | import com.datastax.driver.core.*; |
20 | -import org.apache.commons.csv.CSVFormat; | |
21 | 20 | import org.apache.commons.csv.CSVParser; |
22 | 21 | import org.apache.commons.csv.CSVPrinter; |
23 | 22 | import org.apache.commons.csv.CSVRecord; |
... | ... | @@ -28,9 +27,9 @@ import java.nio.file.Path; |
28 | 27 | import java.nio.file.StandardCopyOption; |
29 | 28 | import java.util.*; |
30 | 29 | |
31 | -public class CassandraDbHelper { | |
30 | +import static org.thingsboard.server.service.install.DatabaseHelper.CSV_DUMP_FORMAT; | |
32 | 31 | |
33 | - private static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N"); | |
32 | +public class CassandraDbHelper { | |
34 | 33 | |
35 | 34 | public static Path dumpCfIfExists(KeyspaceMetadata ks, Session session, String cfName, |
36 | 35 | String[] columns, String[] defaultValues, String dumpPrefix) throws Exception { | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.install.sql; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.apache.commons.csv.CSVParser; | |
20 | +import org.apache.commons.csv.CSVPrinter; | |
21 | +import org.apache.commons.csv.CSVRecord; | |
22 | + | |
23 | +import java.nio.file.Files; | |
24 | +import java.nio.file.Path; | |
25 | +import java.sql.*; | |
26 | +import java.util.ArrayList; | |
27 | +import java.util.HashMap; | |
28 | +import java.util.List; | |
29 | +import java.util.Map; | |
30 | + | |
31 | +import static org.thingsboard.server.service.install.DatabaseHelper.CSV_DUMP_FORMAT; | |
32 | + | |
33 | +/** | |
34 | + * Created by igor on 2/27/18. | |
35 | + */ | |
36 | +@Slf4j | |
37 | +public class SqlDbHelper { | |
38 | + | |
39 | + public static Path dumpTableIfExists(Connection conn, String tableName, | |
40 | + String[] columns, String[] defaultValues, String dumpPrefix) throws Exception { | |
41 | + | |
42 | + DatabaseMetaData metaData = conn.getMetaData(); | |
43 | + ResultSet res = metaData.getTables(null, null, tableName, | |
44 | + new String[] {"TABLE"}); | |
45 | + if (res.next()) { | |
46 | + res.close(); | |
47 | + Path dumpFile = Files.createTempFile(dumpPrefix, null); | |
48 | + Files.deleteIfExists(dumpFile); | |
49 | + try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(dumpFile), CSV_DUMP_FORMAT)) { | |
50 | + try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM " + tableName)) { | |
51 | + try (ResultSet tableRes = stmt.executeQuery()) { | |
52 | + ResultSetMetaData resMetaData = tableRes.getMetaData(); | |
53 | + Map<String, Integer> columnIndexMap = new HashMap<>(); | |
54 | + for (int i = 0; i < resMetaData.getColumnCount(); i++) { | |
55 | + String columnName = resMetaData.getColumnName(i); | |
56 | + columnIndexMap.put(columnName, i); | |
57 | + } | |
58 | + while(tableRes.next()) { | |
59 | + dumpRow(tableRes, columnIndexMap, columns, defaultValues, csvPrinter); | |
60 | + } | |
61 | + } | |
62 | + } | |
63 | + } | |
64 | + return dumpFile; | |
65 | + } else { | |
66 | + return null; | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + public static void loadTable(Connection conn, String tableName, String[] columns, Path sourceFile) throws Exception { | |
71 | + PreparedStatement prepared = conn.prepareStatement(createInsertStatement(tableName, columns)); | |
72 | + prepared.getParameterMetaData(); | |
73 | + try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(sourceFile), CSV_DUMP_FORMAT.withHeader(columns))) { | |
74 | + csvParser.forEach(record -> { | |
75 | + try { | |
76 | + for (int i=0;i<columns.length;i++) { | |
77 | + setColumnValue(i, columns[i], record, prepared); | |
78 | + } | |
79 | + prepared.execute(); | |
80 | + } catch (SQLException e) { | |
81 | + log.error("Unable to load table record!", e); | |
82 | + } | |
83 | + }); | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + private static void dumpRow(ResultSet res, Map<String, Integer> columnIndexMap, String[] columns, | |
88 | + String[] defaultValues, CSVPrinter csvPrinter) throws Exception { | |
89 | + List<String> record = new ArrayList<>(); | |
90 | + for (int i=0;i<columns.length;i++) { | |
91 | + String column = columns[i]; | |
92 | + String defaultValue; | |
93 | + if (defaultValues != null && i < defaultValues.length) { | |
94 | + defaultValue = defaultValues[i]; | |
95 | + } else { | |
96 | + defaultValue = ""; | |
97 | + } | |
98 | + record.add(getColumnValue(column, defaultValue, columnIndexMap, res)); | |
99 | + } | |
100 | + csvPrinter.printRecord(record); | |
101 | + } | |
102 | + | |
103 | + private static String getColumnValue(String column, String defaultValue, Map<String, Integer> columnIndexMap, ResultSet res) { | |
104 | + int index = columnIndexMap.containsKey(column) ? columnIndexMap.get(column) : -1; | |
105 | + if (index > -1) { | |
106 | + String str; | |
107 | + try { | |
108 | + Object obj = res.getObject(index); | |
109 | + if (obj == null) { | |
110 | + str = ""; | |
111 | + } else { | |
112 | + str = obj.toString(); | |
113 | + } | |
114 | + } catch (Exception e) { | |
115 | + str = ""; | |
116 | + } | |
117 | + return str; | |
118 | + } else { | |
119 | + return defaultValue; | |
120 | + } | |
121 | + } | |
122 | + | |
123 | + private static void setColumnValue(int index, String column, | |
124 | + CSVRecord record, PreparedStatement preparedStatement) throws SQLException { | |
125 | + String value = record.get(column); | |
126 | + int type = preparedStatement.getParameterMetaData().getParameterType(index + 1); | |
127 | + preparedStatement.setObject(index + 1, value, type); | |
128 | + } | |
129 | + | |
130 | + private static String createInsertStatement(String tableName, String[] columns) { | |
131 | + StringBuilder insertStatementBuilder = new StringBuilder(); | |
132 | + insertStatementBuilder.append("INSERT INTO ").append(tableName).append(" ("); | |
133 | + for (String column : columns) { | |
134 | + insertStatementBuilder.append(column).append(","); | |
135 | + } | |
136 | + insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1); | |
137 | + insertStatementBuilder.append(") VALUES ("); | |
138 | + for (String column : columns) { | |
139 | + insertStatementBuilder.append("?").append(","); | |
140 | + } | |
141 | + insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1); | |
142 | + insertStatementBuilder.append(")"); | |
143 | + return insertStatementBuilder.toString(); | |
144 | + } | |
145 | + | |
146 | +} | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import static org.hamcrest.Matchers.containsString; |
19 | 19 | import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
20 | 20 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
21 | 21 | |
22 | +import java.sql.Time; | |
22 | 23 | import java.util.ArrayList; |
23 | 24 | import java.util.Collections; |
24 | 25 | import java.util.List; |
... | ... | @@ -29,6 +30,8 @@ import org.thingsboard.server.common.data.*; |
29 | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
30 | 31 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 32 | import org.thingsboard.server.common.data.page.TextPageLink; |
33 | +import org.thingsboard.server.common.data.page.TimePageData; | |
34 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
32 | 35 | import org.thingsboard.server.common.data.security.Authority; |
33 | 36 | import org.thingsboard.server.dao.model.ModelConstants; |
34 | 37 | import org.junit.After; |
... | ... | @@ -82,8 +85,6 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
82 | 85 | Assert.assertNotNull(savedDashboard.getId()); |
83 | 86 | Assert.assertTrue(savedDashboard.getCreatedTime() > 0); |
84 | 87 | Assert.assertEquals(savedTenant.getId(), savedDashboard.getTenantId()); |
85 | - Assert.assertNotNull(savedDashboard.getCustomerId()); | |
86 | - Assert.assertEquals(NULL_UUID, savedDashboard.getCustomerId().getId()); | |
87 | 88 | Assert.assertEquals(dashboard.getTitle(), savedDashboard.getTitle()); |
88 | 89 | |
89 | 90 | savedDashboard.setTitle("My new dashboard"); |
... | ... | @@ -136,17 +137,20 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
136 | 137 | |
137 | 138 | Dashboard assignedDashboard = doPost("/api/customer/" + savedCustomer.getId().getId().toString() |
138 | 139 | + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); |
139 | - Assert.assertEquals(savedCustomer.getId(), assignedDashboard.getCustomerId()); | |
140 | - | |
140 | + | |
141 | + Assert.assertTrue(assignedDashboard.getAssignedCustomers().containsKey(savedCustomer.getId().toString())); | |
142 | + | |
141 | 143 | Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); |
142 | - Assert.assertEquals(savedCustomer.getId(), foundDashboard.getCustomerId()); | |
144 | + Assert.assertTrue(foundDashboard.getAssignedCustomers().containsKey(savedCustomer.getId().toString())); | |
143 | 145 | |
144 | 146 | Dashboard unassignedDashboard = |
145 | - doDelete("/api/customer/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); | |
146 | - Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDashboard.getCustomerId().getId()); | |
147 | - | |
147 | + doDelete("/api/customer/"+savedCustomer.getId().getId().toString()+"/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); | |
148 | + | |
149 | + Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty()); | |
150 | + | |
148 | 151 | foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); |
149 | - Assert.assertEquals(ModelConstants.NULL_UUID, foundDashboard.getCustomerId().getId()); | |
152 | + | |
153 | + Assert.assertTrue(foundDashboard.getAssignedCustomers() == null || foundDashboard.getAssignedCustomers().isEmpty()); | |
150 | 154 | } |
151 | 155 | |
152 | 156 | @Test |
... | ... | @@ -320,11 +324,11 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
320 | 324 | } |
321 | 325 | |
322 | 326 | List<DashboardInfo> loadedDashboards = new ArrayList<>(); |
323 | - TextPageLink pageLink = new TextPageLink(21); | |
324 | - TextPageData<DashboardInfo> pageData = null; | |
327 | + TimePageLink pageLink = new TimePageLink(21); | |
328 | + TimePageData<DashboardInfo> pageData = null; | |
325 | 329 | do { |
326 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
327 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
330 | + pageData = doGetTypedWithTimePageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
331 | + new TypeReference<TimePageData<DashboardInfo>>(){}, pageLink); | |
328 | 332 | loadedDashboards.addAll(pageData.getData()); |
329 | 333 | if (pageData.hasNext()) { |
330 | 334 | pageLink = pageData.getNextPageLink(); |
... | ... | @@ -336,93 +340,5 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
336 | 340 | |
337 | 341 | Assert.assertEquals(dashboards, loadedDashboards); |
338 | 342 | } |
339 | - | |
340 | - @Test | |
341 | - public void testFindCustomerDashboardsByTitle() throws Exception { | |
342 | - Customer customer = new Customer(); | |
343 | - customer.setTitle("Test customer"); | |
344 | - customer = doPost("/api/customer", customer, Customer.class); | |
345 | - CustomerId customerId = customer.getId(); | |
346 | - | |
347 | - String title1 = "Dashboard title 1"; | |
348 | - List<DashboardInfo> dashboardsTitle1 = new ArrayList<>(); | |
349 | - for (int i=0;i<125;i++) { | |
350 | - Dashboard dashboard = new Dashboard(); | |
351 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); | |
352 | - String title = title1+suffix; | |
353 | - title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); | |
354 | - dashboard.setTitle(title); | |
355 | - dashboard = doPost("/api/dashboard", dashboard, Dashboard.class); | |
356 | - dashboardsTitle1.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString() | |
357 | - + "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class))); | |
358 | - } | |
359 | - String title2 = "Dashboard title 2"; | |
360 | - List<DashboardInfo> dashboardsTitle2 = new ArrayList<>(); | |
361 | - for (int i=0;i<143;i++) { | |
362 | - Dashboard dashboard = new Dashboard(); | |
363 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); | |
364 | - String title = title2+suffix; | |
365 | - title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); | |
366 | - dashboard.setTitle(title); | |
367 | - dashboard = doPost("/api/dashboard", dashboard, Dashboard.class); | |
368 | - dashboardsTitle2.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString() | |
369 | - + "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class))); | |
370 | - } | |
371 | - | |
372 | - List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>(); | |
373 | - TextPageLink pageLink = new TextPageLink(18, title1); | |
374 | - TextPageData<DashboardInfo> pageData = null; | |
375 | - do { | |
376 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
377 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
378 | - loadedDashboardsTitle1.addAll(pageData.getData()); | |
379 | - if (pageData.hasNext()) { | |
380 | - pageLink = pageData.getNextPageLink(); | |
381 | - } | |
382 | - } while (pageData.hasNext()); | |
383 | - | |
384 | - Collections.sort(dashboardsTitle1, idComparator); | |
385 | - Collections.sort(loadedDashboardsTitle1, idComparator); | |
386 | - | |
387 | - Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1); | |
388 | - | |
389 | - List<DashboardInfo> loadedDashboardsTitle2 = new ArrayList<>(); | |
390 | - pageLink = new TextPageLink(7, title2); | |
391 | - do { | |
392 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
393 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
394 | - loadedDashboardsTitle2.addAll(pageData.getData()); | |
395 | - if (pageData.hasNext()) { | |
396 | - pageLink = pageData.getNextPageLink(); | |
397 | - } | |
398 | - } while (pageData.hasNext()); | |
399 | - | |
400 | - Collections.sort(dashboardsTitle2, idComparator); | |
401 | - Collections.sort(loadedDashboardsTitle2, idComparator); | |
402 | - | |
403 | - Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2); | |
404 | - | |
405 | - for (DashboardInfo dashboard : loadedDashboardsTitle1) { | |
406 | - doDelete("/api/customer/dashboard/" + dashboard.getId().getId().toString()) | |
407 | - .andExpect(status().isOk()); | |
408 | - } | |
409 | - | |
410 | - pageLink = new TextPageLink(5, title1); | |
411 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
412 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
413 | - Assert.assertFalse(pageData.hasNext()); | |
414 | - Assert.assertEquals(0, pageData.getData().size()); | |
415 | - | |
416 | - for (DashboardInfo dashboard : loadedDashboardsTitle2) { | |
417 | - doDelete("/api/customer/dashboard/" + dashboard.getId().getId().toString()) | |
418 | - .andExpect(status().isOk()); | |
419 | - } | |
420 | - | |
421 | - pageLink = new TextPageLink(9, title2); | |
422 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
423 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
424 | - Assert.assertFalse(pageData.hasNext()); | |
425 | - Assert.assertEquals(0, pageData.getData().size()); | |
426 | - } | |
427 | 343 | |
428 | 344 | } | ... | ... |
... | ... | @@ -79,8 +79,6 @@ public class Dashboard extends DashboardInfo { |
79 | 79 | StringBuilder builder = new StringBuilder(); |
80 | 80 | builder.append("Dashboard [tenantId="); |
81 | 81 | builder.append(getTenantId()); |
82 | - builder.append(", customerId="); | |
83 | - builder.append(getCustomerId()); | |
84 | 82 | builder.append(", title="); |
85 | 83 | builder.append(getTitle()); |
86 | 84 | builder.append(", configuration="); | ... | ... |
... | ... | @@ -20,11 +20,16 @@ import org.thingsboard.server.common.data.id.CustomerId; |
20 | 20 | import org.thingsboard.server.common.data.id.DashboardId; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | |
23 | +import java.util.HashMap; | |
24 | +import java.util.List; | |
25 | +import java.util.Map; | |
26 | +import java.util.Set; | |
27 | + | |
23 | 28 | public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName { |
24 | 29 | |
25 | 30 | private TenantId tenantId; |
26 | - private CustomerId customerId; | |
27 | 31 | private String title; |
32 | + private Map<String, String> assignedCustomers; | |
28 | 33 | |
29 | 34 | public DashboardInfo() { |
30 | 35 | super(); |
... | ... | @@ -37,8 +42,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
37 | 42 | public DashboardInfo(DashboardInfo dashboardInfo) { |
38 | 43 | super(dashboardInfo); |
39 | 44 | this.tenantId = dashboardInfo.getTenantId(); |
40 | - this.customerId = dashboardInfo.getCustomerId(); | |
41 | 45 | this.title = dashboardInfo.getTitle(); |
46 | + this.assignedCustomers = dashboardInfo.getAssignedCustomers(); | |
42 | 47 | } |
43 | 48 | |
44 | 49 | public TenantId getTenantId() { |
... | ... | @@ -49,14 +54,6 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
49 | 54 | this.tenantId = tenantId; |
50 | 55 | } |
51 | 56 | |
52 | - public CustomerId getCustomerId() { | |
53 | - return customerId; | |
54 | - } | |
55 | - | |
56 | - public void setCustomerId(CustomerId customerId) { | |
57 | - this.customerId = customerId; | |
58 | - } | |
59 | - | |
60 | 57 | public String getTitle() { |
61 | 58 | return title; |
62 | 59 | } |
... | ... | @@ -65,6 +62,44 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
65 | 62 | this.title = title; |
66 | 63 | } |
67 | 64 | |
65 | + public Map<String, String> getAssignedCustomers() { | |
66 | + return assignedCustomers; | |
67 | + } | |
68 | + | |
69 | + public void setAssignedCustomers(Map<String, String> assignedCustomers) { | |
70 | + this.assignedCustomers = assignedCustomers; | |
71 | + } | |
72 | + | |
73 | + public boolean addAssignedCustomer(CustomerId customerId, String title) { | |
74 | + if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { | |
75 | + return false; | |
76 | + } else { | |
77 | + if (this.assignedCustomers == null) { | |
78 | + this.assignedCustomers = new HashMap<>(); | |
79 | + } | |
80 | + this.assignedCustomers.put(customerId.toString(), title); | |
81 | + return true; | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + public boolean updateAssignedCustomer(CustomerId customerId, String title) { | |
86 | + if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { | |
87 | + this.assignedCustomers.put(customerId.toString(), title); | |
88 | + return true; | |
89 | + } else { | |
90 | + return false; | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + public boolean removeAssignedCustomer(CustomerId customerId) { | |
95 | + if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { | |
96 | + this.assignedCustomers.remove(customerId.toString()); | |
97 | + return true; | |
98 | + } else { | |
99 | + return false; | |
100 | + } | |
101 | + } | |
102 | + | |
68 | 103 | @Override |
69 | 104 | @JsonProperty(access = JsonProperty.Access.READ_ONLY) |
70 | 105 | public String getName() { |
... | ... | @@ -80,7 +115,6 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
80 | 115 | public int hashCode() { |
81 | 116 | final int prime = 31; |
82 | 117 | int result = super.hashCode(); |
83 | - result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); | |
84 | 118 | result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
85 | 119 | result = prime * result + ((title == null) ? 0 : title.hashCode()); |
86 | 120 | return result; |
... | ... | @@ -95,11 +129,6 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
95 | 129 | if (getClass() != obj.getClass()) |
96 | 130 | return false; |
97 | 131 | DashboardInfo other = (DashboardInfo) obj; |
98 | - if (customerId == null) { | |
99 | - if (other.customerId != null) | |
100 | - return false; | |
101 | - } else if (!customerId.equals(other.customerId)) | |
102 | - return false; | |
103 | 132 | if (tenantId == null) { |
104 | 133 | if (other.tenantId != null) |
105 | 134 | return false; |
... | ... | @@ -118,8 +147,6 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
118 | 147 | StringBuilder builder = new StringBuilder(); |
119 | 148 | builder.append("DashboardInfo [tenantId="); |
120 | 149 | builder.append(tenantId); |
121 | - builder.append(", customerId="); | |
122 | - builder.append(customerId); | |
123 | 150 | builder.append(", title="); |
124 | 151 | builder.append(title); |
125 | 152 | builder.append("]"); | ... | ... |
... | ... | @@ -97,7 +97,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom |
97 | 97 | public Customer saveCustomer(Customer customer) { |
98 | 98 | log.trace("Executing saveCustomer [{}]", customer); |
99 | 99 | customerValidator.validate(customer); |
100 | - return customerDao.save(customer); | |
100 | + Customer savedCustomer = customerDao.save(customer); | |
101 | + dashboardService.updateCustomerDashboards(savedCustomer.getTenantId(), savedCustomer.getId(), savedCustomer.getTitle()); | |
102 | + return savedCustomer; | |
101 | 103 | } |
102 | 104 | |
103 | 105 | @Override | ... | ... |
... | ... | @@ -15,16 +15,26 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.AsyncFunction; | |
19 | +import com.google.common.util.concurrent.Futures; | |
20 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | 23 | import org.springframework.stereotype.Component; |
20 | 24 | import org.thingsboard.server.common.data.DashboardInfo; |
25 | +import org.thingsboard.server.common.data.EntityType; | |
26 | +import org.thingsboard.server.common.data.id.CustomerId; | |
21 | 27 | import org.thingsboard.server.common.data.page.TextPageLink; |
28 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
29 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
30 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | |
22 | 31 | import org.thingsboard.server.dao.DaoUtil; |
23 | 32 | import org.thingsboard.server.dao.model.nosql.DashboardInfoEntity; |
24 | 33 | import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; |
34 | +import org.thingsboard.server.dao.relation.RelationDao; | |
25 | 35 | import org.thingsboard.server.dao.util.NoSqlDao; |
26 | 36 | |
27 | -import java.util.Arrays; | |
37 | +import java.util.ArrayList; | |
28 | 38 | import java.util.Collections; |
29 | 39 | import java.util.List; |
30 | 40 | import java.util.UUID; |
... | ... | @@ -37,6 +47,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; |
37 | 47 | @NoSqlDao |
38 | 48 | public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao<DashboardInfoEntity, DashboardInfo> implements DashboardInfoDao { |
39 | 49 | |
50 | + @Autowired | |
51 | + private RelationDao relationDao; | |
52 | + | |
40 | 53 | @Override |
41 | 54 | protected Class<DashboardInfoEntity> getColumnFamilyClass() { |
42 | 55 | return DashboardInfoEntity.class; |
... | ... | @@ -59,15 +72,18 @@ public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao<Da |
59 | 72 | } |
60 | 73 | |
61 | 74 | @Override |
62 | - public List<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { | |
75 | + public ListenableFuture<List<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TimePageLink pageLink) { | |
63 | 76 | log.debug("Try to find dashboards by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); |
64 | - List<DashboardInfoEntity> dashboardEntities = findPageWithTextSearch(DASHBOARD_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, | |
65 | - Arrays.asList(eq(DASHBOARD_CUSTOMER_ID_PROPERTY, customerId), | |
66 | - eq(DASHBOARD_TENANT_ID_PROPERTY, tenantId)), | |
67 | - pageLink); | |
68 | 77 | |
69 | - log.trace("Found dashboards [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", dashboardEntities, tenantId, customerId, pageLink); | |
70 | - return DaoUtil.convertDataList(dashboardEntities); | |
78 | + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new CustomerId(customerId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD, EntityType.DASHBOARD, pageLink); | |
79 | + | |
80 | + return Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<DashboardInfo>>) input -> { | |
81 | + List<ListenableFuture<DashboardInfo>> dashboardFutures = new ArrayList<>(input.size()); | |
82 | + for (EntityRelation relation : input) { | |
83 | + dashboardFutures.add(findByIdAsync(relation.getTo().getId())); | |
84 | + } | |
85 | + return Futures.successfulAsList(dashboardFutures); | |
86 | + }); | |
71 | 87 | } |
72 | 88 | |
73 | 89 | } | ... | ... |
... | ... | @@ -15,8 +15,10 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.DashboardInfo; |
19 | 20 | import org.thingsboard.server.common.data.page.TextPageLink; |
21 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
20 | 22 | import org.thingsboard.server.dao.Dao; |
21 | 23 | |
22 | 24 | import java.util.List; |
... | ... | @@ -44,6 +46,6 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> { |
44 | 46 | * @param pageLink the page link |
45 | 47 | * @return the list of dashboard objects |
46 | 48 | */ |
47 | - List<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); | |
49 | + ListenableFuture<List<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TimePageLink pageLink); | |
48 | 50 | |
49 | 51 | } | ... | ... |
... | ... | @@ -23,6 +23,10 @@ import org.thingsboard.server.common.data.id.DashboardId; |
23 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | 24 | import org.thingsboard.server.common.data.page.TextPageData; |
25 | 25 | import org.thingsboard.server.common.data.page.TextPageLink; |
26 | +import org.thingsboard.server.common.data.page.TimePageData; | |
27 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
28 | + | |
29 | +import java.sql.Time; | |
26 | 30 | |
27 | 31 | public interface DashboardService { |
28 | 32 | |
... | ... | @@ -38,7 +42,7 @@ public interface DashboardService { |
38 | 42 | |
39 | 43 | Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); |
40 | 44 | |
41 | - Dashboard unassignDashboardFromCustomer(DashboardId dashboardId); | |
45 | + Dashboard unassignDashboardFromCustomer(DashboardId dashboardId, CustomerId customerId); | |
42 | 46 | |
43 | 47 | void deleteDashboard(DashboardId dashboardId); |
44 | 48 | |
... | ... | @@ -46,8 +50,10 @@ public interface DashboardService { |
46 | 50 | |
47 | 51 | void deleteDashboardsByTenantId(TenantId tenantId); |
48 | 52 | |
49 | - TextPageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
53 | + ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink); | |
50 | 54 | |
51 | 55 | void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); |
52 | 56 | |
57 | + void updateCustomerDashboards(TenantId tenantId, CustomerId customerId, String customerTitle); | |
58 | + | |
53 | 59 | } | ... | ... |
... | ... | @@ -15,30 +15,42 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | +import com.google.common.base.Function; | |
19 | +import com.google.common.util.concurrent.Futures; | |
18 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 21 | import lombok.extern.slf4j.Slf4j; |
20 | 22 | import org.apache.commons.lang3.StringUtils; |
21 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 24 | import org.springframework.stereotype.Service; |
23 | -import org.thingsboard.server.common.data.Customer; | |
24 | -import org.thingsboard.server.common.data.Dashboard; | |
25 | -import org.thingsboard.server.common.data.DashboardInfo; | |
26 | -import org.thingsboard.server.common.data.Tenant; | |
25 | +import org.thingsboard.server.common.data.*; | |
26 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | |
27 | 27 | import org.thingsboard.server.common.data.id.CustomerId; |
28 | 28 | import org.thingsboard.server.common.data.id.DashboardId; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 30 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 31 | import org.thingsboard.server.common.data.page.TextPageLink; |
32 | +import org.thingsboard.server.common.data.page.TimePageData; | |
33 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
34 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
35 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | |
32 | 36 | import org.thingsboard.server.dao.customer.CustomerDao; |
33 | 37 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
34 | 38 | import org.thingsboard.server.dao.exception.DataValidationException; |
35 | 39 | import org.thingsboard.server.dao.model.ModelConstants; |
40 | +import org.thingsboard.server.dao.relation.RelationDao; | |
36 | 41 | import org.thingsboard.server.dao.service.DataValidator; |
37 | 42 | import org.thingsboard.server.dao.service.PaginatedRemover; |
43 | +import org.thingsboard.server.dao.service.TimePaginatedRemover; | |
38 | 44 | import org.thingsboard.server.dao.service.Validator; |
39 | 45 | import org.thingsboard.server.dao.tenant.TenantDao; |
40 | 46 | |
47 | +import javax.annotation.Nullable; | |
48 | +import java.sql.Time; | |
49 | +import java.util.ArrayList; | |
50 | +import java.util.HashSet; | |
41 | 51 | import java.util.List; |
52 | +import java.util.Set; | |
53 | +import java.util.concurrent.ExecutionException; | |
42 | 54 | |
43 | 55 | import static org.thingsboard.server.dao.service.Validator.validateId; |
44 | 56 | |
... | ... | @@ -59,7 +71,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
59 | 71 | |
60 | 72 | @Autowired |
61 | 73 | private CustomerDao customerDao; |
62 | - | |
74 | + | |
63 | 75 | @Override |
64 | 76 | public Dashboard findDashboardById(DashboardId dashboardId) { |
65 | 77 | log.trace("Executing findDashboardById [{}]", dashboardId); |
... | ... | @@ -98,15 +110,59 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
98 | 110 | @Override |
99 | 111 | public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId) { |
100 | 112 | Dashboard dashboard = findDashboardById(dashboardId); |
101 | - dashboard.setCustomerId(customerId); | |
102 | - return saveDashboard(dashboard); | |
113 | + Customer customer = customerDao.findById(customerId.getId()); | |
114 | + if (customer == null) { | |
115 | + throw new DataValidationException("Can't assign dashboard to non-existent customer!"); | |
116 | + } | |
117 | + if (!customer.getTenantId().getId().equals(dashboard.getTenantId().getId())) { | |
118 | + throw new DataValidationException("Can't assign dashboard to customer from different tenant!"); | |
119 | + } | |
120 | + if (dashboard.addAssignedCustomer(customerId, customer.getTitle())) { | |
121 | + try { | |
122 | + createRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD)); | |
123 | + } catch (ExecutionException | InterruptedException e) { | |
124 | + log.warn("[{}] Failed to create dashboard relation. Customer Id: [{}]", dashboardId, customerId); | |
125 | + throw new RuntimeException(e); | |
126 | + } | |
127 | + return saveDashboard(dashboard); | |
128 | + } else { | |
129 | + return dashboard; | |
130 | + } | |
103 | 131 | } |
104 | 132 | |
105 | 133 | @Override |
106 | - public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId) { | |
134 | + public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId, CustomerId customerId) { | |
107 | 135 | Dashboard dashboard = findDashboardById(dashboardId); |
108 | - dashboard.setCustomerId(null); | |
109 | - return saveDashboard(dashboard); | |
136 | + if (dashboard.removeAssignedCustomer(customerId)) { | |
137 | + try { | |
138 | + deleteRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD)); | |
139 | + } catch (ExecutionException | InterruptedException e) { | |
140 | + log.warn("[{}] Failed to delete dashboard relation. Customer Id: [{}]", dashboardId, customerId); | |
141 | + throw new RuntimeException(e); | |
142 | + } | |
143 | + return saveDashboard(dashboard); | |
144 | + } else { | |
145 | + return dashboard; | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + private Dashboard updateAssignedCustomerTitle(DashboardId dashboardId, CustomerId customerId, String customerTitle) { | |
150 | + Dashboard dashboard = findDashboardById(dashboardId); | |
151 | + if (dashboard.updateAssignedCustomer(customerId, customerTitle)) { | |
152 | + return saveDashboard(dashboard); | |
153 | + } else { | |
154 | + return dashboard; | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + private void deleteRelation(EntityRelation dashboardRelation) throws ExecutionException, InterruptedException { | |
159 | + log.debug("Deleting Dashboard relation: {}", dashboardRelation); | |
160 | + relationService.deleteRelationAsync(dashboardRelation).get(); | |
161 | + } | |
162 | + | |
163 | + private void createRelation(EntityRelation dashboardRelation) throws ExecutionException, InterruptedException { | |
164 | + log.debug("Creating Dashboard relation: {}", dashboardRelation); | |
165 | + relationService.saveRelationAsync(dashboardRelation).get(); | |
110 | 166 | } |
111 | 167 | |
112 | 168 | @Override |
... | ... | @@ -134,13 +190,20 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
134 | 190 | } |
135 | 191 | |
136 | 192 | @Override |
137 | - public TextPageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { | |
193 | + public ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) { | |
138 | 194 | log.trace("Executing findDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); |
139 | 195 | Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
140 | 196 | Validator.validateId(customerId, "Incorrect customerId " + customerId); |
141 | 197 | Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); |
142 | - List<DashboardInfo> dashboards = dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); | |
143 | - return new TextPageData<>(dashboards, pageLink); | |
198 | + ListenableFuture<List<DashboardInfo>> dashboards = dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); | |
199 | + | |
200 | + return Futures.transform(dashboards, new Function<List<DashboardInfo>, TimePageData<DashboardInfo>>() { | |
201 | + @Nullable | |
202 | + @Override | |
203 | + public TimePageData<DashboardInfo> apply(@Nullable List<DashboardInfo> dashboards) { | |
204 | + return new TimePageData<>(dashboards, pageLink); | |
205 | + } | |
206 | + }); | |
144 | 207 | } |
145 | 208 | |
146 | 209 | @Override |
... | ... | @@ -148,9 +211,18 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
148 | 211 | log.trace("Executing unassignCustomerDashboards, tenantId [{}], customerId [{}]", tenantId, customerId); |
149 | 212 | Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
150 | 213 | Validator.validateId(customerId, "Incorrect customerId " + customerId); |
151 | - new CustomerDashboardsUnassigner(tenantId).removeEntities(customerId); | |
214 | + new CustomerDashboardsUnassigner(tenantId, customerId).removeEntities(customerId); | |
152 | 215 | } |
153 | - | |
216 | + | |
217 | + @Override | |
218 | + public void updateCustomerDashboards(TenantId tenantId, CustomerId customerId, String customerTitle) { | |
219 | + log.trace("Executing updateCustomerDashboards, tenantId [{}], customerId [{}], customerTitle [{}]", tenantId, customerId, customerTitle); | |
220 | + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | |
221 | + Validator.validateId(customerId, "Incorrect customerId " + customerId); | |
222 | + Validator.validateString(customerTitle, "Incorrect customerTitle " + customerTitle); | |
223 | + new CustomerDashboardsUpdater(tenantId, customerId, customerTitle).removeEntities(customerId); | |
224 | + } | |
225 | + | |
154 | 226 | private DataValidator<Dashboard> dashboardValidator = |
155 | 227 | new DataValidator<Dashboard>() { |
156 | 228 | @Override |
... | ... | @@ -166,17 +238,6 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
166 | 238 | throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); |
167 | 239 | } |
168 | 240 | } |
169 | - if (dashboard.getCustomerId() == null) { | |
170 | - dashboard.setCustomerId(new CustomerId(ModelConstants.NULL_UUID)); | |
171 | - } else if (!dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
172 | - Customer customer = customerDao.findById(dashboard.getCustomerId().getId()); | |
173 | - if (customer == null) { | |
174 | - throw new DataValidationException("Can't assign dashboard to non-existent customer!"); | |
175 | - } | |
176 | - if (!customer.getTenantId().getId().equals(dashboard.getTenantId().getId())) { | |
177 | - throw new DataValidationException("Can't assign dashboard to customer from different tenant!"); | |
178 | - } | |
179 | - } | |
180 | 241 | } |
181 | 242 | }; |
182 | 243 | |
... | ... | @@ -194,24 +255,60 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
194 | 255 | } |
195 | 256 | }; |
196 | 257 | |
197 | - private class CustomerDashboardsUnassigner extends PaginatedRemover<CustomerId, DashboardInfo> { | |
258 | + private class CustomerDashboardsUnassigner extends TimePaginatedRemover<CustomerId, DashboardInfo> { | |
198 | 259 | |
199 | 260 | private TenantId tenantId; |
261 | + private CustomerId customerId; | |
200 | 262 | |
201 | - CustomerDashboardsUnassigner(TenantId tenantId) { | |
263 | + CustomerDashboardsUnassigner(TenantId tenantId, CustomerId customerId) { | |
202 | 264 | this.tenantId = tenantId; |
265 | + this.customerId = customerId; | |
203 | 266 | } |
204 | 267 | |
205 | 268 | @Override |
206 | - protected List<DashboardInfo> findEntities(CustomerId id, TextPageLink pageLink) { | |
207 | - return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); | |
269 | + protected List<DashboardInfo> findEntities(CustomerId id, TimePageLink pageLink) { | |
270 | + try { | |
271 | + return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink).get(); | |
272 | + } catch (InterruptedException | ExecutionException e) { | |
273 | + log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", tenantId, id); | |
274 | + throw new RuntimeException(e); | |
275 | + } | |
208 | 276 | } |
209 | 277 | |
210 | 278 | @Override |
211 | 279 | protected void removeEntity(DashboardInfo entity) { |
212 | - unassignDashboardFromCustomer(new DashboardId(entity.getUuidId())); | |
280 | + unassignDashboardFromCustomer(new DashboardId(entity.getUuidId()), this.customerId); | |
213 | 281 | } |
214 | 282 | |
215 | 283 | } |
216 | 284 | |
285 | + private class CustomerDashboardsUpdater extends TimePaginatedRemover<CustomerId, DashboardInfo> { | |
286 | + | |
287 | + private TenantId tenantId; | |
288 | + private CustomerId customerId; | |
289 | + private String customerTitle; | |
290 | + | |
291 | + CustomerDashboardsUpdater(TenantId tenantId, CustomerId customerId, String customerTitle) { | |
292 | + this.tenantId = tenantId; | |
293 | + this.customerId = customerId; | |
294 | + this.customerTitle = customerTitle; | |
295 | + } | |
296 | + | |
297 | + @Override | |
298 | + protected List<DashboardInfo> findEntities(CustomerId id, TimePageLink pageLink) { | |
299 | + try { | |
300 | + return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink).get(); | |
301 | + } catch (InterruptedException | ExecutionException e) { | |
302 | + log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", tenantId, id); | |
303 | + throw new RuntimeException(e); | |
304 | + } | |
305 | + } | |
306 | + | |
307 | + @Override | |
308 | + protected void removeEntity(DashboardInfo entity) { | |
309 | + updateAssignedCustomerTitle(new DashboardId(entity.getUuidId()), this.customerId, this.customerTitle); | |
310 | + } | |
311 | + | |
312 | + } | |
313 | + | |
217 | 314 | } | ... | ... |
... | ... | @@ -266,13 +266,11 @@ public class ModelConstants { |
266 | 266 | */ |
267 | 267 | public static final String DASHBOARD_COLUMN_FAMILY_NAME = "dashboard"; |
268 | 268 | public static final String DASHBOARD_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; |
269 | - public static final String DASHBOARD_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; | |
270 | 269 | public static final String DASHBOARD_TITLE_PROPERTY = TITLE_PROPERTY; |
271 | 270 | public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration"; |
271 | + public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers"; | |
272 | 272 | |
273 | 273 | public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text"; |
274 | - public static final String DASHBOARD_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_customer_and_search_text"; | |
275 | - | |
276 | 274 | |
277 | 275 | /** |
278 | 276 | * Cassandra plugin metadata constants. | ... | ... |
... | ... | @@ -19,16 +19,19 @@ import com.datastax.driver.core.utils.UUIDs; |
19 | 19 | import com.datastax.driver.mapping.annotations.Column; |
20 | 20 | import com.datastax.driver.mapping.annotations.PartitionKey; |
21 | 21 | import com.datastax.driver.mapping.annotations.Table; |
22 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
22 | 23 | import com.fasterxml.jackson.databind.JsonNode; |
24 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
23 | 25 | import lombok.EqualsAndHashCode; |
24 | 26 | import lombok.ToString; |
27 | +import lombok.extern.slf4j.Slf4j; | |
25 | 28 | import org.thingsboard.server.common.data.Dashboard; |
26 | -import org.thingsboard.server.common.data.id.CustomerId; | |
27 | 29 | import org.thingsboard.server.common.data.id.DashboardId; |
28 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 31 | import org.thingsboard.server.dao.model.SearchTextEntity; |
30 | 32 | import org.thingsboard.server.dao.model.type.JsonCodec; |
31 | 33 | |
34 | +import java.util.HashMap; | |
32 | 35 | import java.util.UUID; |
33 | 36 | |
34 | 37 | import static org.thingsboard.server.dao.model.ModelConstants.*; |
... | ... | @@ -36,8 +39,11 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; |
36 | 39 | @Table(name = DASHBOARD_COLUMN_FAMILY_NAME) |
37 | 40 | @EqualsAndHashCode |
38 | 41 | @ToString |
42 | +@Slf4j | |
39 | 43 | public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
40 | - | |
44 | + | |
45 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
46 | + | |
41 | 47 | @PartitionKey(value = 0) |
42 | 48 | @Column(name = ID_PROPERTY) |
43 | 49 | private UUID id; |
... | ... | @@ -46,16 +52,15 @@ public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
46 | 52 | @Column(name = DASHBOARD_TENANT_ID_PROPERTY) |
47 | 53 | private UUID tenantId; |
48 | 54 | |
49 | - @PartitionKey(value = 2) | |
50 | - @Column(name = DASHBOARD_CUSTOMER_ID_PROPERTY) | |
51 | - private UUID customerId; | |
52 | - | |
53 | 55 | @Column(name = DASHBOARD_TITLE_PROPERTY) |
54 | 56 | private String title; |
55 | 57 | |
56 | 58 | @Column(name = SEARCH_TEXT_PROPERTY) |
57 | 59 | private String searchText; |
58 | - | |
60 | + | |
61 | + @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY, codec = JsonCodec.class) | |
62 | + private JsonNode assignedCustomers; | |
63 | + | |
59 | 64 | @Column(name = DASHBOARD_CONFIGURATION_PROPERTY, codec = JsonCodec.class) |
60 | 65 | private JsonNode configuration; |
61 | 66 | |
... | ... | @@ -70,10 +75,10 @@ public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
70 | 75 | if (dashboard.getTenantId() != null) { |
71 | 76 | this.tenantId = dashboard.getTenantId().getId(); |
72 | 77 | } |
73 | - if (dashboard.getCustomerId() != null) { | |
74 | - this.customerId = dashboard.getCustomerId().getId(); | |
75 | - } | |
76 | 78 | this.title = dashboard.getTitle(); |
79 | + if (dashboard.getAssignedCustomers() != null) { | |
80 | + this.assignedCustomers = objectMapper.valueToTree(dashboard.getAssignedCustomers()); | |
81 | + } | |
77 | 82 | this.configuration = dashboard.getConfiguration(); |
78 | 83 | } |
79 | 84 | |
... | ... | @@ -93,14 +98,6 @@ public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
93 | 98 | this.tenantId = tenantId; |
94 | 99 | } |
95 | 100 | |
96 | - public UUID getCustomerId() { | |
97 | - return customerId; | |
98 | - } | |
99 | - | |
100 | - public void setCustomerId(UUID customerId) { | |
101 | - this.customerId = customerId; | |
102 | - } | |
103 | - | |
104 | 101 | public String getTitle() { |
105 | 102 | return title; |
106 | 103 | } |
... | ... | @@ -109,6 +106,14 @@ public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
109 | 106 | this.title = title; |
110 | 107 | } |
111 | 108 | |
109 | + public JsonNode getAssignedCustomers() { | |
110 | + return assignedCustomers; | |
111 | + } | |
112 | + | |
113 | + public void setAssignedCustomers(JsonNode assignedCustomers) { | |
114 | + this.assignedCustomers = assignedCustomers; | |
115 | + } | |
116 | + | |
112 | 117 | public JsonNode getConfiguration() { |
113 | 118 | return configuration; |
114 | 119 | } |
... | ... | @@ -138,10 +143,14 @@ public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
138 | 143 | if (tenantId != null) { |
139 | 144 | dashboard.setTenantId(new TenantId(tenantId)); |
140 | 145 | } |
141 | - if (customerId != null) { | |
142 | - dashboard.setCustomerId(new CustomerId(customerId)); | |
143 | - } | |
144 | 146 | dashboard.setTitle(title); |
147 | + if (assignedCustomers != null) { | |
148 | + try { | |
149 | + dashboard.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); | |
150 | + } catch (JsonProcessingException e) { | |
151 | + log.warn("Unable to parse assigned customers!", e); | |
152 | + } | |
153 | + } | |
145 | 154 | dashboard.setConfiguration(configuration); |
146 | 155 | return dashboard; |
147 | 156 | } | ... | ... |
... | ... | @@ -19,14 +19,21 @@ import com.datastax.driver.core.utils.UUIDs; |
19 | 19 | import com.datastax.driver.mapping.annotations.Column; |
20 | 20 | import com.datastax.driver.mapping.annotations.PartitionKey; |
21 | 21 | import com.datastax.driver.mapping.annotations.Table; |
22 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
23 | +import com.fasterxml.jackson.databind.JsonNode; | |
24 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
22 | 25 | import lombok.EqualsAndHashCode; |
23 | 26 | import lombok.ToString; |
27 | +import lombok.extern.slf4j.Slf4j; | |
24 | 28 | import org.thingsboard.server.common.data.DashboardInfo; |
25 | 29 | import org.thingsboard.server.common.data.id.CustomerId; |
26 | 30 | import org.thingsboard.server.common.data.id.DashboardId; |
27 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
28 | 32 | import org.thingsboard.server.dao.model.SearchTextEntity; |
33 | +import org.thingsboard.server.dao.model.type.JsonCodec; | |
29 | 34 | |
35 | +import java.util.HashMap; | |
36 | +import java.util.Set; | |
30 | 37 | import java.util.UUID; |
31 | 38 | |
32 | 39 | import static org.thingsboard.server.dao.model.ModelConstants.*; |
... | ... | @@ -34,8 +41,11 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; |
34 | 41 | @Table(name = DASHBOARD_COLUMN_FAMILY_NAME) |
35 | 42 | @EqualsAndHashCode |
36 | 43 | @ToString |
44 | +@Slf4j | |
37 | 45 | public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
38 | 46 | |
47 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
48 | + | |
39 | 49 | @PartitionKey(value = 0) |
40 | 50 | @Column(name = ID_PROPERTY) |
41 | 51 | private UUID id; |
... | ... | @@ -44,16 +54,15 @@ public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
44 | 54 | @Column(name = DASHBOARD_TENANT_ID_PROPERTY) |
45 | 55 | private UUID tenantId; |
46 | 56 | |
47 | - @PartitionKey(value = 2) | |
48 | - @Column(name = DASHBOARD_CUSTOMER_ID_PROPERTY) | |
49 | - private UUID customerId; | |
50 | - | |
51 | 57 | @Column(name = DASHBOARD_TITLE_PROPERTY) |
52 | 58 | private String title; |
53 | 59 | |
54 | 60 | @Column(name = SEARCH_TEXT_PROPERTY) |
55 | 61 | private String searchText; |
56 | 62 | |
63 | + @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY, codec = JsonCodec.class) | |
64 | + private JsonNode assignedCustomers; | |
65 | + | |
57 | 66 | public DashboardInfoEntity() { |
58 | 67 | super(); |
59 | 68 | } |
... | ... | @@ -65,10 +74,10 @@ public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
65 | 74 | if (dashboardInfo.getTenantId() != null) { |
66 | 75 | this.tenantId = dashboardInfo.getTenantId().getId(); |
67 | 76 | } |
68 | - if (dashboardInfo.getCustomerId() != null) { | |
69 | - this.customerId = dashboardInfo.getCustomerId().getId(); | |
70 | - } | |
71 | 77 | this.title = dashboardInfo.getTitle(); |
78 | + if (dashboardInfo.getAssignedCustomers() != null) { | |
79 | + this.assignedCustomers = objectMapper.valueToTree(dashboardInfo.getAssignedCustomers()); | |
80 | + } | |
72 | 81 | } |
73 | 82 | |
74 | 83 | public UUID getId() { |
... | ... | @@ -87,14 +96,6 @@ public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
87 | 96 | this.tenantId = tenantId; |
88 | 97 | } |
89 | 98 | |
90 | - public UUID getCustomerId() { | |
91 | - return customerId; | |
92 | - } | |
93 | - | |
94 | - public void setCustomerId(UUID customerId) { | |
95 | - this.customerId = customerId; | |
96 | - } | |
97 | - | |
98 | 99 | public String getTitle() { |
99 | 100 | return title; |
100 | 101 | } |
... | ... | @@ -103,6 +104,14 @@ public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
103 | 104 | this.title = title; |
104 | 105 | } |
105 | 106 | |
107 | + public JsonNode getAssignedCustomers() { | |
108 | + return assignedCustomers; | |
109 | + } | |
110 | + | |
111 | + public void setAssignedCustomers(JsonNode assignedCustomers) { | |
112 | + this.assignedCustomers = assignedCustomers; | |
113 | + } | |
114 | + | |
106 | 115 | @Override |
107 | 116 | public String getSearchTextSource() { |
108 | 117 | return getTitle(); |
... | ... | @@ -124,10 +133,14 @@ public class DashboardInfoEntity implements SearchTextEntity<DashboardInfo> { |
124 | 133 | if (tenantId != null) { |
125 | 134 | dashboardInfo.setTenantId(new TenantId(tenantId)); |
126 | 135 | } |
127 | - if (customerId != null) { | |
128 | - dashboardInfo.setCustomerId(new CustomerId(customerId)); | |
129 | - } | |
130 | 136 | dashboardInfo.setTitle(title); |
137 | + if (assignedCustomers != null) { | |
138 | + try { | |
139 | + dashboardInfo.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); | |
140 | + } catch (JsonProcessingException e) { | |
141 | + log.warn("Unable to parse assigned customers!", e); | |
142 | + } | |
143 | + } | |
131 | 144 | return dashboardInfo; |
132 | 145 | } |
133 | 146 | ... | ... |
... | ... | @@ -16,9 +16,12 @@ |
16 | 16 | package org.thingsboard.server.dao.model.sql; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
19 | 20 | import com.fasterxml.jackson.databind.JsonNode; |
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | 22 | import lombok.Data; |
21 | 23 | import lombok.EqualsAndHashCode; |
24 | +import lombok.extern.slf4j.Slf4j; | |
22 | 25 | import org.hibernate.annotations.Type; |
23 | 26 | import org.hibernate.annotations.TypeDef; |
24 | 27 | import org.thingsboard.server.common.data.Dashboard; |
... | ... | @@ -33,20 +36,23 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; |
33 | 36 | import javax.persistence.Column; |
34 | 37 | import javax.persistence.Entity; |
35 | 38 | import javax.persistence.Table; |
39 | +import java.util.HashMap; | |
40 | +import java.util.List; | |
41 | +import java.util.Set; | |
36 | 42 | |
37 | 43 | @Data |
44 | +@Slf4j | |
38 | 45 | @EqualsAndHashCode(callSuper = true) |
39 | 46 | @Entity |
40 | 47 | @TypeDef(name = "json", typeClass = JsonStringType.class) |
41 | 48 | @Table(name = ModelConstants.DASHBOARD_COLUMN_FAMILY_NAME) |
42 | 49 | public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements SearchTextEntity<Dashboard> { |
43 | 50 | |
51 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
52 | + | |
44 | 53 | @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) |
45 | 54 | private String tenantId; |
46 | 55 | |
47 | - @Column(name = ModelConstants.DASHBOARD_CUSTOMER_ID_PROPERTY) | |
48 | - private String customerId; | |
49 | - | |
50 | 56 | @Column(name = ModelConstants.DASHBOARD_TITLE_PROPERTY) |
51 | 57 | private String title; |
52 | 58 | |
... | ... | @@ -54,6 +60,10 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S |
54 | 60 | private String searchText; |
55 | 61 | |
56 | 62 | @Type(type = "json") |
63 | + @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) | |
64 | + private JsonNode assignedCustomers; | |
65 | + | |
66 | + @Type(type = "json") | |
57 | 67 | @Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY) |
58 | 68 | private JsonNode configuration; |
59 | 69 | |
... | ... | @@ -68,10 +78,10 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S |
68 | 78 | if (dashboard.getTenantId() != null) { |
69 | 79 | this.tenantId = toString(dashboard.getTenantId().getId()); |
70 | 80 | } |
71 | - if (dashboard.getCustomerId() != null) { | |
72 | - this.customerId = toString(dashboard.getCustomerId().getId()); | |
73 | - } | |
74 | 81 | this.title = dashboard.getTitle(); |
82 | + if (dashboard.getAssignedCustomers() != null) { | |
83 | + this.assignedCustomers = objectMapper.valueToTree(dashboard.getAssignedCustomers()); | |
84 | + } | |
75 | 85 | this.configuration = dashboard.getConfiguration(); |
76 | 86 | } |
77 | 87 | |
... | ... | @@ -92,10 +102,14 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S |
92 | 102 | if (tenantId != null) { |
93 | 103 | dashboard.setTenantId(new TenantId(toUUID(tenantId))); |
94 | 104 | } |
95 | - if (customerId != null) { | |
96 | - dashboard.setCustomerId(new CustomerId(toUUID(customerId))); | |
97 | - } | |
98 | 105 | dashboard.setTitle(title); |
106 | + if (assignedCustomers != null) { | |
107 | + try { | |
108 | + dashboard.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); | |
109 | + } catch (JsonProcessingException e) { | |
110 | + log.warn("Unable to parse assigned customers!", e); | |
111 | + } | |
112 | + } | |
99 | 113 | dashboard.setConfiguration(configuration); |
100 | 114 | return dashboard; |
101 | 115 | } | ... | ... |
... | ... | @@ -16,8 +16,13 @@ |
16 | 16 | package org.thingsboard.server.dao.model.sql; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | 22 | import lombok.Data; |
20 | 23 | import lombok.EqualsAndHashCode; |
24 | +import lombok.extern.slf4j.Slf4j; | |
25 | +import org.hibernate.annotations.Type; | |
21 | 26 | import org.thingsboard.server.common.data.DashboardInfo; |
22 | 27 | import org.thingsboard.server.common.data.id.CustomerId; |
23 | 28 | import org.thingsboard.server.common.data.id.DashboardId; |
... | ... | @@ -29,25 +34,31 @@ import org.thingsboard.server.dao.model.SearchTextEntity; |
29 | 34 | import javax.persistence.Column; |
30 | 35 | import javax.persistence.Entity; |
31 | 36 | import javax.persistence.Table; |
37 | +import java.util.HashMap; | |
38 | +import java.util.Set; | |
32 | 39 | |
33 | 40 | @Data |
41 | +@Slf4j | |
34 | 42 | @EqualsAndHashCode(callSuper = true) |
35 | 43 | @Entity |
36 | 44 | @Table(name = ModelConstants.DASHBOARD_COLUMN_FAMILY_NAME) |
37 | 45 | public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements SearchTextEntity<DashboardInfo> { |
38 | 46 | |
47 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
48 | + | |
39 | 49 | @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) |
40 | 50 | private String tenantId; |
41 | 51 | |
42 | - @Column(name = ModelConstants.DASHBOARD_CUSTOMER_ID_PROPERTY) | |
43 | - private String customerId; | |
44 | - | |
45 | 52 | @Column(name = ModelConstants.DASHBOARD_TITLE_PROPERTY) |
46 | 53 | private String title; |
47 | 54 | |
48 | 55 | @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) |
49 | 56 | private String searchText; |
50 | 57 | |
58 | + @Type(type = "json") | |
59 | + @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) | |
60 | + private JsonNode assignedCustomers; | |
61 | + | |
51 | 62 | public DashboardInfoEntity() { |
52 | 63 | super(); |
53 | 64 | } |
... | ... | @@ -59,10 +70,10 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
59 | 70 | if (dashboardInfo.getTenantId() != null) { |
60 | 71 | this.tenantId = toString(dashboardInfo.getTenantId().getId()); |
61 | 72 | } |
62 | - if (dashboardInfo.getCustomerId() != null) { | |
63 | - this.customerId = toString(dashboardInfo.getCustomerId().getId()); | |
64 | - } | |
65 | 73 | this.title = dashboardInfo.getTitle(); |
74 | + if (dashboardInfo.getAssignedCustomers() != null) { | |
75 | + this.assignedCustomers = objectMapper.valueToTree(dashboardInfo.getAssignedCustomers()); | |
76 | + } | |
66 | 77 | } |
67 | 78 | |
68 | 79 | @Override |
... | ... | @@ -86,10 +97,14 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
86 | 97 | if (tenantId != null) { |
87 | 98 | dashboardInfo.setTenantId(new TenantId(toUUID(tenantId))); |
88 | 99 | } |
89 | - if (customerId != null) { | |
90 | - dashboardInfo.setCustomerId(new CustomerId(toUUID(customerId))); | |
91 | - } | |
92 | 100 | dashboardInfo.setTitle(title); |
101 | + if (assignedCustomers != null) { | |
102 | + try { | |
103 | + dashboardInfo.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); | |
104 | + } catch (JsonProcessingException e) { | |
105 | + log.warn("Unable to parse assigned customers!", e); | |
106 | + } | |
107 | + } | |
93 | 108 | return dashboardInfo; |
94 | 109 | } |
95 | 110 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.service; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.id.IdBased; | |
19 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
20 | + | |
21 | +import java.sql.Time; | |
22 | +import java.util.List; | |
23 | +import java.util.UUID; | |
24 | + | |
25 | +public abstract class TimePaginatedRemover<I, D extends IdBased<?>> { | |
26 | + | |
27 | + private static final int DEFAULT_LIMIT = 100; | |
28 | + | |
29 | + public void removeEntities(I id) { | |
30 | + TimePageLink pageLink = new TimePageLink(DEFAULT_LIMIT); | |
31 | + boolean hasNext = true; | |
32 | + while (hasNext) { | |
33 | + List<D> entities = findEntities(id, pageLink); | |
34 | + for (D entity : entities) { | |
35 | + removeEntity(entity); | |
36 | + } | |
37 | + hasNext = entities.size() == pageLink.getLimit(); | |
38 | + if (hasNext) { | |
39 | + int index = entities.size() - 1; | |
40 | + UUID idOffset = entities.get(index).getUuidId(); | |
41 | + pageLink.setIdOffset(idOffset); | |
42 | + } | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + protected abstract List<D> findEntities(I id, TimePageLink pageLink); | |
47 | + | |
48 | + protected abstract void removeEntity(D entity); | |
49 | + | |
50 | +} | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.id.EntityId; |
19 | 19 | import org.thingsboard.server.common.data.id.UUIDBased; |
20 | +import org.thingsboard.server.common.data.page.BasePageLink; | |
20 | 21 | import org.thingsboard.server.common.data.page.TextPageLink; |
21 | 22 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
22 | 23 | |
... | ... | @@ -116,7 +117,7 @@ public class Validator { |
116 | 117 | * @param pageLink the page link |
117 | 118 | * @param errorMessage the error message for exception |
118 | 119 | */ |
119 | - public static void validatePageLink(TextPageLink pageLink, String errorMessage) { | |
120 | + public static void validatePageLink(BasePageLink pageLink, String errorMessage) { | |
120 | 121 | if (pageLink == null || pageLink.getLimit() < 1 || (pageLink.getIdOffset() != null && pageLink.getIdOffset().version() != 1)) { |
121 | 122 | throw new IncorrectParameterException(errorMessage); |
122 | 123 | } | ... | ... |
... | ... | @@ -39,12 +39,4 @@ public interface DashboardInfoRepository extends CrudRepository<DashboardInfoEnt |
39 | 39 | @Param("idOffset") String idOffset, |
40 | 40 | Pageable pageable); |
41 | 41 | |
42 | - @Query("SELECT di FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId " + | |
43 | - "AND di.customerId = :customerId AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + | |
44 | - "AND di.id > :idOffset ORDER BY di.id") | |
45 | - List<DashboardInfoEntity> findByTenantIdAndCustomerId(@Param("tenantId") String tenantId, | |
46 | - @Param("customerId") String customerId, | |
47 | - @Param("searchText") String searchText, | |
48 | - @Param("idOffset") String idOffset, | |
49 | - Pageable pageable); | |
50 | 42 | } | ... | ... |
... | ... | @@ -15,19 +15,31 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.sql.dashboard; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.AsyncFunction; | |
19 | +import com.google.common.util.concurrent.Futures; | |
20 | +import com.google.common.util.concurrent.ListenableFuture; | |
21 | +import lombok.extern.slf4j.Slf4j; | |
18 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
19 | 23 | import org.springframework.data.domain.PageRequest; |
20 | 24 | import org.springframework.data.repository.CrudRepository; |
21 | 25 | import org.springframework.stereotype.Component; |
22 | 26 | import org.thingsboard.server.common.data.DashboardInfo; |
27 | +import org.thingsboard.server.common.data.EntityType; | |
23 | 28 | import org.thingsboard.server.common.data.UUIDConverter; |
29 | +import org.thingsboard.server.common.data.id.CustomerId; | |
24 | 30 | import org.thingsboard.server.common.data.page.TextPageLink; |
31 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
32 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
33 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | |
25 | 34 | import org.thingsboard.server.dao.DaoUtil; |
26 | 35 | import org.thingsboard.server.dao.dashboard.DashboardInfoDao; |
27 | 36 | import org.thingsboard.server.dao.model.sql.DashboardInfoEntity; |
37 | +import org.thingsboard.server.dao.relation.RelationDao; | |
28 | 38 | import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; |
29 | 39 | import org.thingsboard.server.dao.util.SqlDao; |
30 | 40 | |
41 | +import java.sql.Time; | |
42 | +import java.util.ArrayList; | |
31 | 43 | import java.util.List; |
32 | 44 | import java.util.Objects; |
33 | 45 | import java.util.UUID; |
... | ... | @@ -37,11 +49,15 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; |
37 | 49 | /** |
38 | 50 | * Created by Valerii Sosliuk on 5/6/2017. |
39 | 51 | */ |
52 | +@Slf4j | |
40 | 53 | @Component |
41 | 54 | @SqlDao |
42 | 55 | public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoEntity, DashboardInfo> implements DashboardInfoDao { |
43 | 56 | |
44 | 57 | @Autowired |
58 | + private RelationDao relationDao; | |
59 | + | |
60 | + @Autowired | |
45 | 61 | private DashboardInfoRepository dashboardInfoRepository; |
46 | 62 | |
47 | 63 | @Override |
... | ... | @@ -65,13 +81,17 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE |
65 | 81 | } |
66 | 82 | |
67 | 83 | @Override |
68 | - public List<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { | |
69 | - return DaoUtil.convertDataList(dashboardInfoRepository | |
70 | - .findByTenantIdAndCustomerId( | |
71 | - UUIDConverter.fromTimeUUID(tenantId), | |
72 | - UUIDConverter.fromTimeUUID(customerId), | |
73 | - Objects.toString(pageLink.getTextSearch(), ""), | |
74 | - pageLink.getIdOffset() == null ? NULL_UUID_STR : UUIDConverter.fromTimeUUID(pageLink.getIdOffset()), | |
75 | - new PageRequest(0, pageLink.getLimit()))); | |
84 | + public ListenableFuture<List<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TimePageLink pageLink) { | |
85 | + log.debug("Try to find dashboards by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); | |
86 | + | |
87 | + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new CustomerId(customerId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD, EntityType.DASHBOARD, pageLink); | |
88 | + | |
89 | + return Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<DashboardInfo>>) input -> { | |
90 | + List<ListenableFuture<DashboardInfo>> dashboardFutures = new ArrayList<>(input.size()); | |
91 | + for (EntityRelation relation : input) { | |
92 | + dashboardFutures.add(findByIdAsync(relation.getTo().getId())); | |
93 | + } | |
94 | + return Futures.successfulAsList(dashboardFutures); | |
95 | + }); | |
76 | 96 | } |
77 | 97 | } | ... | ... |
... | ... | @@ -364,26 +364,19 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widget_type_by_tenant_and_ali |
364 | 364 | CREATE TABLE IF NOT EXISTS thingsboard.dashboard ( |
365 | 365 | id timeuuid, |
366 | 366 | tenant_id timeuuid, |
367 | - customer_id timeuuid, | |
368 | 367 | title text, |
369 | 368 | search_text text, |
369 | + assigned_customers text, | |
370 | 370 | configuration text, |
371 | - PRIMARY KEY (id, tenant_id, customer_id) | |
371 | + PRIMARY KEY (id, tenant_id) | |
372 | 372 | ); |
373 | 373 | |
374 | 374 | CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.dashboard_by_tenant_and_search_text AS |
375 | 375 | SELECT * |
376 | 376 | from thingsboard.dashboard |
377 | - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL | |
378 | - PRIMARY KEY ( tenant_id, search_text, id, customer_id ) | |
379 | - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC ); | |
380 | - | |
381 | -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.dashboard_by_customer_and_search_text AS | |
382 | - SELECT * | |
383 | - from thingsboard.dashboard | |
384 | - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL | |
385 | - PRIMARY KEY ( customer_id, tenant_id, search_text, id ) | |
386 | - WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); | |
377 | + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL | |
378 | + PRIMARY KEY ( tenant_id, search_text, id ) | |
379 | + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); | |
387 | 380 | |
388 | 381 | CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_cf ( |
389 | 382 | entity_type text, // (DEVICE, CUSTOMER, TENANT) | ... | ... |
... | ... | @@ -105,7 +105,7 @@ CREATE TABLE IF NOT EXISTS customer ( |
105 | 105 | CREATE TABLE IF NOT EXISTS dashboard ( |
106 | 106 | id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, |
107 | 107 | configuration varchar(10000000), |
108 | - customer_id varchar(31), | |
108 | + assigned_customers varchar(1000000), | |
109 | 109 | search_text varchar(255), |
110 | 110 | tenant_id varchar(31), |
111 | 111 | title varchar(255) | ... | ... |
... | ... | @@ -29,13 +29,17 @@ import org.thingsboard.server.common.data.id.CustomerId; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 30 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 31 | import org.thingsboard.server.common.data.page.TextPageLink; |
32 | +import org.thingsboard.server.common.data.page.TimePageData; | |
33 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
32 | 34 | import org.thingsboard.server.dao.exception.DataValidationException; |
33 | 35 | import org.thingsboard.server.dao.model.ModelConstants; |
34 | 36 | |
35 | 37 | import java.io.IOException; |
38 | +import java.sql.Time; | |
36 | 39 | import java.util.ArrayList; |
37 | 40 | import java.util.Collections; |
38 | 41 | import java.util.List; |
42 | +import java.util.concurrent.ExecutionException; | |
39 | 43 | |
40 | 44 | public abstract class BaseDashboardServiceTest extends AbstractServiceTest { |
41 | 45 | |
... | ... | @@ -68,8 +72,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { |
68 | 72 | Assert.assertNotNull(savedDashboard.getId()); |
69 | 73 | Assert.assertTrue(savedDashboard.getCreatedTime() > 0); |
70 | 74 | Assert.assertEquals(dashboard.getTenantId(), savedDashboard.getTenantId()); |
71 | - Assert.assertNotNull(savedDashboard.getCustomerId()); | |
72 | - Assert.assertEquals(ModelConstants.NULL_UUID, savedDashboard.getCustomerId().getId()); | |
73 | 75 | Assert.assertEquals(dashboard.getTitle(), savedDashboard.getTitle()); |
74 | 76 | |
75 | 77 | savedDashboard.setTitle("My new dashboard"); |
... | ... | @@ -280,7 +282,7 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { |
280 | 282 | } |
281 | 283 | |
282 | 284 | @Test |
283 | - public void testFindDashboardsByTenantIdAndCustomerId() { | |
285 | + public void testFindDashboardsByTenantIdAndCustomerId() throws ExecutionException, InterruptedException { | |
284 | 286 | Tenant tenant = new Tenant(); |
285 | 287 | tenant.setTitle("Test tenant"); |
286 | 288 | tenant = tenantService.saveTenant(tenant); |
... | ... | @@ -303,10 +305,10 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { |
303 | 305 | } |
304 | 306 | |
305 | 307 | List<DashboardInfo> loadedDashboards = new ArrayList<>(); |
306 | - TextPageLink pageLink = new TextPageLink(23); | |
307 | - TextPageData<DashboardInfo> pageData = null; | |
308 | + TimePageLink pageLink = new TimePageLink(23); | |
309 | + TimePageData<DashboardInfo> pageData = null; | |
308 | 310 | do { |
309 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
311 | + pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).get(); | |
310 | 312 | loadedDashboards.addAll(pageData.getData()); |
311 | 313 | if (pageData.hasNext()) { |
312 | 314 | pageLink = pageData.getNextPageLink(); |
... | ... | @@ -320,96 +322,12 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { |
320 | 322 | |
321 | 323 | dashboardService.unassignCustomerDashboards(tenantId, customerId); |
322 | 324 | |
323 | - pageLink = new TextPageLink(42); | |
324 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
325 | + pageLink = new TimePageLink(42); | |
326 | + pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).get(); | |
325 | 327 | Assert.assertFalse(pageData.hasNext()); |
326 | 328 | Assert.assertTrue(pageData.getData().isEmpty()); |
327 | 329 | |
328 | 330 | tenantService.deleteTenant(tenantId); |
329 | 331 | } |
330 | - | |
331 | - @Test | |
332 | - public void testFindDashboardsByTenantIdCustomerIdAndTitle() { | |
333 | - | |
334 | - Customer customer = new Customer(); | |
335 | - customer.setTitle("Test customer"); | |
336 | - customer.setTenantId(tenantId); | |
337 | - customer = customerService.saveCustomer(customer); | |
338 | - CustomerId customerId = customer.getId(); | |
339 | - | |
340 | - String title1 = "Dashboard title 1"; | |
341 | - List<DashboardInfo> dashboardsTitle1 = new ArrayList<>(); | |
342 | - for (int i=0;i<124;i++) { | |
343 | - Dashboard dashboard = new Dashboard(); | |
344 | - dashboard.setTenantId(tenantId); | |
345 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); | |
346 | - String title = title1+suffix; | |
347 | - title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); | |
348 | - dashboard.setTitle(title); | |
349 | - dashboard = dashboardService.saveDashboard(dashboard); | |
350 | - dashboardsTitle1.add(new DashboardInfo(dashboardService.assignDashboardToCustomer(dashboard.getId(), customerId))); | |
351 | - } | |
352 | - String title2 = "Dashboard title 2"; | |
353 | - List<DashboardInfo> dashboardsTitle2 = new ArrayList<>(); | |
354 | - for (int i=0;i<151;i++) { | |
355 | - Dashboard dashboard = new Dashboard(); | |
356 | - dashboard.setTenantId(tenantId); | |
357 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); | |
358 | - String title = title2+suffix; | |
359 | - title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); | |
360 | - dashboard.setTitle(title); | |
361 | - dashboard = dashboardService.saveDashboard(dashboard); | |
362 | - dashboardsTitle2.add(new DashboardInfo(dashboardService.assignDashboardToCustomer(dashboard.getId(), customerId))); | |
363 | - } | |
364 | - | |
365 | - List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>(); | |
366 | - TextPageLink pageLink = new TextPageLink(24, title1); | |
367 | - TextPageData<DashboardInfo> pageData = null; | |
368 | - do { | |
369 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
370 | - loadedDashboardsTitle1.addAll(pageData.getData()); | |
371 | - if (pageData.hasNext()) { | |
372 | - pageLink = pageData.getNextPageLink(); | |
373 | - } | |
374 | - } while (pageData.hasNext()); | |
375 | - | |
376 | - Collections.sort(dashboardsTitle1, idComparator); | |
377 | - Collections.sort(loadedDashboardsTitle1, idComparator); | |
378 | - | |
379 | - Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1); | |
380 | - | |
381 | - List<DashboardInfo> loadedDashboardsTitle2 = new ArrayList<>(); | |
382 | - pageLink = new TextPageLink(4, title2); | |
383 | - do { | |
384 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
385 | - loadedDashboardsTitle2.addAll(pageData.getData()); | |
386 | - if (pageData.hasNext()) { | |
387 | - pageLink = pageData.getNextPageLink(); | |
388 | - } | |
389 | - } while (pageData.hasNext()); | |
390 | 332 | |
391 | - Collections.sort(dashboardsTitle2, idComparator); | |
392 | - Collections.sort(loadedDashboardsTitle2, idComparator); | |
393 | - | |
394 | - Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2); | |
395 | - | |
396 | - for (DashboardInfo dashboard : loadedDashboardsTitle1) { | |
397 | - dashboardService.deleteDashboard(dashboard.getId()); | |
398 | - } | |
399 | - | |
400 | - pageLink = new TextPageLink(4, title1); | |
401 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
402 | - Assert.assertFalse(pageData.hasNext()); | |
403 | - Assert.assertEquals(0, pageData.getData().size()); | |
404 | - | |
405 | - for (DashboardInfo dashboard : loadedDashboardsTitle2) { | |
406 | - dashboardService.deleteDashboard(dashboard.getId()); | |
407 | - } | |
408 | - | |
409 | - pageLink = new TextPageLink(4, title2); | |
410 | - pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); | |
411 | - Assert.assertFalse(pageData.hasNext()); | |
412 | - Assert.assertEquals(0, pageData.getData().size()); | |
413 | - customerService.deleteCustomer(customerId); | |
414 | - } | |
415 | 333 | } | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.sql.dashboard; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import org.junit.Assert; | |
19 | 20 | import org.junit.Test; |
20 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
21 | 22 | import org.thingsboard.server.common.data.DashboardInfo; |
... | ... | @@ -40,53 +41,26 @@ public class JpaDashboardInfoDaoTest extends AbstractJpaDaoTest { |
40 | 41 | @Test |
41 | 42 | public void testFindDashboardsByTenantId() { |
42 | 43 | UUID tenantId1 = UUIDs.timeBased(); |
43 | - UUID customerId1 = UUIDs.timeBased(); | |
44 | 44 | UUID tenantId2 = UUIDs.timeBased(); |
45 | - UUID customerId2 = UUIDs.timeBased(); | |
46 | 45 | |
47 | 46 | for (int i = 0; i < 20; i++) { |
48 | - createDashboard(tenantId1, customerId1, i); | |
49 | - createDashboard(tenantId2, customerId2, i * 2); | |
47 | + createDashboard(tenantId1, i); | |
48 | + createDashboard(tenantId2, i * 2); | |
50 | 49 | } |
51 | 50 | |
52 | 51 | TextPageLink pageLink1 = new TextPageLink(15, "DASHBOARD"); |
53 | 52 | List<DashboardInfo> dashboardInfos1 = dashboardInfoDao.findDashboardsByTenantId(tenantId1, pageLink1); |
54 | - assertEquals(15, dashboardInfos1.size()); | |
53 | + Assert.assertEquals(15, dashboardInfos1.size()); | |
55 | 54 | |
56 | 55 | TextPageLink pageLink2 = new TextPageLink(15, "DASHBOARD", dashboardInfos1.get(14).getId().getId(), null); |
57 | 56 | List<DashboardInfo> dashboardInfos2 = dashboardInfoDao.findDashboardsByTenantId(tenantId1, pageLink2); |
58 | - assertEquals(5, dashboardInfos2.size()); | |
57 | + Assert.assertEquals(5, dashboardInfos2.size()); | |
59 | 58 | } |
60 | 59 | |
61 | - @Test | |
62 | - public void testFindDashboardsByTenantAndCustomerId() { | |
63 | - UUID tenantId1 = UUIDs.timeBased(); | |
64 | - UUID customerId1 = UUIDs.timeBased(); | |
65 | - UUID tenantId2 = UUIDs.timeBased(); | |
66 | - UUID customerId2 = UUIDs.timeBased(); | |
67 | - | |
68 | - for (int i = 0; i < 20; i++) { | |
69 | - createDashboard(tenantId1, customerId1, i); | |
70 | - createDashboard(tenantId2, customerId2, i * 2); | |
71 | - } | |
72 | - | |
73 | - TextPageLink pageLink1 = new TextPageLink(15, "DASHBOARD"); | |
74 | - List<DashboardInfo> dashboardInfos1 = dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId1, customerId1, pageLink1); | |
75 | - assertEquals(15, dashboardInfos1.size()); | |
76 | - | |
77 | - TextPageLink pageLink2 = new TextPageLink(15, "DASHBOARD", dashboardInfos1.get(14).getId().getId(), null); | |
78 | - List<DashboardInfo> dashboardInfos2 = dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId1, customerId1, pageLink2); | |
79 | - assertEquals(5, dashboardInfos2.size()); | |
80 | - } | |
81 | - | |
82 | - private void assertEquals(int i, int size) { | |
83 | - } | |
84 | - | |
85 | - private void createDashboard(UUID tenantId, UUID customerId, int index) { | |
60 | + private void createDashboard(UUID tenantId, int index) { | |
86 | 61 | DashboardInfo dashboardInfo = new DashboardInfo(); |
87 | 62 | dashboardInfo.setId(new DashboardId(UUIDs.timeBased())); |
88 | 63 | dashboardInfo.setTenantId(new TenantId(tenantId)); |
89 | - dashboardInfo.setCustomerId(new CustomerId(customerId)); | |
90 | 64 | dashboardInfo.setTitle("DASHBOARD_" + index); |
91 | 65 | dashboardInfoDao.save(dashboardInfo); |
92 | 66 | } | ... | ... |