Commit f1fb0cedae51eb129e24b69a8b2ad44e2b57e463
1 parent
9c44920f
Add audit log details for telemetry deleted and telemetry updated types
Showing
8 changed files
with
61 additions
and
12 deletions
@@ -716,6 +716,9 @@ public abstract class BaseController { | @@ -716,6 +716,9 @@ public abstract class BaseController { | ||
716 | case TIMESERIES_UPDATED: | 716 | case TIMESERIES_UPDATED: |
717 | msgType = DataConstants.TIMESERIES_UPDATED; | 717 | msgType = DataConstants.TIMESERIES_UPDATED; |
718 | break; | 718 | break; |
719 | + case TIMESERIES_DELETED: | ||
720 | + msgType = DataConstants.TIMESERIES_DELETED; | ||
721 | + break; | ||
719 | } | 722 | } |
720 | if (!StringUtils.isEmpty(msgType)) { | 723 | if (!StringUtils.isEmpty(msgType)) { |
721 | try { | 724 | try { |
@@ -774,6 +777,14 @@ public abstract class BaseController { | @@ -774,6 +777,14 @@ public abstract class BaseController { | ||
774 | } else if (actionType == ActionType.TIMESERIES_UPDATED) { | 777 | } else if (actionType == ActionType.TIMESERIES_UPDATED) { |
775 | List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); | 778 | List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); |
776 | addTimeseries(entityNode, timeseries); | 779 | addTimeseries(entityNode, timeseries); |
780 | + } else if (actionType == ActionType.TIMESERIES_DELETED) { | ||
781 | + List<String> keys = extractParameter(List.class, 0, additionalInfo); | ||
782 | + if (keys != null) { | ||
783 | + ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); | ||
784 | + keys.forEach(timeseriesArrayNode::add); | ||
785 | + } | ||
786 | + entityNode.put("startTs", extractParameter(Long.class, 1, additionalInfo)); | ||
787 | + entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); | ||
777 | } | 788 | } |
778 | } | 789 | } |
779 | TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); | 790 | TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); |
@@ -298,7 +298,6 @@ public class TelemetryController extends BaseController { | @@ -298,7 +298,6 @@ public class TelemetryController extends BaseController { | ||
298 | deleteToTs = System.currentTimeMillis(); | 298 | deleteToTs = System.currentTimeMillis(); |
299 | } else { | 299 | } else { |
300 | if (startTs == null || endTs == null) { | 300 | if (startTs == null || endTs == null) { |
301 | - deleteToTs = endTs; | ||
302 | return getImmediateDeferredResult("When deleteAllDataForKeys is false, start and end timestamp values shouldn't be empty", HttpStatus.BAD_REQUEST); | 301 | return getImmediateDeferredResult("When deleteAllDataForKeys is false, start and end timestamp values shouldn't be empty", HttpStatus.BAD_REQUEST); |
303 | } else { | 302 | } else { |
304 | deleteFromTs = startTs; | 303 | deleteFromTs = startTs; |
@@ -316,13 +315,13 @@ public class TelemetryController extends BaseController { | @@ -316,13 +315,13 @@ public class TelemetryController extends BaseController { | ||
316 | Futures.addCallback(future, new FutureCallback<List<Void>>() { | 315 | Futures.addCallback(future, new FutureCallback<List<Void>>() { |
317 | @Override | 316 | @Override |
318 | public void onSuccess(@Nullable List<Void> tmp) { | 317 | public void onSuccess(@Nullable List<Void> tmp) { |
319 | - logTimeseriesDeleted(user, entityId, keys, null); | 318 | + logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); |
320 | result.setResult(new ResponseEntity<>(HttpStatus.OK)); | 319 | result.setResult(new ResponseEntity<>(HttpStatus.OK)); |
321 | } | 320 | } |
322 | 321 | ||
323 | @Override | 322 | @Override |
324 | public void onFailure(Throwable t) { | 323 | public void onFailure(Throwable t) { |
325 | - logTimeseriesDeleted(user, entityId, keys, t); | 324 | + logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, t); |
326 | result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); | 325 | result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); |
327 | } | 326 | } |
328 | }, executor); | 327 | }, executor); |
@@ -443,6 +442,7 @@ public class TelemetryController extends BaseController { | @@ -443,6 +442,7 @@ public class TelemetryController extends BaseController { | ||
443 | if (entries.isEmpty()) { | 442 | if (entries.isEmpty()) { |
444 | return getImmediateDeferredResult("No timeseries data found in request body!", HttpStatus.BAD_REQUEST); | 443 | return getImmediateDeferredResult("No timeseries data found in request body!", HttpStatus.BAD_REQUEST); |
445 | } | 444 | } |
445 | + SecurityUser user = getCurrentUser(); | ||
446 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_TELEMETRY, entityIdSrc, (result, tenantId, entityId) -> { | 446 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_TELEMETRY, entityIdSrc, (result, tenantId, entityId) -> { |
447 | long tenantTtl = ttl; | 447 | long tenantTtl = ttl; |
448 | if (!TenantId.SYS_TENANT_ID.equals(tenantId) && tenantTtl == 0) { | 448 | if (!TenantId.SYS_TENANT_ID.equals(tenantId) && tenantTtl == 0) { |
@@ -590,10 +590,10 @@ public class TelemetryController extends BaseController { | @@ -590,10 +590,10 @@ public class TelemetryController extends BaseController { | ||
590 | }; | 590 | }; |
591 | } | 591 | } |
592 | 592 | ||
593 | - private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, Throwable e) { | 593 | + private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, long startTs, long endTs, Throwable e) { |
594 | try { | 594 | try { |
595 | logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e), | 595 | logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e), |
596 | - keys); | 596 | + keys, startTs, endTs); |
597 | } catch (ThingsboardException te) { | 597 | } catch (ThingsboardException te) { |
598 | log.warn("Failed to log timeseries delete", te); | 598 | log.warn("Failed to log timeseries delete", te); |
599 | } | 599 | } |
@@ -60,6 +60,7 @@ public class DataConstants { | @@ -60,6 +60,7 @@ public class DataConstants { | ||
60 | public static final String ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED"; | 60 | public static final String ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED"; |
61 | public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; | 61 | public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; |
62 | public static final String TIMESERIES_UPDATED = "TIMESERIES_UPDATED"; | 62 | public static final String TIMESERIES_UPDATED = "TIMESERIES_UPDATED"; |
63 | + public static final String TIMESERIES_DELETED = "TIMESERIES_DELETED"; | ||
63 | public static final String ALARM_ACK = "ALARM_ACK"; | 64 | public static final String ALARM_ACK = "ALARM_ACK"; |
64 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; | 65 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; |
65 | public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; | 66 | public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; |
@@ -24,8 +24,8 @@ public enum ActionType { | @@ -24,8 +24,8 @@ public enum ActionType { | ||
24 | UPDATED(false), // log entity | 24 | UPDATED(false), // log entity |
25 | ATTRIBUTES_UPDATED(false), // log attributes/values | 25 | ATTRIBUTES_UPDATED(false), // log attributes/values |
26 | ATTRIBUTES_DELETED(false), // log attributes | 26 | ATTRIBUTES_DELETED(false), // log attributes |
27 | - TIMESERIES_DELETED(false), // log timeseries | ||
28 | TIMESERIES_UPDATED(false), // log timeseries update | 27 | TIMESERIES_UPDATED(false), // log timeseries update |
28 | + TIMESERIES_DELETED(false), // log timeseries | ||
29 | RPC_CALL(false), // log method and params | 29 | RPC_CALL(false), // log method and params |
30 | CREDENTIALS_UPDATED(false), // log new credentials | 30 | CREDENTIALS_UPDATED(false), // log new credentials |
31 | ASSIGNED_TO_CUSTOMER(false), // log customer name | 31 | ASSIGNED_TO_CUSTOMER(false), // log customer name |
@@ -39,21 +39,23 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -39,21 +39,23 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
39 | import org.thingsboard.server.common.data.id.TenantId; | 39 | import org.thingsboard.server.common.data.id.TenantId; |
40 | import org.thingsboard.server.common.data.id.UserId; | 40 | import org.thingsboard.server.common.data.id.UserId; |
41 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 41 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
42 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
42 | import org.thingsboard.server.common.data.page.PageData; | 43 | import org.thingsboard.server.common.data.page.PageData; |
43 | import org.thingsboard.server.common.data.page.TimePageLink; | 44 | import org.thingsboard.server.common.data.page.TimePageLink; |
44 | import org.thingsboard.server.common.data.relation.EntityRelation; | 45 | import org.thingsboard.server.common.data.relation.EntityRelation; |
45 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; | 46 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
46 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 47 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
47 | import org.thingsboard.server.dao.audit.sink.AuditLogSink; | 48 | import org.thingsboard.server.dao.audit.sink.AuditLogSink; |
49 | +import org.thingsboard.server.dao.device.provision.ProvisionRequest; | ||
48 | import org.thingsboard.server.dao.entity.EntityService; | 50 | import org.thingsboard.server.dao.entity.EntityService; |
49 | import org.thingsboard.server.dao.exception.DataValidationException; | 51 | import org.thingsboard.server.dao.exception.DataValidationException; |
50 | -import org.thingsboard.server.dao.device.provision.ProvisionRequest; | ||
51 | import org.thingsboard.server.dao.service.DataValidator; | 52 | import org.thingsboard.server.dao.service.DataValidator; |
52 | 53 | ||
53 | import java.io.PrintWriter; | 54 | import java.io.PrintWriter; |
54 | import java.io.StringWriter; | 55 | import java.io.StringWriter; |
55 | import java.util.List; | 56 | import java.util.List; |
56 | import java.util.UUID; | 57 | import java.util.UUID; |
58 | +import java.util.stream.Collectors; | ||
57 | 59 | ||
58 | import static org.thingsboard.server.dao.service.Validator.validateEntityId; | 60 | import static org.thingsboard.server.dao.service.Validator.validateEntityId; |
59 | import static org.thingsboard.server.dao.service.Validator.validateId; | 61 | import static org.thingsboard.server.dao.service.Validator.validateId; |
@@ -265,6 +267,32 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -265,6 +267,32 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
265 | actionData.set("provisionRequest", objectMapper.valueToTree(request)); | 267 | actionData.set("provisionRequest", objectMapper.valueToTree(request)); |
266 | } | 268 | } |
267 | break; | 269 | break; |
270 | + case TIMESERIES_UPDATED: | ||
271 | + actionData.put("entityId", entityId.toString()); | ||
272 | + List<TsKvEntry> updatedTimeseries = extractParameter(List.class, 0, additionalInfo); | ||
273 | + if (updatedTimeseries != null) { | ||
274 | + ArrayNode result = actionData.putArray("timeseries"); | ||
275 | + updatedTimeseries.stream() | ||
276 | + .collect(Collectors.groupingBy(TsKvEntry::getTs)) | ||
277 | + .forEach((k, v) -> { | ||
278 | + ObjectNode element = objectMapper.createObjectNode(); | ||
279 | + element.put("ts", k); | ||
280 | + ObjectNode values = element.putObject("values"); | ||
281 | + v.forEach(kvEntry -> values.put(kvEntry.getKey(), kvEntry.getValueAsString())); | ||
282 | + result.add(element); | ||
283 | + }); | ||
284 | + } | ||
285 | + break; | ||
286 | + case TIMESERIES_DELETED: | ||
287 | + actionData.put("entityId", entityId.toString()); | ||
288 | + List<String> timeseriesKeys = extractParameter(List.class, 0, additionalInfo); | ||
289 | + if (timeseriesKeys != null) { | ||
290 | + ArrayNode timeseriesArrayNode = actionData.putArray("timeseries"); | ||
291 | + timeseriesKeys.forEach(timeseriesArrayNode::add); | ||
292 | + } | ||
293 | + actionData.put("startTs", extractParameter(Long.class, 1, additionalInfo)); | ||
294 | + actionData.put("endTs", extractParameter(Long.class, 2, additionalInfo)); | ||
295 | + break; | ||
268 | } | 296 | } |
269 | return actionData; | 297 | return actionData; |
270 | } | 298 | } |
@@ -35,7 +35,8 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | @@ -35,7 +35,8 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
35 | configClazz = EmptyNodeConfiguration.class, | 35 | configClazz = EmptyNodeConfiguration.class, |
36 | relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", | 36 | relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", |
37 | "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", | 37 | "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", |
38 | - "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", "Timeseries Updated"}, | 38 | + "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", |
39 | + "Timeseries Updated", "Timeseries Deleted"}, | ||
39 | nodeDescription = "Route incoming messages by Message Type", | 40 | nodeDescription = "Route incoming messages by Message Type", |
40 | nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", | 41 | nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", |
41 | uiResources = {"static/rulenode/rulenode-core-config.js"}, | 42 | uiResources = {"static/rulenode/rulenode-core-config.js"}, |
@@ -91,7 +92,9 @@ public class TbMsgTypeSwitchNode implements TbNode { | @@ -91,7 +92,9 @@ public class TbMsgTypeSwitchNode implements TbNode { | ||
91 | } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) { | 92 | } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) { |
92 | relationType = "Entity Assigned To Tenant"; | 93 | relationType = "Entity Assigned To Tenant"; |
93 | } else if (msg.getType().equals(DataConstants.TIMESERIES_UPDATED)) { | 94 | } else if (msg.getType().equals(DataConstants.TIMESERIES_UPDATED)) { |
94 | - relationType = "Timeseries updated"; | 95 | + relationType = "Timeseries Updated"; |
96 | + } else if (msg.getType().equals(DataConstants.TIMESERIES_DELETED)) { | ||
97 | + relationType = "Timeseries Deleted"; | ||
95 | } else { | 98 | } else { |
96 | relationType = "Other"; | 99 | relationType = "Other"; |
97 | } | 100 | } |
@@ -53,7 +53,9 @@ export enum ActionType { | @@ -53,7 +53,9 @@ export enum ActionType { | ||
53 | ASSIGNED_FROM_TENANT = 'ASSIGNED_FROM_TENANT', | 53 | ASSIGNED_FROM_TENANT = 'ASSIGNED_FROM_TENANT', |
54 | ASSIGNED_TO_TENANT = 'ASSIGNED_TO_TENANT', | 54 | ASSIGNED_TO_TENANT = 'ASSIGNED_TO_TENANT', |
55 | PROVISION_SUCCESS = 'PROVISION_SUCCESS', | 55 | PROVISION_SUCCESS = 'PROVISION_SUCCESS', |
56 | - PROVISION_FAILURE = 'PROVISION_FAILURE' | 56 | + PROVISION_FAILURE = 'PROVISION_FAILURE', |
57 | + TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', | ||
58 | + TIMESERIES_DELETED = 'TIMESERIES_DELETED' | ||
57 | } | 59 | } |
58 | 60 | ||
59 | export enum ActionStatus { | 61 | export enum ActionStatus { |
@@ -87,7 +89,9 @@ export const actionTypeTranslations = new Map<ActionType, string>( | @@ -87,7 +89,9 @@ export const actionTypeTranslations = new Map<ActionType, string>( | ||
87 | [ActionType.ASSIGNED_FROM_TENANT, 'audit-log.type-assigned-from-tenant'], | 89 | [ActionType.ASSIGNED_FROM_TENANT, 'audit-log.type-assigned-from-tenant'], |
88 | [ActionType.ASSIGNED_TO_TENANT, 'audit-log.type-assigned-to-tenant'], | 90 | [ActionType.ASSIGNED_TO_TENANT, 'audit-log.type-assigned-to-tenant'], |
89 | [ActionType.PROVISION_SUCCESS, 'audit-log.type-provision-success'], | 91 | [ActionType.PROVISION_SUCCESS, 'audit-log.type-provision-success'], |
90 | - [ActionType.PROVISION_FAILURE, 'audit-log.type-provision-failure'] | 92 | + [ActionType.PROVISION_FAILURE, 'audit-log.type-provision-failure'], |
93 | + [ActionType.TIMESERIES_UPDATED, 'audit-log.type-timeseries-updated'], | ||
94 | + [ActionType.TIMESERIES_DELETED, 'audit-log.type-timeseries-deleted'] | ||
91 | ] | 95 | ] |
92 | ); | 96 | ); |
93 | 97 |
@@ -527,7 +527,9 @@ | @@ -527,7 +527,9 @@ | ||
527 | "type-assigned-from-tenant": "Assigned from Tenant", | 527 | "type-assigned-from-tenant": "Assigned from Tenant", |
528 | "type-assigned-to-tenant": "Assigned to Tenant", | 528 | "type-assigned-to-tenant": "Assigned to Tenant", |
529 | "type-provision-success": "Device provisioned", | 529 | "type-provision-success": "Device provisioned", |
530 | - "type-provision-failure": "Device provisioning was failed" | 530 | + "type-provision-failure": "Device provisioning was failed", |
531 | + "type-timeseries-updated": "Telemetry updated", | ||
532 | + "type-timeseries-deleted": "Telemetry deleted" | ||
531 | }, | 533 | }, |
532 | "confirm-on-exit": { | 534 | "confirm-on-exit": { |
533 | "message": "You have unsaved changes. Are you sure you want to leave this page?", | 535 | "message": "You have unsaved changes. Are you sure you want to leave this page?", |