Commit 7e8c90ec6d4cf1ebd32a7da2c1c71796f9286f84

Authored by Igor Kulikov
2 parents 65e971f0 194d628b

Merge branch 'master' into develop/3.0

... ... @@ -120,7 +120,9 @@ public class AlarmController extends BaseController {
120 120 try {
121 121 AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
122 122 Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
123   - alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, System.currentTimeMillis()).get();
  123 + long ackTs = System.currentTimeMillis();
  124 + alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, ackTs).get();
  125 + alarm.setAckTs(ackTs);
124 126 logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null);
125 127 } catch (Exception e) {
126 128 throw handleException(e);
... ... @@ -135,7 +137,9 @@ public class AlarmController extends BaseController {
135 137 try {
136 138 AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
137 139 Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
138   - alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, System.currentTimeMillis()).get();
  140 + long clearTs = System.currentTimeMillis();
  141 + alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, clearTs).get();
  142 + alarm.setClearTs(clearTs);
139 143 logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null);
140 144 } catch (Exception e) {
141 145 throw handleException(e);
... ...
... ... @@ -24,13 +24,11 @@ import org.springframework.web.bind.annotation.RequestParam;
24 24 import org.springframework.web.bind.annotation.ResponseBody;
25 25 import org.springframework.web.bind.annotation.ResponseStatus;
26 26 import org.springframework.web.bind.annotation.RestController;
27   -import org.thingsboard.server.common.data.alarm.Alarm;
28 27 import org.thingsboard.server.common.data.audit.ActionType;
29 28 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
30 29 import org.thingsboard.server.common.data.exception.ThingsboardException;
31 30 import org.thingsboard.server.common.data.id.EntityId;
32 31 import org.thingsboard.server.common.data.id.EntityIdFactory;
33   -import org.thingsboard.server.common.data.id.UUIDBased;
34 32 import org.thingsboard.server.common.data.relation.EntityRelation;
35 33 import org.thingsboard.server.common.data.relation.EntityRelationInfo;
36 34 import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
... ... @@ -38,6 +36,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
38 36 import org.thingsboard.server.service.security.permission.Operation;
39 37
40 38 import java.util.List;
  39 +import java.util.stream.Collectors;
41 40
42 41
43 42 @RestController
... ... @@ -167,7 +166,7 @@ public class EntityRelationController extends BaseController {
167 166 checkEntityId(entityId, Operation.READ);
168 167 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
169 168 try {
170   - return checkNotNull(relationService.findByFrom(getTenantId(), entityId, typeGroup));
  169 + return checkNotNull(filterRelationsByReadPermission(relationService.findByFrom(getTenantId(), entityId, typeGroup)));
171 170 } catch (Exception e) {
172 171 throw handleException(e);
173 172 }
... ... @@ -185,7 +184,7 @@ public class EntityRelationController extends BaseController {
185 184 checkEntityId(entityId, Operation.READ);
186 185 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
187 186 try {
188   - return checkNotNull(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get());
  187 + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get()));
189 188 } catch (Exception e) {
190 189 throw handleException(e);
191 190 }
... ... @@ -205,7 +204,7 @@ public class EntityRelationController extends BaseController {
205 204 checkEntityId(entityId, Operation.READ);
206 205 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
207 206 try {
208   - return checkNotNull(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup));
  207 + return checkNotNull(filterRelationsByReadPermission(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup)));
209 208 } catch (Exception e) {
210 209 throw handleException(e);
211 210 }
... ... @@ -223,7 +222,7 @@ public class EntityRelationController extends BaseController {
223 222 checkEntityId(entityId, Operation.READ);
224 223 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
225 224 try {
226   - return checkNotNull(relationService.findByTo(getTenantId(), entityId, typeGroup));
  225 + return checkNotNull(filterRelationsByReadPermission(relationService.findByTo(getTenantId(), entityId, typeGroup)));
227 226 } catch (Exception e) {
228 227 throw handleException(e);
229 228 }
... ... @@ -241,7 +240,7 @@ public class EntityRelationController extends BaseController {
241 240 checkEntityId(entityId, Operation.READ);
242 241 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
243 242 try {
244   - return checkNotNull(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get());
  243 + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get()));
245 244 } catch (Exception e) {
246 245 throw handleException(e);
247 246 }
... ... @@ -261,7 +260,7 @@ public class EntityRelationController extends BaseController {
261 260 checkEntityId(entityId, Operation.READ);
262 261 RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
263 262 try {
264   - return checkNotNull(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup));
  263 + return checkNotNull(filterRelationsByReadPermission(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup)));
