Commit 23b21b29128230673bc8cc89a1e32410d022174f
1 parent
ead30d70
Added get by user id and customer id
Improved partitions query
Showing
15 changed files
with
562 additions
and
102 deletions
@@ -18,20 +18,64 @@ package org.thingsboard.server.controller; | @@ -18,20 +18,64 @@ package org.thingsboard.server.controller; | ||
18 | import org.springframework.security.access.prepost.PreAuthorize; | 18 | import org.springframework.security.access.prepost.PreAuthorize; |
19 | import org.springframework.web.bind.annotation.*; | 19 | import org.springframework.web.bind.annotation.*; |
20 | import org.thingsboard.server.common.data.audit.AuditLog; | 20 | import org.thingsboard.server.common.data.audit.AuditLog; |
21 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
21 | import org.thingsboard.server.common.data.id.EntityIdFactory; | 22 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
22 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | +import org.thingsboard.server.common.data.id.UserId; | ||
23 | import org.thingsboard.server.common.data.page.TimePageData; | 25 | import org.thingsboard.server.common.data.page.TimePageData; |
24 | import org.thingsboard.server.common.data.page.TimePageLink; | 26 | import org.thingsboard.server.common.data.page.TimePageLink; |
25 | import org.thingsboard.server.exception.ThingsboardException; | 27 | import org.thingsboard.server.exception.ThingsboardException; |
26 | 28 | ||
29 | +import java.util.UUID; | ||
30 | + | ||
27 | @RestController | 31 | @RestController |
28 | @RequestMapping("/api") | 32 | @RequestMapping("/api") |
29 | public class AuditLogController extends BaseController { | 33 | public class AuditLogController extends BaseController { |
30 | 34 | ||
31 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") | 35 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
32 | - @RequestMapping(value = "/audit/logs/{entityType}/{entityId}", params = {"limit"}, method = RequestMethod.GET) | 36 | + @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"limit"}, method = RequestMethod.GET) |
33 | @ResponseBody | 37 | @ResponseBody |
34 | - public TimePageData<AuditLog> getAuditLogs( | 38 | + public TimePageData<AuditLog> getAuditLogsByCustomerId( |
39 | + @PathVariable("customerId") String strCustomerId, | ||
40 | + @RequestParam int limit, | ||
41 | + @RequestParam(required = false) Long startTime, | ||
42 | + @RequestParam(required = false) Long endTime, | ||
43 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | ||
44 | + @RequestParam(required = false) String offset) throws ThingsboardException { | ||
45 | + try { | ||
46 | + checkParameter("CustomerId", strCustomerId); | ||
47 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
48 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | ||
49 | + return checkNotNull(auditLogService.findAuditLogsByTenantIdAndCustomerId(tenantId, new CustomerId(UUID.fromString(strCustomerId)), pageLink)); | ||
50 | + } catch (Exception e) { | ||
51 | + throw handleException(e); | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
56 | + @RequestMapping(value = "/audit/logs/user/{userId}", params = {"limit"}, method = RequestMethod.GET) | ||
57 | + @ResponseBody | ||
58 | + public TimePageData<AuditLog> getAuditLogsByUserId( | ||
59 | + @PathVariable("userId") String strUserId, | ||
60 | + @RequestParam int limit, | ||
61 | + @RequestParam(required = false) Long startTime, | ||
62 | + @RequestParam(required = false) Long endTime, | ||
63 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | ||
64 | + @RequestParam(required = false) String offset) throws ThingsboardException { | ||
65 | + try { | ||
66 | + checkParameter("UserId", strUserId); | ||
67 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
68 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | ||
69 | + return checkNotNull(auditLogService.findAuditLogsByTenantIdAndUserId(tenantId, new UserId(UUID.fromString(strUserId)), pageLink)); | ||
70 | + } catch (Exception e) { | ||
71 | + throw handleException(e); | ||
72 | + } | ||
73 | + } | ||
74 | + | ||
75 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
76 | + @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"limit"}, method = RequestMethod.GET) | ||
77 | + @ResponseBody | ||
78 | + public TimePageData<AuditLog> getAuditLogsByEntityId( | ||
35 | @PathVariable("entityType") String strEntityType, | 79 | @PathVariable("entityType") String strEntityType, |
36 | @PathVariable("entityId") String strEntityId, | 80 | @PathVariable("entityId") String strEntityId, |
37 | @RequestParam int limit, | 81 | @RequestParam int limit, |
@@ -85,12 +85,16 @@ public class DeviceController extends BaseController { | @@ -85,12 +85,16 @@ public class DeviceController extends BaseController { | ||
85 | savedDevice.getName(), | 85 | savedDevice.getName(), |
86 | savedDevice.getType()); | 86 | savedDevice.getType()); |
87 | 87 | ||
88 | - // TODO: refactor to ANNOTATION usage | ||
89 | - if (device.getId() == null) { | ||
90 | - logDeviceAction(savedDevice, ActionType.ADDED); | ||
91 | - } else { | ||
92 | - logDeviceAction(savedDevice, ActionType.UPDATED); | ||
93 | - } | 88 | + auditLogService.logEntityAction( |
89 | + getCurrentUser(), | ||
90 | + savedDevice.getId(), | ||
91 | + savedDevice.getName(), | ||
92 | + savedDevice.getCustomerId(), | ||
93 | + device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, | ||
94 | + null, | ||
95 | + ActionStatus.SUCCESS, | ||
96 | + null); | ||
97 | + | ||
94 | 98 | ||
95 | return savedDevice; | 99 | return savedDevice; |
96 | } catch (Exception e) { | 100 | } catch (Exception e) { |
@@ -107,8 +111,15 @@ public class DeviceController extends BaseController { | @@ -107,8 +111,15 @@ public class DeviceController extends BaseController { | ||
107 | DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | 111 | DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
108 | Device device = checkDeviceId(deviceId); | 112 | Device device = checkDeviceId(deviceId); |
109 | deviceService.deleteDevice(deviceId); | 113 | deviceService.deleteDevice(deviceId); |
110 | - // TODO: refactor to ANNOTATION usage | ||
111 | - logDeviceAction(device, ActionType.DELETED); | 114 | + auditLogService.logEntityAction( |
115 | + getCurrentUser(), | ||
116 | + device.getId(), | ||
117 | + device.getName(), | ||
118 | + device.getCustomerId(), | ||
119 | + ActionType.DELETED, | ||
120 | + null, | ||
121 | + ActionStatus.SUCCESS, | ||
122 | + null); | ||
112 | } catch (Exception e) { | 123 | } catch (Exception e) { |
113 | throw handleException(e); | 124 | throw handleException(e); |
114 | } | 125 | } |
@@ -189,8 +200,15 @@ public class DeviceController extends BaseController { | @@ -189,8 +200,15 @@ public class DeviceController extends BaseController { | ||
189 | Device device = checkDeviceId(deviceCredentials.getDeviceId()); | 200 | Device device = checkDeviceId(deviceCredentials.getDeviceId()); |
190 | DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials)); | 201 | DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials)); |
191 | actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()); | 202 | actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()); |
192 | - // TODO: refactor to ANNOTATION usage | ||
193 | - logDeviceAction(device, ActionType.CREDENTIALS_UPDATED); | 203 | + auditLogService.logEntityAction( |
204 | + getCurrentUser(), | ||
205 | + device.getId(), | ||
206 | + device.getName(), | ||
207 | + device.getCustomerId(), | ||
208 | + ActionType.CREDENTIALS_UPDATED, | ||
209 | + null, | ||
210 | + ActionStatus.SUCCESS, | ||
211 | + null); | ||
194 | return result; | 212 | return result; |
195 | } catch (Exception e) { | 213 | } catch (Exception e) { |
196 | throw handleException(e); | 214 | throw handleException(e); |
@@ -321,19 +339,4 @@ public class DeviceController extends BaseController { | @@ -321,19 +339,4 @@ public class DeviceController extends BaseController { | ||
321 | throw handleException(e); | 339 | throw handleException(e); |
322 | } | 340 | } |
323 | } | 341 | } |
324 | - | ||
325 | - // TODO: refactor to ANNOTATION usage | ||
326 | - private void logDeviceAction(Device device, ActionType actionType) throws ThingsboardException { | ||
327 | - auditLogService.logAction( | ||
328 | - getCurrentUser().getTenantId(), | ||
329 | - device.getId(), | ||
330 | - device.getName(), | ||
331 | - device.getCustomerId(), | ||
332 | - getCurrentUser().getId(), | ||
333 | - getCurrentUser().getName(), | ||
334 | - actionType, | ||
335 | - null, | ||
336 | - ActionStatus.SUCCESS, | ||
337 | - null); | ||
338 | - } | ||
339 | } | 342 | } |
@@ -244,7 +244,6 @@ spring: | @@ -244,7 +244,6 @@ spring: | ||
244 | username: "${SPRING_DATASOURCE_USERNAME:sa}" | 244 | username: "${SPRING_DATASOURCE_USERNAME:sa}" |
245 | password: "${SPRING_DATASOURCE_PASSWORD:}" | 245 | password: "${SPRING_DATASOURCE_PASSWORD:}" |
246 | 246 | ||
247 | - | ||
248 | # PostgreSQL DAO Configuration | 247 | # PostgreSQL DAO Configuration |
249 | #spring: | 248 | #spring: |
250 | # data: | 249 | # data: |
@@ -260,3 +259,8 @@ spring: | @@ -260,3 +259,8 @@ spring: | ||
260 | # url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" | 259 | # url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" |
261 | # username: "${SPRING_DATASOURCE_USERNAME:postgres}" | 260 | # username: "${SPRING_DATASOURCE_USERNAME:postgres}" |
262 | # password: "${SPRING_DATASOURCE_PASSWORD:postgres}" | 261 | # password: "${SPRING_DATASOURCE_PASSWORD:postgres}" |
262 | + | ||
263 | +# Audit log parameters | ||
264 | +audit_log: | ||
265 | + # Enable/disable audit log functionality. | ||
266 | + enabled: "${AUDIT_LOG_ENABLED:true}" |
@@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.audit.AuditLog; | @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.audit.AuditLog; | ||
27 | import org.thingsboard.server.common.data.page.TimePageData; | 27 | import org.thingsboard.server.common.data.page.TimePageData; |
28 | import org.thingsboard.server.common.data.page.TimePageLink; | 28 | import org.thingsboard.server.common.data.page.TimePageLink; |
29 | import org.thingsboard.server.common.data.security.Authority; | 29 | import org.thingsboard.server.common.data.security.Authority; |
30 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
30 | 31 | ||
31 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
32 | import java.util.List; | 33 | import java.util.List; |
@@ -36,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. | @@ -36,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. | ||
36 | public abstract class BaseAuditLogControllerTest extends AbstractControllerTest { | 37 | public abstract class BaseAuditLogControllerTest extends AbstractControllerTest { |
37 | 38 | ||
38 | private Tenant savedTenant; | 39 | private Tenant savedTenant; |
40 | + private User tenantAdmin; | ||
39 | 41 | ||
40 | @Before | 42 | @Before |
41 | public void beforeTest() throws Exception { | 43 | public void beforeTest() throws Exception { |
@@ -46,14 +48,14 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | @@ -46,14 +48,14 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | ||
46 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); | 48 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
47 | Assert.assertNotNull(savedTenant); | 49 | Assert.assertNotNull(savedTenant); |
48 | 50 | ||
49 | - User tenantAdmin = new User(); | 51 | + tenantAdmin = new User(); |
50 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | 52 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
51 | tenantAdmin.setTenantId(savedTenant.getId()); | 53 | tenantAdmin.setTenantId(savedTenant.getId()); |
52 | tenantAdmin.setEmail("tenant2@thingsboard.org"); | 54 | tenantAdmin.setEmail("tenant2@thingsboard.org"); |
53 | tenantAdmin.setFirstName("Joe"); | 55 | tenantAdmin.setFirstName("Joe"); |
54 | tenantAdmin.setLastName("Downs"); | 56 | tenantAdmin.setLastName("Downs"); |
55 | 57 | ||
56 | - createUserAndLogin(tenantAdmin, "testPassword1"); | 58 | + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
57 | } | 59 | } |
58 | 60 | ||
59 | @After | 61 | @After |
@@ -65,7 +67,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | @@ -65,7 +67,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | ||
65 | } | 67 | } |
66 | 68 | ||
67 | @Test | 69 | @Test |
68 | - public void testSaveDeviceAuditLogs() throws Exception { | 70 | + public void testAuditLogs() throws Exception { |
69 | for (int i = 0; i < 178; i++) { | 71 | for (int i = 0; i < 178; i++) { |
70 | Device device = new Device(); | 72 | Device device = new Device(); |
71 | device.setName("Device" + i); | 73 | device.setName("Device" + i); |
@@ -87,10 +89,38 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | @@ -87,10 +89,38 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | ||
87 | } while (pageData.hasNext()); | 89 | } while (pageData.hasNext()); |
88 | 90 | ||
89 | Assert.assertEquals(178, loadedAuditLogs.size()); | 91 | Assert.assertEquals(178, loadedAuditLogs.size()); |
92 | + | ||
93 | + loadedAuditLogs = new ArrayList<>(); | ||
94 | + pageLink = new TimePageLink(23); | ||
95 | + do { | ||
96 | + pageData = doGetTypedWithTimePageLink("/api/audit/logs/customer/" + ModelConstants.NULL_UUID + "?", | ||
97 | + new TypeReference<TimePageData<AuditLog>>() { | ||
98 | + }, pageLink); | ||
99 | + loadedAuditLogs.addAll(pageData.getData()); | ||
100 | + if (pageData.hasNext()) { | ||
101 | + pageLink = pageData.getNextPageLink(); | ||
102 | + } | ||
103 | + } while (pageData.hasNext()); | ||
104 | + | ||
105 | + Assert.assertEquals(178, loadedAuditLogs.size()); | ||
106 | + | ||
107 | + loadedAuditLogs = new ArrayList<>(); | ||
108 | + pageLink = new TimePageLink(23); | ||
109 | + do { | ||
110 | + pageData = doGetTypedWithTimePageLink("/api/audit/logs/user/" + tenantAdmin.getId().getId().toString() + "?", | ||
111 | + new TypeReference<TimePageData<AuditLog>>() { | ||
112 | + }, pageLink); | ||
113 | + loadedAuditLogs.addAll(pageData.getData()); | ||
114 | + if (pageData.hasNext()) { | ||
115 | + pageLink = pageData.getNextPageLink(); | ||
116 | + } | ||
117 | + } while (pageData.hasNext()); | ||
118 | + | ||
119 | + Assert.assertEquals(178, loadedAuditLogs.size()); | ||
90 | } | 120 | } |
91 | 121 | ||
92 | @Test | 122 | @Test |
93 | - public void testUpdateDeviceAuditLogs() throws Exception { | 123 | + public void testAuditLogs_byTenantIdAndEntityId() throws Exception { |
94 | Device device = new Device(); | 124 | Device device = new Device(); |
95 | device.setName("Device name"); | 125 | device.setName("Device name"); |
96 | device.setType("default"); | 126 | device.setType("default"); |
@@ -104,7 +134,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | @@ -104,7 +134,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest | ||
104 | TimePageLink pageLink = new TimePageLink(23); | 134 | TimePageLink pageLink = new TimePageLink(23); |
105 | TimePageData<AuditLog> pageData; | 135 | TimePageData<AuditLog> pageData; |
106 | do { | 136 | do { |
107 | - pageData = doGetTypedWithTimePageLink("/api/audit/logs/DEVICE/" + savedDevice.getId().getId() + "?", | 137 | + pageData = doGetTypedWithTimePageLink("/api/audit/logs/entity/DEVICE/" + savedDevice.getId().getId() + "?", |
108 | new TypeReference<TimePageData<AuditLog>>() { | 138 | new TypeReference<TimePageData<AuditLog>>() { |
109 | }, pageLink); | 139 | }, pageLink); |
110 | loadedAuditLogs.addAll(pageData.getData()); | 140 | loadedAuditLogs.addAll(pageData.getData()); |
@@ -17,7 +17,9 @@ package org.thingsboard.server.dao.audit; | @@ -17,7 +17,9 @@ package org.thingsboard.server.dao.audit; | ||
17 | 17 | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | import org.thingsboard.server.common.data.audit.AuditLog; | 19 | import org.thingsboard.server.common.data.audit.AuditLog; |
20 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
20 | import org.thingsboard.server.common.data.id.EntityId; | 21 | import org.thingsboard.server.common.data.id.EntityId; |
22 | +import org.thingsboard.server.common.data.id.UserId; | ||
21 | import org.thingsboard.server.common.data.page.TimePageLink; | 23 | import org.thingsboard.server.common.data.page.TimePageLink; |
22 | 24 | ||
23 | import java.util.List; | 25 | import java.util.List; |
@@ -29,9 +31,17 @@ public interface AuditLogDao { | @@ -29,9 +31,17 @@ public interface AuditLogDao { | ||
29 | 31 | ||
30 | ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog); | 32 | ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog); |
31 | 33 | ||
34 | + ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog); | ||
35 | + | ||
36 | + ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog); | ||
37 | + | ||
32 | ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog); | 38 | ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog); |
33 | 39 | ||
34 | List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink); | 40 | List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink); |
35 | 41 | ||
42 | + List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink); | ||
43 | + | ||
44 | + List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink); | ||
45 | + | ||
36 | List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink); | 46 | List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink); |
37 | } | 47 | } |
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.audit; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
20 | +import org.thingsboard.server.dao.model.nosql.AuditLogEntity; | ||
21 | + | ||
22 | +import java.util.ArrayList; | ||
23 | +import java.util.List; | ||
24 | +import java.util.UUID; | ||
25 | + | ||
26 | +public class AuditLogQueryCursor { | ||
27 | + @Getter | ||
28 | + private final UUID tenantId; | ||
29 | + @Getter | ||
30 | + private final List<AuditLogEntity> data; | ||
31 | + @Getter | ||
32 | + private final TimePageLink pageLink; | ||
33 | + | ||
34 | + private final List<Long> partitions; | ||
35 | + | ||
36 | + private int partitionIndex; | ||
37 | + private int currentLimit; | ||
38 | + | ||
39 | + public AuditLogQueryCursor(UUID tenantId, TimePageLink pageLink, List<Long> partitions) { | ||
40 | + this.tenantId = tenantId; | ||
41 | + this.partitions = partitions; | ||
42 | + this.partitionIndex = partitions.size() - 1; | ||
43 | + this.data = new ArrayList<>(); | ||
44 | + this.currentLimit = pageLink.getLimit(); | ||
45 | + this.pageLink = pageLink; | ||
46 | + } | ||
47 | + | ||
48 | + public boolean hasNextPartition() { | ||
49 | + return partitionIndex >= 0; | ||
50 | + } | ||
51 | + | ||
52 | + public boolean isFull() { | ||
53 | + return currentLimit <= 0; | ||
54 | + } | ||
55 | + | ||
56 | + public long getNextPartition() { | ||
57 | + long partition = partitions.get(partitionIndex); | ||
58 | + partitionIndex--; | ||
59 | + return partition; | ||
60 | + } | ||
61 | + | ||
62 | + public int getCurrentLimit() { | ||
63 | + return currentLimit; | ||
64 | + } | ||
65 | + | ||
66 | + public void addData(List<AuditLogEntity> newData) { | ||
67 | + currentLimit -= newData.size(); | ||
68 | + data.addAll(newData); | ||
69 | + } | ||
70 | +} |
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.audit; | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.audit; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import com.google.common.util.concurrent.ListenableFuture; | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | +import org.thingsboard.server.common.data.User; | ||
20 | import org.thingsboard.server.common.data.audit.ActionStatus; | 21 | import org.thingsboard.server.common.data.audit.ActionStatus; |
21 | import org.thingsboard.server.common.data.audit.ActionType; | 22 | import org.thingsboard.server.common.data.audit.ActionType; |
22 | import org.thingsboard.server.common.data.audit.AuditLog; | 23 | import org.thingsboard.server.common.data.audit.AuditLog; |
@@ -31,20 +32,21 @@ import java.util.List; | @@ -31,20 +32,21 @@ import java.util.List; | ||
31 | 32 | ||
32 | public interface AuditLogService { | 33 | public interface AuditLogService { |
33 | 34 | ||
35 | + TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink); | ||
36 | + | ||
37 | + TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink); | ||
38 | + | ||
34 | TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink); | 39 | TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink); |
35 | 40 | ||
36 | TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink); | 41 | TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink); |
37 | 42 | ||
38 | - ListenableFuture<List<Void>> logAction(TenantId tenantId, | ||
39 | - EntityId entityId, | ||
40 | - String entityName, | ||
41 | - CustomerId customerId, | ||
42 | - UserId userId, | ||
43 | - String userName, | ||
44 | - ActionType actionType, | ||
45 | - JsonNode actionData, | ||
46 | - ActionStatus actionStatus, | ||
47 | - String actionFailureDetails); | ||
48 | - | 43 | + ListenableFuture<List<Void>> logEntityAction(User user, |
44 | + EntityId entityId, | ||
45 | + String entityName, | ||
46 | + CustomerId customerId, | ||
47 | + ActionType actionType, | ||
48 | + JsonNode actionData, | ||
49 | + ActionStatus actionStatus, | ||
50 | + String actionFailureDetails); | ||
49 | 51 | ||
50 | } | 52 | } |
@@ -15,20 +15,20 @@ | @@ -15,20 +15,20 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.dao.audit; | 16 | package org.thingsboard.server.dao.audit; |
17 | 17 | ||
18 | +import com.datastax.driver.core.utils.UUIDs; | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 19 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import com.google.common.collect.Lists; | 20 | import com.google.common.collect.Lists; |
20 | import com.google.common.util.concurrent.Futures; | 21 | import com.google.common.util.concurrent.Futures; |
21 | import com.google.common.util.concurrent.ListenableFuture; | 22 | import com.google.common.util.concurrent.ListenableFuture; |
22 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
23 | import org.springframework.beans.factory.annotation.Autowired; | 24 | import org.springframework.beans.factory.annotation.Autowired; |
25 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
24 | import org.springframework.stereotype.Service; | 26 | import org.springframework.stereotype.Service; |
27 | +import org.thingsboard.server.common.data.User; | ||
25 | import org.thingsboard.server.common.data.audit.ActionStatus; | 28 | import org.thingsboard.server.common.data.audit.ActionStatus; |
26 | import org.thingsboard.server.common.data.audit.ActionType; | 29 | import org.thingsboard.server.common.data.audit.ActionType; |
27 | import org.thingsboard.server.common.data.audit.AuditLog; | 30 | import org.thingsboard.server.common.data.audit.AuditLog; |
28 | -import org.thingsboard.server.common.data.id.CustomerId; | ||
29 | -import org.thingsboard.server.common.data.id.EntityId; | ||
30 | -import org.thingsboard.server.common.data.id.TenantId; | ||
31 | -import org.thingsboard.server.common.data.id.UserId; | 31 | +import org.thingsboard.server.common.data.id.*; |
32 | import org.thingsboard.server.common.data.page.TimePageData; | 32 | import org.thingsboard.server.common.data.page.TimePageData; |
33 | import org.thingsboard.server.common.data.page.TimePageLink; | 33 | import org.thingsboard.server.common.data.page.TimePageLink; |
34 | import org.thingsboard.server.dao.exception.DataValidationException; | 34 | import org.thingsboard.server.dao.exception.DataValidationException; |
@@ -41,6 +41,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; | @@ -41,6 +41,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; | ||
41 | 41 | ||
42 | @Slf4j | 42 | @Slf4j |
43 | @Service | 43 | @Service |
44 | +@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "true") | ||
44 | public class AuditLogServiceImpl implements AuditLogService { | 45 | public class AuditLogServiceImpl implements AuditLogService { |
45 | 46 | ||
46 | private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; | 47 | private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; |
@@ -50,6 +51,24 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -50,6 +51,24 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
50 | private AuditLogDao auditLogDao; | 51 | private AuditLogDao auditLogDao; |
51 | 52 | ||
52 | @Override | 53 | @Override |
54 | + public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) { | ||
55 | + log.trace("Executing findAuditLogsByTenantIdAndCustomerId [{}], [{}], [{}]", tenantId, customerId, pageLink); | ||
56 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
57 | + validateId(customerId, "Incorrect customerId " + customerId); | ||
58 | + List<AuditLog> auditLogs = auditLogDao.findAuditLogsByTenantIdAndCustomerId(tenantId.getId(), customerId, pageLink); | ||
59 | + return new TimePageData<>(auditLogs, pageLink); | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) { | ||
64 | + log.trace("Executing findAuditLogsByTenantIdAndUserId [{}], [{}], [{}]", tenantId, userId, pageLink); | ||
65 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
66 | + validateId(userId, "Incorrect userId" + userId); | ||
67 | + List<AuditLog> auditLogs = auditLogDao.findAuditLogsByTenantIdAndUserId(tenantId.getId(), userId, pageLink); | ||
68 | + return new TimePageData<>(auditLogs, pageLink); | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
53 | public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) { | 72 | public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) { |
54 | log.trace("Executing findAuditLogsByTenantIdAndEntityId [{}], [{}], [{}]", tenantId, entityId, pageLink); | 73 | log.trace("Executing findAuditLogsByTenantIdAndEntityId [{}], [{}], [{}]", tenantId, entityId, pageLink); |
55 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | 74 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
@@ -66,6 +85,28 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -66,6 +85,28 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
66 | return new TimePageData<>(auditLogs, pageLink); | 85 | return new TimePageData<>(auditLogs, pageLink); |
67 | } | 86 | } |
68 | 87 | ||
88 | + @Override | ||
89 | + public ListenableFuture<List<Void>> logEntityAction(User user, | ||
90 | + EntityId entityId, | ||
91 | + String entityName, | ||
92 | + CustomerId customerId, | ||
93 | + ActionType actionType, | ||
94 | + JsonNode actionData, | ||
95 | + ActionStatus actionStatus, | ||
96 | + String actionFailureDetails) { | ||
97 | + return logAction( | ||
98 | + user.getTenantId(), | ||
99 | + entityId, | ||
100 | + entityName, | ||
101 | + customerId, | ||
102 | + user.getId(), | ||
103 | + user.getName(), | ||
104 | + actionType, | ||
105 | + actionData, | ||
106 | + actionStatus, | ||
107 | + actionFailureDetails); | ||
108 | + } | ||
109 | + | ||
69 | private AuditLog createAuditLogEntry(TenantId tenantId, | 110 | private AuditLog createAuditLogEntry(TenantId tenantId, |
70 | EntityId entityId, | 111 | EntityId entityId, |
71 | String entityName, | 112 | String entityName, |
@@ -77,6 +118,7 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -77,6 +118,7 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
77 | ActionStatus actionStatus, | 118 | ActionStatus actionStatus, |
78 | String actionFailureDetails) { | 119 | String actionFailureDetails) { |
79 | AuditLog result = new AuditLog(); | 120 | AuditLog result = new AuditLog(); |
121 | + result.setId(new AuditLogId(UUIDs.timeBased())); | ||
80 | result.setTenantId(tenantId); | 122 | result.setTenantId(tenantId); |
81 | result.setEntityId(entityId); | 123 | result.setEntityId(entityId); |
82 | result.setEntityName(entityName); | 124 | result.setEntityName(entityName); |
@@ -90,17 +132,16 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -90,17 +132,16 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
90 | return result; | 132 | return result; |
91 | } | 133 | } |
92 | 134 | ||
93 | - @Override | ||
94 | - public ListenableFuture<List<Void>> logAction(TenantId tenantId, | ||
95 | - EntityId entityId, | ||
96 | - String entityName, | ||
97 | - CustomerId customerId, | ||
98 | - UserId userId, | ||
99 | - String userName, | ||
100 | - ActionType actionType, | ||
101 | - JsonNode actionData, | ||
102 | - ActionStatus actionStatus, | ||
103 | - String actionFailureDetails) { | 135 | + private ListenableFuture<List<Void>> logAction(TenantId tenantId, |
136 | + EntityId entityId, | ||
137 | + String entityName, | ||
138 | + CustomerId customerId, | ||
139 | + UserId userId, | ||
140 | + String userName, | ||
141 | + ActionType actionType, | ||
142 | + JsonNode actionData, | ||
143 | + ActionStatus actionStatus, | ||
144 | + String actionFailureDetails) { | ||
104 | AuditLog auditLogEntry = createAuditLogEntry(tenantId, entityId, entityName, customerId, userId, userName, | 145 | AuditLog auditLogEntry = createAuditLogEntry(tenantId, entityId, entityName, customerId, userId, userName, |
105 | actionType, actionData, actionStatus, actionFailureDetails); | 146 | actionType, actionData, actionStatus, actionFailureDetails); |
106 | log.trace("Executing logAction [{}]", auditLogEntry); | 147 | log.trace("Executing logAction [{}]", auditLogEntry); |
@@ -109,6 +150,8 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -109,6 +150,8 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
109 | futures.add(auditLogDao.savePartitionsByTenantId(auditLogEntry)); | 150 | futures.add(auditLogDao.savePartitionsByTenantId(auditLogEntry)); |
110 | futures.add(auditLogDao.saveByTenantId(auditLogEntry)); | 151 | futures.add(auditLogDao.saveByTenantId(auditLogEntry)); |
111 | futures.add(auditLogDao.saveByTenantIdAndEntityId(auditLogEntry)); | 152 | futures.add(auditLogDao.saveByTenantIdAndEntityId(auditLogEntry)); |
153 | + futures.add(auditLogDao.saveByTenantIdAndCustomerId(auditLogEntry)); | ||
154 | + futures.add(auditLogDao.saveByTenantIdAndUserId(auditLogEntry)); | ||
112 | return Futures.allAsList(futures); | 155 | return Futures.allAsList(futures); |
113 | } | 156 | } |
114 | 157 |
@@ -19,7 +19,8 @@ import com.datastax.driver.core.BoundStatement; | @@ -19,7 +19,8 @@ import com.datastax.driver.core.BoundStatement; | ||
19 | import com.datastax.driver.core.PreparedStatement; | 19 | import com.datastax.driver.core.PreparedStatement; |
20 | import com.datastax.driver.core.ResultSet; | 20 | import com.datastax.driver.core.ResultSet; |
21 | import com.datastax.driver.core.ResultSetFuture; | 21 | import com.datastax.driver.core.ResultSetFuture; |
22 | -import com.datastax.driver.core.utils.UUIDs; | 22 | +import com.datastax.driver.core.querybuilder.QueryBuilder; |
23 | +import com.datastax.driver.core.querybuilder.Select; | ||
23 | import com.google.common.base.Function; | 24 | import com.google.common.base.Function; |
24 | import com.google.common.util.concurrent.Futures; | 25 | import com.google.common.util.concurrent.Futures; |
25 | import com.google.common.util.concurrent.ListenableFuture; | 26 | import com.google.common.util.concurrent.ListenableFuture; |
@@ -29,8 +30,9 @@ import org.springframework.beans.factory.annotation.Value; | @@ -29,8 +30,9 @@ import org.springframework.beans.factory.annotation.Value; | ||
29 | import org.springframework.core.env.Environment; | 30 | import org.springframework.core.env.Environment; |
30 | import org.springframework.stereotype.Component; | 31 | import org.springframework.stereotype.Component; |
31 | import org.thingsboard.server.common.data.audit.AuditLog; | 32 | import org.thingsboard.server.common.data.audit.AuditLog; |
32 | -import org.thingsboard.server.common.data.id.AuditLogId; | 33 | +import org.thingsboard.server.common.data.id.CustomerId; |
33 | import org.thingsboard.server.common.data.id.EntityId; | 34 | import org.thingsboard.server.common.data.id.EntityId; |
35 | +import org.thingsboard.server.common.data.id.UserId; | ||
34 | import org.thingsboard.server.common.data.page.TimePageLink; | 36 | import org.thingsboard.server.common.data.page.TimePageLink; |
35 | import org.thingsboard.server.dao.DaoUtil; | 37 | import org.thingsboard.server.dao.DaoUtil; |
36 | import org.thingsboard.server.dao.model.ModelConstants; | 38 | import org.thingsboard.server.dao.model.ModelConstants; |
@@ -52,6 +54,7 @@ import java.util.Optional; | @@ -52,6 +54,7 @@ import java.util.Optional; | ||
52 | import java.util.UUID; | 54 | import java.util.UUID; |
53 | import java.util.concurrent.ExecutorService; | 55 | import java.util.concurrent.ExecutorService; |
54 | import java.util.concurrent.Executors; | 56 | import java.util.concurrent.Executors; |
57 | +import java.util.stream.Collectors; | ||
55 | 58 | ||
56 | import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; | 59 | import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
57 | import static org.thingsboard.server.dao.model.ModelConstants.*; | 60 | import static org.thingsboard.server.dao.model.ModelConstants.*; |
@@ -82,7 +85,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -82,7 +85,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
82 | private String partitioning; | 85 | private String partitioning; |
83 | private TsPartitionDate tsFormat; | 86 | private TsPartitionDate tsFormat; |
84 | 87 | ||
85 | - private PreparedStatement[] saveStmts; | 88 | + private PreparedStatement partitionInsertStmt; |
89 | + private PreparedStatement saveByTenantStmt; | ||
90 | + private PreparedStatement saveByTenantIdAndUserIdStmt; | ||
91 | + private PreparedStatement saveByTenantIdAndEntityIdStmt; | ||
92 | + private PreparedStatement saveByTenantIdAndCustomerIdStmt; | ||
86 | 93 | ||
87 | private boolean isInstall() { | 94 | private boolean isInstall() { |
88 | return environment.acceptsProfiles("install"); | 95 | return environment.acceptsProfiles("install"); |
@@ -123,11 +130,9 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -123,11 +130,9 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
123 | public ListenableFuture<Void> saveByTenantId(AuditLog auditLog) { | 130 | public ListenableFuture<Void> saveByTenantId(AuditLog auditLog) { |
124 | log.debug("Save saveByTenantId [{}] ", auditLog); | 131 | log.debug("Save saveByTenantId [{}] ", auditLog); |
125 | 132 | ||
126 | - AuditLogId auditLogId = new AuditLogId(UUIDs.timeBased()); | ||
127 | - | ||
128 | long partition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); | 133 | long partition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); |
129 | BoundStatement stmt = getSaveByTenantStmt().bind(); | 134 | BoundStatement stmt = getSaveByTenantStmt().bind(); |
130 | - stmt.setUUID(0, auditLogId.getId()) | 135 | + stmt = stmt.setUUID(0, auditLog.getId().getId()) |
131 | .setUUID(1, auditLog.getTenantId().getId()) | 136 | .setUUID(1, auditLog.getTenantId().getId()) |
132 | .setUUID(2, auditLog.getEntityId().getId()) | 137 | .setUUID(2, auditLog.getEntityId().getId()) |
133 | .setString(3, auditLog.getEntityId().getEntityType().name()) | 138 | .setString(3, auditLog.getEntityId().getEntityType().name()) |
@@ -140,18 +145,45 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -140,18 +145,45 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
140 | public ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog) { | 145 | public ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog) { |
141 | log.debug("Save saveByTenantIdAndEntityId [{}] ", auditLog); | 146 | log.debug("Save saveByTenantIdAndEntityId [{}] ", auditLog); |
142 | 147 | ||
143 | - AuditLogId auditLogId = new AuditLogId(UUIDs.timeBased()); | ||
144 | - | ||
145 | BoundStatement stmt = getSaveByTenantIdAndEntityIdStmt().bind(); | 148 | BoundStatement stmt = getSaveByTenantIdAndEntityIdStmt().bind(); |
146 | - stmt.setUUID(0, auditLogId.getId()) | ||
147 | - .setUUID(1, auditLog.getTenantId().getId()) | ||
148 | - .setUUID(2, auditLog.getEntityId().getId()) | ||
149 | - .setString(3, auditLog.getEntityId().getEntityType().name()) | ||
150 | - .setString(4, auditLog.getActionType().name()); | 149 | + stmt = setSaveStmtVariables(stmt, auditLog); |
151 | return getFuture(executeAsyncWrite(stmt), rs -> null); | 150 | return getFuture(executeAsyncWrite(stmt), rs -> null); |
152 | } | 151 | } |
153 | 152 | ||
154 | @Override | 153 | @Override |
154 | + public ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog) { | ||
155 | + log.debug("Save saveByTenantIdAndCustomerId [{}] ", auditLog); | ||
156 | + | ||
157 | + BoundStatement stmt = getSaveByTenantIdAndCustomerIdStmt().bind(); | ||
158 | + stmt = setSaveStmtVariables(stmt, auditLog); | ||
159 | + return getFuture(executeAsyncWrite(stmt), rs -> null); | ||
160 | + } | ||
161 | + | ||
162 | + @Override | ||
163 | + public ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog) { | ||
164 | + log.debug("Save saveByTenantIdAndUserId [{}] ", auditLog); | ||
165 | + | ||
166 | + BoundStatement stmt = getSaveByTenantIdAndUserIdStmt().bind(); | ||
167 | + stmt = setSaveStmtVariables(stmt, auditLog); | ||
168 | + return getFuture(executeAsyncWrite(stmt), rs -> null); | ||
169 | + } | ||
170 | + | ||
171 | + private BoundStatement setSaveStmtVariables(BoundStatement stmt, AuditLog auditLog) { | ||
172 | + return stmt.setUUID(0, auditLog.getId().getId()) | ||
173 | + .setUUID(1, auditLog.getTenantId().getId()) | ||
174 | + .setUUID(2, auditLog.getCustomerId().getId()) | ||
175 | + .setUUID(3, auditLog.getEntityId().getId()) | ||
176 | + .setString(4, auditLog.getEntityId().getEntityType().name()) | ||
177 | + .setString(5, auditLog.getEntityName()) | ||
178 | + .setUUID(6, auditLog.getUserId().getId()) | ||
179 | + .setString(7, auditLog.getUserName()) | ||
180 | + .setString(8, auditLog.getActionType().name()) | ||
181 | + .setString(9, auditLog.getActionData() != null ? auditLog.getActionData().toString() : null) | ||
182 | + .setString(10, auditLog.getActionStatus().name()) | ||
183 | + .setString(11, auditLog.getActionFailureDetails()); | ||
184 | + } | ||
185 | + | ||
186 | + @Override | ||
155 | public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) { | 187 | public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) { |
156 | log.debug("Save savePartitionsByTenantId [{}] ", auditLog); | 188 | log.debug("Save savePartitionsByTenantId [{}] ", auditLog); |
157 | 189 | ||
@@ -163,35 +195,66 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -163,35 +195,66 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
163 | return getFuture(executeAsyncWrite(stmt), rs -> null); | 195 | return getFuture(executeAsyncWrite(stmt), rs -> null); |
164 | } | 196 | } |
165 | 197 | ||
166 | - private PreparedStatement getPartitionInsertStmt() { | ||
167 | - // TODO: ADD CACHE LOGIC | ||
168 | - return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF + | ||
169 | - "(" + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + | ||
170 | - "," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" + | ||
171 | - " VALUES(?, ?)"); | 198 | + private PreparedStatement getSaveByTenantIdAndEntityIdStmt() { |
199 | + if (saveByTenantIdAndEntityIdStmt == null) { | ||
200 | + saveByTenantIdAndEntityIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_ENTITY_ID_CF); | ||
201 | + } | ||
202 | + return saveByTenantIdAndEntityIdStmt; | ||
172 | } | 203 | } |
173 | 204 | ||
174 | - private PreparedStatement getSaveByTenantIdAndEntityIdStmt() { | ||
175 | - // TODO: ADD CACHE LOGIC | ||
176 | - return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_ENTITY_ID_CF + | ||
177 | - "(" + ModelConstants.AUDIT_LOG_ID_PROPERTY + | ||
178 | - "," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + | ||
179 | - "," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY + | ||
180 | - "," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY + | ||
181 | - "," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY + ")" + | ||
182 | - " VALUES(?, ?, ?, ?, ?)"); | 205 | + private PreparedStatement getSaveByTenantIdAndCustomerIdStmt() { |
206 | + if (saveByTenantIdAndCustomerIdStmt == null) { | ||
207 | + saveByTenantIdAndCustomerIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_CUSTOMER_ID_CF); | ||
208 | + } | ||
209 | + return saveByTenantIdAndCustomerIdStmt; | ||
183 | } | 210 | } |
184 | 211 | ||
185 | - private PreparedStatement getSaveByTenantStmt() { | ||
186 | - // TODO: ADD CACHE LOGIC | ||
187 | - return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_CF + | 212 | + private PreparedStatement getSaveByTenantIdAndUserIdStmt() { |
213 | + if (saveByTenantIdAndUserIdStmt == null) { | ||
214 | + saveByTenantIdAndUserIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_USER_ID_CF); | ||
215 | + } | ||
216 | + return saveByTenantIdAndUserIdStmt; | ||
217 | + } | ||
218 | + | ||
219 | + private PreparedStatement getSaveByTenantIdAndCFName(String cfName) { | ||
220 | + return getSession().prepare(INSERT_INTO + cfName + | ||
188 | "(" + ModelConstants.AUDIT_LOG_ID_PROPERTY + | 221 | "(" + ModelConstants.AUDIT_LOG_ID_PROPERTY + |
189 | "," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + | 222 | "," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + |
223 | + "," + ModelConstants.AUDIT_LOG_CUSTOMER_ID_PROPERTY + | ||
190 | "," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY + | 224 | "," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY + |
191 | "," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY + | 225 | "," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY + |
226 | + "," + ModelConstants.AUDIT_LOG_ENTITY_NAME_PROPERTY + | ||
227 | + "," + ModelConstants.AUDIT_LOG_USER_ID_PROPERTY + | ||
228 | + "," + ModelConstants.AUDIT_LOG_USER_NAME_PROPERTY + | ||
192 | "," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY + | 229 | "," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY + |
193 | - "," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" + | ||
194 | - " VALUES(?, ?, ?, ?, ?, ?)"); | 230 | + "," + ModelConstants.AUDIT_LOG_ACTION_DATA_PROPERTY + |
231 | + "," + ModelConstants.AUDIT_LOG_ACTION_STATUS_PROPERTY + | ||
232 | + "," + ModelConstants.AUDIT_LOG_ACTION_FAILURE_DETAILS_PROPERTY + ")" + | ||
233 | + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); | ||
234 | + } | ||
235 | + | ||
236 | + private PreparedStatement getPartitionInsertStmt() { | ||
237 | + if (partitionInsertStmt == null) { | ||
238 | + partitionInsertStmt = getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF + | ||
239 | + "(" + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + | ||
240 | + "," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" + | ||
241 | + " VALUES(?, ?)"); | ||
242 | + } | ||
243 | + return partitionInsertStmt; | ||
244 | + } | ||
245 | + | ||
246 | + private PreparedStatement getSaveByTenantStmt() { | ||
247 | + if (saveByTenantStmt == null) { | ||
248 | + saveByTenantStmt = getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_CF + | ||
249 | + "(" + ModelConstants.AUDIT_LOG_ID_PROPERTY + | ||
250 | + "," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY + | ||
251 | + "," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY + | ||
252 | + "," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY + | ||
253 | + "," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY + | ||
254 | + "," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" + | ||
255 | + " VALUES(?, ?, ?, ?, ?, ?)"); | ||
256 | + } | ||
257 | + return saveByTenantStmt; | ||
195 | } | 258 | } |
196 | 259 | ||
197 | private long toPartitionTs(long ts) { | 260 | private long toPartitionTs(long ts) { |
@@ -199,7 +262,6 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -199,7 +262,6 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
199 | return tsFormat.truncatedTo(time).toInstant(ZoneOffset.UTC).toEpochMilli(); | 262 | return tsFormat.truncatedTo(time).toInstant(ZoneOffset.UTC).toEpochMilli(); |
200 | } | 263 | } |
201 | 264 | ||
202 | - | ||
203 | @Override | 265 | @Override |
204 | public List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink) { | 266 | public List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink) { |
205 | log.trace("Try to find audit logs by tenant [{}], entity [{}] and pageLink [{}]", tenantId, entityId, pageLink); | 267 | log.trace("Try to find audit logs by tenant [{}], entity [{}] and pageLink [{}]", tenantId, entityId, pageLink); |
@@ -213,30 +275,75 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | @@ -213,30 +275,75 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo | ||
213 | } | 275 | } |
214 | 276 | ||
215 | @Override | 277 | @Override |
278 | + public List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink) { | ||
279 | + log.trace("Try to find audit logs by tenant [{}], customer [{}] and pageLink [{}]", tenantId, customerId, pageLink); | ||
280 | + List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_CUSTOMER_ID_CF, | ||
281 | + Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId), | ||
282 | + eq(ModelConstants.AUDIT_LOG_CUSTOMER_ID_PROPERTY, customerId.getId())), | ||
283 | + pageLink); | ||
284 | + log.trace("Found audit logs by tenant [{}], customer [{}] and pageLink [{}]", tenantId, customerId, pageLink); | ||
285 | + return DaoUtil.convertDataList(entities); | ||
286 | + } | ||
287 | + | ||
288 | + @Override | ||
289 | + public List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink) { | ||
290 | + log.trace("Try to find audit logs by tenant [{}], user [{}] and pageLink [{}]", tenantId, userId, pageLink); | ||
291 | + List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_USER_ID_CF, | ||
292 | + Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId), | ||
293 | + eq(ModelConstants.AUDIT_LOG_USER_ID_PROPERTY, userId.getId())), | ||
294 | + pageLink); | ||
295 | + log.trace("Found audit logs by tenant [{}], user [{}] and pageLink [{}]", tenantId, userId, pageLink); | ||
296 | + return DaoUtil.convertDataList(entities); | ||
297 | + } | ||
298 | + | ||
299 | + @Override | ||
216 | public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) { | 300 | public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) { |
217 | log.trace("Try to find audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink); | 301 | log.trace("Try to find audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink); |
218 | 302 | ||
219 | - // TODO: ADD AUDIT LOG PARTITION CURSOR LOGIC | ||
220 | - | ||
221 | long minPartition; | 303 | long minPartition; |
222 | - long maxPartition; | ||
223 | - | ||
224 | if (pageLink.getStartTime() != null && pageLink.getStartTime() != 0) { | 304 | if (pageLink.getStartTime() != null && pageLink.getStartTime() != 0) { |
225 | minPartition = toPartitionTs(pageLink.getStartTime()); | 305 | minPartition = toPartitionTs(pageLink.getStartTime()); |
226 | } else { | 306 | } else { |
227 | minPartition = toPartitionTs(LocalDate.now().minusMonths(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); | 307 | minPartition = toPartitionTs(LocalDate.now().minusMonths(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); |
228 | } | 308 | } |
229 | 309 | ||
310 | + long maxPartition; | ||
230 | if (pageLink.getEndTime() != null && pageLink.getEndTime() != 0) { | 311 | if (pageLink.getEndTime() != null && pageLink.getEndTime() != 0) { |
231 | maxPartition = toPartitionTs(pageLink.getEndTime()); | 312 | maxPartition = toPartitionTs(pageLink.getEndTime()); |
232 | } else { | 313 | } else { |
233 | maxPartition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); | 314 | maxPartition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()); |
234 | } | 315 | } |
235 | - List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_TENANT_ID_CF, | ||
236 | - Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId), | ||
237 | - eq(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY, maxPartition)), | ||
238 | - pageLink); | 316 | + |
317 | + List<Long> partitions = fetchPartitions(tenantId, minPartition, maxPartition) | ||
318 | + .all() | ||
319 | + .stream() | ||
320 | + .map(row -> row.getLong(ModelConstants.PARTITION_COLUMN)) | ||
321 | + .collect(Collectors.toList()); | ||
322 | + | ||
323 | + AuditLogQueryCursor cursor = new AuditLogQueryCursor(tenantId, pageLink, partitions); | ||
324 | + List<AuditLogEntity> entities = fetchSequentiallyWithLimit(cursor); | ||
239 | log.trace("Found audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink); | 325 | log.trace("Found audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink); |
240 | return DaoUtil.convertDataList(entities); | 326 | return DaoUtil.convertDataList(entities); |
241 | } | 327 | } |
328 | + | ||
329 | + private List<AuditLogEntity> fetchSequentiallyWithLimit(AuditLogQueryCursor cursor) { | ||
330 | + if (cursor.isFull() || !cursor.hasNextPartition()) { | ||
331 | + return cursor.getData(); | ||
332 | + } else { | ||
333 | + cursor.addData(findPageWithTimeSearch(AUDIT_LOG_BY_TENANT_ID_CF, | ||
334 | + Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, cursor.getTenantId()), | ||
335 | + eq(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY, cursor.getNextPartition())), | ||
336 | + cursor.getPageLink())); | ||
337 | + return fetchSequentiallyWithLimit(cursor); | ||
338 | + } | ||
339 | + } | ||
340 | + | ||
341 | + private ResultSet fetchPartitions(UUID tenantId, long minPartition, long maxPartition) { | ||
342 | + Select.Where select = QueryBuilder.select(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY).from(ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF) | ||
343 | + .where(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId)); | ||
344 | + select.and(QueryBuilder.gte(ModelConstants.PARTITION_COLUMN, minPartition)); | ||
345 | + select.and(QueryBuilder.lte(ModelConstants.PARTITION_COLUMN, maxPartition)); | ||
346 | + return getSession().execute(select); | ||
347 | + } | ||
348 | + | ||
242 | } | 349 | } |
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.audit; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import com.google.common.util.concurrent.ListenableFuture; | ||
20 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
21 | +import org.thingsboard.server.common.data.User; | ||
22 | +import org.thingsboard.server.common.data.audit.ActionStatus; | ||
23 | +import org.thingsboard.server.common.data.audit.ActionType; | ||
24 | +import org.thingsboard.server.common.data.audit.AuditLog; | ||
25 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
26 | +import org.thingsboard.server.common.data.id.EntityId; | ||
27 | +import org.thingsboard.server.common.data.id.TenantId; | ||
28 | +import org.thingsboard.server.common.data.id.UserId; | ||
29 | +import org.thingsboard.server.common.data.page.TimePageData; | ||
30 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
31 | + | ||
32 | +import java.util.List; | ||
33 | + | ||
34 | +@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "false") | ||
35 | +public class DummyAuditLogServiceImpl implements AuditLogService { | ||
36 | + | ||
37 | + @Override | ||
38 | + public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) { | ||
39 | + return null; | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) { | ||
44 | + return null; | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) { | ||
49 | + return null; | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink) { | ||
54 | + return null; | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public ListenableFuture<List<Void>> logEntityAction(User user, EntityId entityId, String entityName, CustomerId customerId, ActionType actionType, JsonNode actionData, ActionStatus actionStatus, String actionFailureDetails) { | ||
59 | + return null; | ||
60 | + } | ||
61 | +} |
@@ -147,6 +147,8 @@ public class ModelConstants { | @@ -147,6 +147,8 @@ public class ModelConstants { | ||
147 | public static final String AUDIT_LOG_COLUMN_FAMILY_NAME = "audit_log"; | 147 | public static final String AUDIT_LOG_COLUMN_FAMILY_NAME = "audit_log"; |
148 | 148 | ||
149 | public static final String AUDIT_LOG_BY_ENTITY_ID_CF = "audit_log_by_entity_id"; | 149 | public static final String AUDIT_LOG_BY_ENTITY_ID_CF = "audit_log_by_entity_id"; |
150 | + public static final String AUDIT_LOG_BY_CUSTOMER_ID_CF = "audit_log_by_customer_id"; | ||
151 | + public static final String AUDIT_LOG_BY_USER_ID_CF = "audit_log_by_user_id"; | ||
150 | public static final String AUDIT_LOG_BY_TENANT_ID_CF = "audit_log_by_tenant_id"; | 152 | public static final String AUDIT_LOG_BY_TENANT_ID_CF = "audit_log_by_tenant_id"; |
151 | public static final String AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF = "audit_log_by_tenant_id_partitions"; | 153 | public static final String AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF = "audit_log_by_tenant_id_partitions"; |
152 | 154 |
@@ -41,4 +41,20 @@ public interface AuditLogRepository extends CrudRepository<AuditLogEntity, Strin | @@ -41,4 +41,20 @@ public interface AuditLogRepository extends CrudRepository<AuditLogEntity, Strin | ||
41 | @Param("entityType") EntityType entityType, | 41 | @Param("entityType") EntityType entityType, |
42 | @Param("idOffset") String idOffset, | 42 | @Param("idOffset") String idOffset, |
43 | Pageable pageable); | 43 | Pageable pageable); |
44 | + | ||
45 | + @Query("SELECT al FROM AuditLogEntity al WHERE al.tenantId = :tenantId " + | ||
46 | + "AND al.customerId = :customerId " + | ||
47 | + "AND al.id > :idOffset ORDER BY al.id") | ||
48 | + List<AuditLogEntity> findByTenantIdAndCustomerId(@Param("tenantId") String tenantId, | ||
49 | + @Param("customerId") String customerId, | ||
50 | + @Param("idOffset") String idOffset, | ||
51 | + Pageable pageable); | ||
52 | + | ||
53 | + @Query("SELECT al FROM AuditLogEntity al WHERE al.tenantId = :tenantId " + | ||
54 | + "AND al.userId = :userId " + | ||
55 | + "AND al.id > :idOffset ORDER BY al.id") | ||
56 | + List<AuditLogEntity> findByTenantIdAndUserId(@Param("tenantId") String tenantId, | ||
57 | + @Param("userId") String userId, | ||
58 | + @Param("idOffset") String idOffset, | ||
59 | + Pageable pageable); | ||
44 | } | 60 | } |
@@ -23,7 +23,9 @@ import org.springframework.data.domain.PageRequest; | @@ -23,7 +23,9 @@ import org.springframework.data.domain.PageRequest; | ||
23 | import org.springframework.data.repository.CrudRepository; | 23 | import org.springframework.data.repository.CrudRepository; |
24 | import org.springframework.stereotype.Component; | 24 | import org.springframework.stereotype.Component; |
25 | import org.thingsboard.server.common.data.audit.AuditLog; | 25 | import org.thingsboard.server.common.data.audit.AuditLog; |
26 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
26 | import org.thingsboard.server.common.data.id.EntityId; | 27 | import org.thingsboard.server.common.data.id.EntityId; |
28 | +import org.thingsboard.server.common.data.id.UserId; | ||
27 | import org.thingsboard.server.common.data.page.TimePageLink; | 29 | import org.thingsboard.server.common.data.page.TimePageLink; |
28 | import org.thingsboard.server.dao.DaoUtil; | 30 | import org.thingsboard.server.dao.DaoUtil; |
29 | import org.thingsboard.server.dao.audit.AuditLogDao; | 31 | import org.thingsboard.server.dao.audit.AuditLogDao; |
@@ -77,6 +79,16 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp | @@ -77,6 +79,16 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp | ||
77 | } | 79 | } |
78 | 80 | ||
79 | @Override | 81 | @Override |
82 | + public ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog) { | ||
83 | + return insertService.submit(() -> null); | ||
84 | + } | ||
85 | + | ||
86 | + @Override | ||
87 | + public ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog) { | ||
88 | + return insertService.submit(() -> null); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
80 | public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) { | 92 | public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) { |
81 | return insertService.submit(() -> null); | 93 | return insertService.submit(() -> null); |
82 | } | 94 | } |
@@ -93,6 +105,26 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp | @@ -93,6 +105,26 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp | ||
93 | } | 105 | } |
94 | 106 | ||
95 | @Override | 107 | @Override |
108 | + public List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink) { | ||
109 | + return DaoUtil.convertDataList( | ||
110 | + auditLogRepository.findByTenantIdAndCustomerId( | ||
111 | + fromTimeUUID(tenantId), | ||
112 | + fromTimeUUID(customerId.getId()), | ||
113 | + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), | ||
114 | + new PageRequest(0, pageLink.getLimit()))); | ||
115 | + } | ||
116 | + | ||
117 | + @Override | ||
118 | + public List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink) { | ||
119 | + return DaoUtil.convertDataList( | ||
120 | + auditLogRepository.findByTenantIdAndUserId( | ||
121 | + fromTimeUUID(tenantId), | ||
122 | + fromTimeUUID(userId.getId()), | ||
123 | + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), | ||
124 | + new PageRequest(0, pageLink.getLimit()))); | ||
125 | + } | ||
126 | + | ||
127 | + @Override | ||
96 | public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) { | 128 | public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) { |
97 | return DaoUtil.convertDataList( | 129 | return DaoUtil.convertDataList( |
98 | auditLogRepository.findByTenantId( | 130 | auditLogRepository.findByTenantId( |
@@ -566,6 +566,40 @@ CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_entity_id ( | @@ -566,6 +566,40 @@ CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_entity_id ( | ||
566 | PRIMARY KEY ((tenant_id, entity_id, entity_type), id) | 566 | PRIMARY KEY ((tenant_id, entity_id, entity_type), id) |
567 | ); | 567 | ); |
568 | 568 | ||
569 | +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_customer_id ( | ||
570 | + tenant_id timeuuid, | ||
571 | + id timeuuid, | ||
572 | + customer_id timeuuid, | ||
573 | + entity_id timeuuid, | ||
574 | + entity_type text, | ||
575 | + entity_name text, | ||
576 | + user_id timeuuid, | ||
577 | + user_name text, | ||
578 | + action_type text, | ||
579 | + action_data text, | ||
580 | + action_status text, | ||
581 | + action_failure_details text, | ||
582 | + PRIMARY KEY ((tenant_id, customer_id), id) | ||
583 | +); | ||
584 | + | ||
585 | +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_user_id ( | ||
586 | + tenant_id timeuuid, | ||
587 | + id timeuuid, | ||
588 | + customer_id timeuuid, | ||
589 | + entity_id timeuuid, | ||
590 | + entity_type text, | ||
591 | + entity_name text, | ||
592 | + user_id timeuuid, | ||
593 | + user_name text, | ||
594 | + action_type text, | ||
595 | + action_data text, | ||
596 | + action_status text, | ||
597 | + action_failure_details text, | ||
598 | + PRIMARY KEY ((tenant_id, user_id), id) | ||
599 | +); | ||
600 | + | ||
601 | + | ||
602 | + | ||
569 | CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id ( | 603 | CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id ( |
570 | tenant_id timeuuid, | 604 | tenant_id timeuuid, |
571 | id timeuuid, | 605 | id timeuuid, |