265 264 } catch (Exception e) {
266 265 throw handleException(e);
267 266 }
... ... @@ -276,7 +275,7 @@ public class EntityRelationController extends BaseController {
276 275 checkNotNull(query.getFilters());
277 276 checkEntityId(query.getParameters().getEntityId(), Operation.READ);
278 277 try {
279   - return checkNotNull(relationService.findByQuery(getTenantId(), query).get());
  278 + return checkNotNull(filterRelationsByReadPermission(relationService.findByQuery(getTenantId(), query).get()));
280 279 } catch (Exception e) {
281 280 throw handleException(e);
282 281 }
... ... @@ -291,12 +290,28 @@ public class EntityRelationController extends BaseController {
291 290 checkNotNull(query.getFilters());
292 291 checkEntityId(query.getParameters().getEntityId(), Operation.READ);
293 292 try {
294   - return checkNotNull(relationService.findInfoByQuery(getTenantId(), query).get());
  293 + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByQuery(getTenantId(), query).get()));
295 294 } catch (Exception e) {
296 295 throw handleException(e);
297 296 }
298 297 }
299 298
  299 + private <T extends EntityRelation> List<T> filterRelationsByReadPermission(List<T> relationsByQuery) {
  300 + return relationsByQuery.stream().filter(relationByQuery -> {
  301 + try {
  302 + checkEntityId(relationByQuery.getTo(), Operation.READ);
  303 + } catch (ThingsboardException e) {
  304 + return false;
  305 + }
  306 + try {
  307 + checkEntityId(relationByQuery.getFrom(), Operation.READ);
  308 + } catch (ThingsboardException e) {
  309 + return false;
  310 + }
  311 + return true;
  312 + }).collect(Collectors.toList());
  313 + }
  314 +
300 315 private RelationTypeGroup parseRelationTypeGroup(String strRelationTypeGroup, RelationTypeGroup defaultValue) {
301 316 RelationTypeGroup result = defaultValue;
302 317 if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length() > 0) {
... ...
... ... @@ -39,7 +39,7 @@ public interface AlarmService {
39 39
40 40 ListenableFuture<Boolean> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs);
41 41
42   - ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long ackTs);
  42 + ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs);
43 43
44 44 ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId);
45 45
... ...
... ... @@ -407,8 +407,12 @@ final class MqttClientImpl implements MqttClient {
407 407 }
408 408
409 409 private MqttMessageIdVariableHeader getNewMessageId() {
410   - this.nextMessageId.compareAndSet(0xffff, 1);
411   - return MqttMessageIdVariableHeader.from(this.nextMessageId.getAndIncrement());
  410 + int messageId;
  411 + synchronized (this.nextMessageId) {
  412 + this.nextMessageId.compareAndSet(0xffff, 1);
  413 + messageId = this.nextMessageId.getAndIncrement();
  414 + }
  415 + return MqttMessageIdVariableHeader.from(messageId);
412 416 }
413 417
414 418 private Future<Void> createSubscription(String topic, MqttHandler handler, boolean once, MqttQoS qos) {
... ...
... ... @@ -55,7 +55,7 @@ while :
55 55 echo "Done"
56 56 exit 0
57 57 ;;
58   - [yY]|[yY][eE]|[yY][eE]|[sS]|[yY]|"")
  58 + [yY]|[yY][eE]|[yY][eE][sS]|"")
59 59 echo "Cleaning up files"
60 60 rm -rf $CLIENT_FILE_PREFIX.jks
61 61 rm -rf $CLIENT_FILE_PREFIX.pub.pem
... ...
... ... @@ -71,7 +71,7 @@ while :
71 71 echo "Done"
72 72 exit 0
73 73 ;;
74   - [yY]|[yY][eE]|[yY][eE]|[sS]|[yY]|"")
  74 + [yY]|[yY][eE]|[yY][eE][sS]|"")
75 75 echo "Cleaning up files"
76 76 rm -rf $SERVER_FILE_PREFIX.jks
77 77 rm -rf $SERVER_FILE_PREFIX.pub.pem
... ... @@ -129,7 +129,7 @@ if [[ $COPY = true ]]; then
129 129 [nN]|[nN][oO])
130 130 break
131 131 ;;
132   - [yY]|[yY][eE]|[yY][eE]|[sS]|[yY]|"")
  132 + [yY]|[yY][eE]|[yY][eE][sS]|"")
133 133 read -p "(Default: $SERVER_KEYSTORE_DIR): " dir
134 134 if [[ ! -z $dir ]]; then
135 135 DESTINATION=$dir;
... ...
... ... @@ -616,7 +616,7 @@ export default class TbMapWidgetV2 {
616 616 locationChanged = true;
617 617 }
618 618 }
619   - } else {
  619 + } else if (latData.length > 0 && lngData.length > 0) {
620 620 // Create or update marker
621 621 lat = latData[latData.length - 1][1];
622 622 lng = lngData[lngData.length - 1][1];
... ...
... ... @@ -31,10 +31,6 @@ tb-timeseries-table-widget {
31 31 z-index: 10;
32 32 }
33 33
34   - md-table-container {
35   - overflow-x: visible;
36   - }
37   -
38 34 md-tabs:not(.md-no-tab-content):not(.md-dynamic-height) {
39 35 min-height: 0;
40 36 }
... ...
... ... @@ -38,56 +38,58 @@
38 38 </div>
39 39 </md-toolbar>
40 40
41   - <md-tabs flex md-selected="vm.sourceIndex" ng-class="{'tb-headless': vm.sources.length === 1}"
  41 + <md-tabs md-selected="vm.sourceIndex" ng-class="{'tb-headless': vm.sources.length === 1}"
42 42 id="tabs" md-border-bottom flex>
43 43 <md-tab ng-repeat="source in vm.sources" label="{{ source.datasource.name }}">
44   - <md-table-container class="flex">
45   - <table md-table>
46   - <thead fix-head md-head md-order="source.query.order" md-on-reorder="vm.onReorder(source)">
47   - <tr md-row>
48   - <th ng-show="vm.showTimestamp"
49   - md-column md-order-by="0"
50   - >
51   - <span>Timestamp</span>
52   - </th>
53   - <th md-column
54   - md-order-by="{{ h.index }}"
55   - ng-repeat="h in source.ts.header"
56   - >
57   - <span>{{ h.dataKey.label }}</span>
58   - </th>
59   - </tr>
60   - </thead>
  44 + <div class="tb-absolute-fill" layout="column">
  45 + <md-table-container flex>
  46 + <table md-table>
  47 + <thead fix-head md-head md-order="source.query.order" md-on-reorder="vm.onReorder(source)">
  48 + <tr md-row>
  49 + <th ng-show="vm.showTimestamp"
  50 + md-column md-order-by="0"
  51 + >
  52 + <span>Timestamp</span>
  53 + </th>
  54 + <th md-column
  55 + md-order-by="{{ h.index }}"
  56 + ng-repeat="h in source.ts.header"
  57 + >
  58 + <span>{{ h.dataKey.label }}</span>
  59 + </th>
  60 + </tr>
  61 + </thead>
61 62
62   - <tbody md-body>
63   - <tr md-row ng-repeat="row in source.ts.data track by $index" ng-click="vm.onRowClick($event, row)">
64   - <td ng-show="$index > 0 || ($index === 0 && vm.showTimestamp)"
65   - md-cell
66   - ng-repeat="d in row track by $index"
67   - ng-style="vm.cellStyle(source, $index, d)"
68   - ng-bind-html="vm.cellContent(source, $index, row, d)"
69   - ></td>
70   - <td md-cell class="tb-action-cell"
71   - ng-style="{minWidth: vm.actionCellDescriptors.length*36+'px',
72   - maxWidth: vm.actionCellDescriptors.length*36+'px',
73   - width: vm.actionCellDescriptors.length*36+'px'}">
74   - <md-button class="md-icon-button" ng-repeat="actionDescriptor in vm.actionCellDescriptors"
75   - aria-label="{{ actionDescriptor.displayName }}"
76   - ng-click="vm.onActionButtonClick($event, row, actionDescriptor)" ng-disabled="$root.loading">
77   - <md-icon aria-label="{{ actionDescriptor.displayName }}" class="material-icons">{{actionDescriptor.icon}}</md-icon>
78   - <md-tooltip md-direction="top">
79   - {{ actionDescriptor.displayName }}
80   - </md-tooltip>
81   - </md-button>
82   - </td>
83   - </tr>
84   - </tbody>
85   - </table>
86   - <md-divider></md-divider>
87   - <span ng-show="!vm.sources[vm.sourceIndex].data.length"
88   - layout-align="center center"
89   - class="no-data-found" translate>widget.no-data-found</span>
90   - </md-table-container>
  63 + <tbody md-body>
  64 + <tr md-row ng-repeat="row in source.ts.data track by $index" ng-click="vm.onRowClick($event, row)">
  65 + <td ng-show="$index > 0 || ($index === 0 && vm.showTimestamp)"
  66 + md-cell
  67 + ng-repeat="d in row track by $index"
  68 + ng-style="vm.cellStyle(source, $index, d)"
  69 + ng-bind-html="vm.cellContent(source, $index, row, d)"
  70 + ></td>
  71 + <td md-cell class="tb-action-cell"
  72 + ng-style="{minWidth: vm.actionCellDescriptors.length*36+'px',
  73 + maxWidth: vm.actionCellDescriptors.length*36+'px',
  74 + width: vm.actionCellDescriptors.length*36+'px'}">
  75 + <md-button class="md-icon-button" ng-repeat="actionDescriptor in vm.actionCellDescriptors"
  76 + aria-label="{{ actionDescriptor.displayName }}"
  77 + ng-click="vm.onActionButtonClick($event, row, actionDescriptor)" ng-disabled="$root.loading">
  78 + <md-icon aria-label="{{ actionDescriptor.displayName }}" class="material-icons">{{actionDescriptor.icon}}</md-icon>
  79 + <md-tooltip md-direction="top">
  80 + {{ actionDescriptor.displayName }}
  81 + </md-tooltip>
  82 + </md-button>
  83 + </td>
  84 + </tr>
  85 + </tbody>
  86 + </table>
  87 + <md-divider></md-divider>
  88 + <span ng-show="!vm.sources[vm.sourceIndex].data.length"
  89 + layout-align="center center"
  90 + class="no-data-found" translate>widget.no-data-found</span>
  91 + </md-table-container>
  92 + </div>
91 93 </md-tab>
92 94 </md-tabs>
93 95 <md-table-pagination ng-if="vm.displayPagination"
... ...