Added get by user id and customer id
Improved partitions query
This commit is contained in:
parent
ead30d700b
commit
23b21b2912
@ -18,20 +18,64 @@ package org.thingsboard.server.controller;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.page.TimePageData;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.exception.ThingsboardException;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class AuditLogController extends BaseController {
|
||||
|
||||
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
|
||||
@RequestMapping(value = "/audit/logs/{entityType}/{entityId}", params = {"limit"}, method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"limit"}, method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public TimePageData<AuditLog> getAuditLogs(
|
||||
public TimePageData<AuditLog> getAuditLogsByCustomerId(
|
||||
@PathVariable("customerId") String strCustomerId,
|
||||
@RequestParam int limit,
|
||||
@RequestParam(required = false) Long startTime,
|
||||
@RequestParam(required = false) Long endTime,
|
||||
@RequestParam(required = false, defaultValue = "false") boolean ascOrder,
|
||||
@RequestParam(required = false) String offset) throws ThingsboardException {
|
||||
try {
|
||||
checkParameter("CustomerId", strCustomerId);
|
||||
TenantId tenantId = getCurrentUser().getTenantId();
|
||||
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
|
||||
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndCustomerId(tenantId, new CustomerId(UUID.fromString(strCustomerId)), pageLink));
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
|
||||
@RequestMapping(value = "/audit/logs/user/{userId}", params = {"limit"}, method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public TimePageData<AuditLog> getAuditLogsByUserId(
|
||||
@PathVariable("userId") String strUserId,
|
||||
@RequestParam int limit,
|
||||
@RequestParam(required = false) Long startTime,
|
||||
@RequestParam(required = false) Long endTime,
|
||||
@RequestParam(required = false, defaultValue = "false") boolean ascOrder,
|
||||
@RequestParam(required = false) String offset) throws ThingsboardException {
|
||||
try {
|
||||
checkParameter("UserId", strUserId);
|
||||
TenantId tenantId = getCurrentUser().getTenantId();
|
||||
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
|
||||
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndUserId(tenantId, new UserId(UUID.fromString(strUserId)), pageLink));
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
|
||||
@RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"limit"}, method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public TimePageData<AuditLog> getAuditLogsByEntityId(
|
||||
@PathVariable("entityType") String strEntityType,
|
||||
@PathVariable("entityId") String strEntityId,
|
||||
@RequestParam int limit,
|
||||
|
||||
@ -85,12 +85,16 @@ public class DeviceController extends BaseController {
|
||||
savedDevice.getName(),
|
||||
savedDevice.getType());
|
||||
|
||||
// TODO: refactor to ANNOTATION usage
|
||||
if (device.getId() == null) {
|
||||
logDeviceAction(savedDevice, ActionType.ADDED);
|
||||
} else {
|
||||
logDeviceAction(savedDevice, ActionType.UPDATED);
|
||||
}
|
||||
auditLogService.logEntityAction(
|
||||
getCurrentUser(),
|
||||
savedDevice.getId(),
|
||||
savedDevice.getName(),
|
||||
savedDevice.getCustomerId(),
|
||||
device.getId() == null ? ActionType.ADDED : ActionType.UPDATED,
|
||||
null,
|
||||
ActionStatus.SUCCESS,
|
||||
null);
|
||||
|
||||
|
||||
return savedDevice;
|
||||
} catch (Exception e) {
|
||||
@ -107,8 +111,15 @@ public class DeviceController extends BaseController {
|
||||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
|
||||
Device device = checkDeviceId(deviceId);
|
||||
deviceService.deleteDevice(deviceId);
|
||||
// TODO: refactor to ANNOTATION usage
|
||||
logDeviceAction(device, ActionType.DELETED);
|
||||
auditLogService.logEntityAction(
|
||||
getCurrentUser(),
|
||||
device.getId(),
|
||||
device.getName(),
|
||||
device.getCustomerId(),
|
||||
ActionType.DELETED,
|
||||
null,
|
||||
ActionStatus.SUCCESS,
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
@ -189,8 +200,15 @@ public class DeviceController extends BaseController {
|
||||
Device device = checkDeviceId(deviceCredentials.getDeviceId());
|
||||
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials));
|
||||
actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId());
|
||||
// TODO: refactor to ANNOTATION usage
|
||||
logDeviceAction(device, ActionType.CREDENTIALS_UPDATED);
|
||||
auditLogService.logEntityAction(
|
||||
getCurrentUser(),
|
||||
device.getId(),
|
||||
device.getName(),
|
||||
device.getCustomerId(),
|
||||
ActionType.CREDENTIALS_UPDATED,
|
||||
null,
|
||||
ActionStatus.SUCCESS,
|
||||
null);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
@ -321,19 +339,4 @@ public class DeviceController extends BaseController {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: refactor to ANNOTATION usage
|
||||
private void logDeviceAction(Device device, ActionType actionType) throws ThingsboardException {
|
||||
auditLogService.logAction(
|
||||
getCurrentUser().getTenantId(),
|
||||
device.getId(),
|
||||
device.getName(),
|
||||
device.getCustomerId(),
|
||||
getCurrentUser().getId(),
|
||||
getCurrentUser().getName(),
|
||||
actionType,
|
||||
null,
|
||||
ActionStatus.SUCCESS,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +244,6 @@ spring:
|
||||
username: "${SPRING_DATASOURCE_USERNAME:sa}"
|
||||
password: "${SPRING_DATASOURCE_PASSWORD:}"
|
||||
|
||||
|
||||
# PostgreSQL DAO Configuration
|
||||
#spring:
|
||||
# data:
|
||||
@ -260,3 +259,8 @@ spring:
|
||||
# url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}"
|
||||
# username: "${SPRING_DATASOURCE_USERNAME:postgres}"
|
||||
# password: "${SPRING_DATASOURCE_PASSWORD:postgres}"
|
||||
|
||||
# Audit log parameters
|
||||
audit_log:
|
||||
# Enable/disable audit log functionality.
|
||||
enabled: "${AUDIT_LOG_ENABLED:true}"
|
||||
@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.page.TimePageData;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.dao.model.ModelConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -36,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
public abstract class BaseAuditLogControllerTest extends AbstractControllerTest {
|
||||
|
||||
private Tenant savedTenant;
|
||||
private User tenantAdmin;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
@ -46,14 +48,14 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest
|
||||
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
|
||||
Assert.assertNotNull(savedTenant);
|
||||
|
||||
User tenantAdmin = new User();
|
||||
tenantAdmin = new User();
|
||||
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
|
||||
tenantAdmin.setTenantId(savedTenant.getId());
|
||||
tenantAdmin.setEmail("tenant2@thingsboard.org");
|
||||
tenantAdmin.setFirstName("Joe");
|
||||
tenantAdmin.setLastName("Downs");
|
||||
|
||||
createUserAndLogin(tenantAdmin, "testPassword1");
|
||||
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
|
||||
}
|
||||
|
||||
@After
|
||||
@ -65,7 +67,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveDeviceAuditLogs() throws Exception {
|
||||
public void testAuditLogs() throws Exception {
|
||||
for (int i = 0; i < 178; i++) {
|
||||
Device device = new Device();
|
||||
device.setName("Device" + i);
|
||||
@ -87,10 +89,38 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Assert.assertEquals(178, loadedAuditLogs.size());
|
||||
|
||||
loadedAuditLogs = new ArrayList<>();
|
||||
pageLink = new TimePageLink(23);
|
||||
do {
|
||||
pageData = doGetTypedWithTimePageLink("/api/audit/logs/customer/" + ModelConstants.NULL_UUID + "?",
|
||||
new TypeReference<TimePageData<AuditLog>>() {
|
||||
}, pageLink);
|
||||
loadedAuditLogs.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageData.getNextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Assert.assertEquals(178, loadedAuditLogs.size());
|
||||
|
||||
loadedAuditLogs = new ArrayList<>();
|
||||
pageLink = new TimePageLink(23);
|
||||
do {
|
||||
pageData = doGetTypedWithTimePageLink("/api/audit/logs/user/" + tenantAdmin.getId().getId().toString() + "?",
|
||||
new TypeReference<TimePageData<AuditLog>>() {
|
||||
}, pageLink);
|
||||
loadedAuditLogs.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageData.getNextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Assert.assertEquals(178, loadedAuditLogs.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDeviceAuditLogs() throws Exception {
|
||||
public void testAuditLogs_byTenantIdAndEntityId() throws Exception {
|
||||
Device device = new Device();
|
||||
device.setName("Device name");
|
||||
device.setType("default");
|
||||
@ -104,7 +134,7 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest
|
||||
TimePageLink pageLink = new TimePageLink(23);
|
||||
TimePageData<AuditLog> pageData;
|
||||
do {
|
||||
pageData = doGetTypedWithTimePageLink("/api/audit/logs/DEVICE/" + savedDevice.getId().getId() + "?",
|
||||
pageData = doGetTypedWithTimePageLink("/api/audit/logs/entity/DEVICE/" + savedDevice.getId().getId() + "?",
|
||||
new TypeReference<TimePageData<AuditLog>>() {
|
||||
}, pageLink);
|
||||
loadedAuditLogs.addAll(pageData.getData());
|
||||
|
||||
@ -17,7 +17,9 @@ package org.thingsboard.server.dao.audit;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
|
||||
import java.util.List;
|
||||
@ -29,9 +31,17 @@ public interface AuditLogDao {
|
||||
|
||||
ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog);
|
||||
|
||||
ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog);
|
||||
|
||||
ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog);
|
||||
|
||||
ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog);
|
||||
|
||||
List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink);
|
||||
|
||||
List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink);
|
||||
|
||||
List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink);
|
||||
|
||||
List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink);
|
||||
}
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.dao.audit;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.dao.model.nosql.AuditLogEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuditLogQueryCursor {
|
||||
@Getter
|
||||
private final UUID tenantId;
|
||||
@Getter
|
||||
private final List<AuditLogEntity> data;
|
||||
@Getter
|
||||
private final TimePageLink pageLink;
|
||||
|
||||
private final List<Long> partitions;
|
||||
|
||||
private int partitionIndex;
|
||||
private int currentLimit;
|
||||
|
||||
public AuditLogQueryCursor(UUID tenantId, TimePageLink pageLink, List<Long> partitions) {
|
||||
this.tenantId = tenantId;
|
||||
this.partitions = partitions;
|
||||
this.partitionIndex = partitions.size() - 1;
|
||||
this.data = new ArrayList<>();
|
||||
this.currentLimit = pageLink.getLimit();
|
||||
this.pageLink = pageLink;
|
||||
}
|
||||
|
||||
public boolean hasNextPartition() {
|
||||
return partitionIndex >= 0;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return currentLimit <= 0;
|
||||
}
|
||||
|
||||
public long getNextPartition() {
|
||||
long partition = partitions.get(partitionIndex);
|
||||
partitionIndex--;
|
||||
return partition;
|
||||
}
|
||||
|
||||
public int getCurrentLimit() {
|
||||
return currentLimit;
|
||||
}
|
||||
|
||||
public void addData(List<AuditLogEntity> newData) {
|
||||
currentLimit -= newData.size();
|
||||
data.addAll(newData);
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ package org.thingsboard.server.dao.audit;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.audit.ActionStatus;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
@ -31,20 +32,21 @@ import java.util.List;
|
||||
|
||||
public interface AuditLogService {
|
||||
|
||||
TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink);
|
||||
|
||||
TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink);
|
||||
|
||||
TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink);
|
||||
|
||||
TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink);
|
||||
|
||||
ListenableFuture<List<Void>> logAction(TenantId tenantId,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
CustomerId customerId,
|
||||
UserId userId,
|
||||
String userName,
|
||||
ActionType actionType,
|
||||
JsonNode actionData,
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails);
|
||||
|
||||
ListenableFuture<List<Void>> logEntityAction(User user,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
CustomerId customerId,
|
||||
ActionType actionType,
|
||||
JsonNode actionData,
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails);
|
||||
|
||||
}
|
||||
|
||||
@ -15,20 +15,20 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.audit;
|
||||
|
||||
import com.datastax.driver.core.utils.UUIDs;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.audit.ActionStatus;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.id.*;
|
||||
import org.thingsboard.server.common.data.page.TimePageData;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
@ -41,6 +41,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "true")
|
||||
public class AuditLogServiceImpl implements AuditLogService {
|
||||
|
||||
private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
@ -49,6 +50,24 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
@Autowired
|
||||
private AuditLogDao auditLogDao;
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) {
|
||||
log.trace("Executing findAuditLogsByTenantIdAndCustomerId [{}], [{}], [{}]", tenantId, customerId, pageLink);
|
||||
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
|
||||
validateId(customerId, "Incorrect customerId " + customerId);
|
||||
List<AuditLog> auditLogs = auditLogDao.findAuditLogsByTenantIdAndCustomerId(tenantId.getId(), customerId, pageLink);
|
||||
return new TimePageData<>(auditLogs, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) {
|
||||
log.trace("Executing findAuditLogsByTenantIdAndUserId [{}], [{}], [{}]", tenantId, userId, pageLink);
|
||||
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
|
||||
validateId(userId, "Incorrect userId" + userId);
|
||||
List<AuditLog> auditLogs = auditLogDao.findAuditLogsByTenantIdAndUserId(tenantId.getId(), userId, pageLink);
|
||||
return new TimePageData<>(auditLogs, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) {
|
||||
log.trace("Executing findAuditLogsByTenantIdAndEntityId [{}], [{}], [{}]", tenantId, entityId, pageLink);
|
||||
@ -66,6 +85,28 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
return new TimePageData<>(auditLogs, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<List<Void>> logEntityAction(User user,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
CustomerId customerId,
|
||||
ActionType actionType,
|
||||
JsonNode actionData,
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails) {
|
||||
return logAction(
|
||||
user.getTenantId(),
|
||||
entityId,
|
||||
entityName,
|
||||
customerId,
|
||||
user.getId(),
|
||||
user.getName(),
|
||||
actionType,
|
||||
actionData,
|
||||
actionStatus,
|
||||
actionFailureDetails);
|
||||
}
|
||||
|
||||
private AuditLog createAuditLogEntry(TenantId tenantId,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
@ -77,6 +118,7 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails) {
|
||||
AuditLog result = new AuditLog();
|
||||
result.setId(new AuditLogId(UUIDs.timeBased()));
|
||||
result.setTenantId(tenantId);
|
||||
result.setEntityId(entityId);
|
||||
result.setEntityName(entityName);
|
||||
@ -90,17 +132,16 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<List<Void>> logAction(TenantId tenantId,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
CustomerId customerId,
|
||||
UserId userId,
|
||||
String userName,
|
||||
ActionType actionType,
|
||||
JsonNode actionData,
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails) {
|
||||
private ListenableFuture<List<Void>> logAction(TenantId tenantId,
|
||||
EntityId entityId,
|
||||
String entityName,
|
||||
CustomerId customerId,
|
||||
UserId userId,
|
||||
String userName,
|
||||
ActionType actionType,
|
||||
JsonNode actionData,
|
||||
ActionStatus actionStatus,
|
||||
String actionFailureDetails) {
|
||||
AuditLog auditLogEntry = createAuditLogEntry(tenantId, entityId, entityName, customerId, userId, userName,
|
||||
actionType, actionData, actionStatus, actionFailureDetails);
|
||||
log.trace("Executing logAction [{}]", auditLogEntry);
|
||||
@ -109,6 +150,8 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
futures.add(auditLogDao.savePartitionsByTenantId(auditLogEntry));
|
||||
futures.add(auditLogDao.saveByTenantId(auditLogEntry));
|
||||
futures.add(auditLogDao.saveByTenantIdAndEntityId(auditLogEntry));
|
||||
futures.add(auditLogDao.saveByTenantIdAndCustomerId(auditLogEntry));
|
||||
futures.add(auditLogDao.saveByTenantIdAndUserId(auditLogEntry));
|
||||
return Futures.allAsList(futures);
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,8 @@ import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
import com.datastax.driver.core.utils.UUIDs;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
@ -29,8 +30,9 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.AuditLogId;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.model.ModelConstants;
|
||||
@ -52,6 +54,7 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
|
||||
import static org.thingsboard.server.dao.model.ModelConstants.*;
|
||||
@ -82,7 +85,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
private String partitioning;
|
||||
private TsPartitionDate tsFormat;
|
||||
|
||||
private PreparedStatement[] saveStmts;
|
||||
private PreparedStatement partitionInsertStmt;
|
||||
private PreparedStatement saveByTenantStmt;
|
||||
private PreparedStatement saveByTenantIdAndUserIdStmt;
|
||||
private PreparedStatement saveByTenantIdAndEntityIdStmt;
|
||||
private PreparedStatement saveByTenantIdAndCustomerIdStmt;
|
||||
|
||||
private boolean isInstall() {
|
||||
return environment.acceptsProfiles("install");
|
||||
@ -123,11 +130,9 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
public ListenableFuture<Void> saveByTenantId(AuditLog auditLog) {
|
||||
log.debug("Save saveByTenantId [{}] ", auditLog);
|
||||
|
||||
AuditLogId auditLogId = new AuditLogId(UUIDs.timeBased());
|
||||
|
||||
long partition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||
BoundStatement stmt = getSaveByTenantStmt().bind();
|
||||
stmt.setUUID(0, auditLogId.getId())
|
||||
stmt = stmt.setUUID(0, auditLog.getId().getId())
|
||||
.setUUID(1, auditLog.getTenantId().getId())
|
||||
.setUUID(2, auditLog.getEntityId().getId())
|
||||
.setString(3, auditLog.getEntityId().getEntityType().name())
|
||||
@ -140,17 +145,44 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
public ListenableFuture<Void> saveByTenantIdAndEntityId(AuditLog auditLog) {
|
||||
log.debug("Save saveByTenantIdAndEntityId [{}] ", auditLog);
|
||||
|
||||
AuditLogId auditLogId = new AuditLogId(UUIDs.timeBased());
|
||||
|
||||
BoundStatement stmt = getSaveByTenantIdAndEntityIdStmt().bind();
|
||||
stmt.setUUID(0, auditLogId.getId())
|
||||
.setUUID(1, auditLog.getTenantId().getId())
|
||||
.setUUID(2, auditLog.getEntityId().getId())
|
||||
.setString(3, auditLog.getEntityId().getEntityType().name())
|
||||
.setString(4, auditLog.getActionType().name());
|
||||
stmt = setSaveStmtVariables(stmt, auditLog);
|
||||
return getFuture(executeAsyncWrite(stmt), rs -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog) {
|
||||
log.debug("Save saveByTenantIdAndCustomerId [{}] ", auditLog);
|
||||
|
||||
BoundStatement stmt = getSaveByTenantIdAndCustomerIdStmt().bind();
|
||||
stmt = setSaveStmtVariables(stmt, auditLog);
|
||||
return getFuture(executeAsyncWrite(stmt), rs -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog) {
|
||||
log.debug("Save saveByTenantIdAndUserId [{}] ", auditLog);
|
||||
|
||||
BoundStatement stmt = getSaveByTenantIdAndUserIdStmt().bind();
|
||||
stmt = setSaveStmtVariables(stmt, auditLog);
|
||||
return getFuture(executeAsyncWrite(stmt), rs -> null);
|
||||
}
|
||||
|
||||
private BoundStatement setSaveStmtVariables(BoundStatement stmt, AuditLog auditLog) {
|
||||
return stmt.setUUID(0, auditLog.getId().getId())
|
||||
.setUUID(1, auditLog.getTenantId().getId())
|
||||
.setUUID(2, auditLog.getCustomerId().getId())
|
||||
.setUUID(3, auditLog.getEntityId().getId())
|
||||
.setString(4, auditLog.getEntityId().getEntityType().name())
|
||||
.setString(5, auditLog.getEntityName())
|
||||
.setUUID(6, auditLog.getUserId().getId())
|
||||
.setString(7, auditLog.getUserName())
|
||||
.setString(8, auditLog.getActionType().name())
|
||||
.setString(9, auditLog.getActionData() != null ? auditLog.getActionData().toString() : null)
|
||||
.setString(10, auditLog.getActionStatus().name())
|
||||
.setString(11, auditLog.getActionFailureDetails());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) {
|
||||
log.debug("Save savePartitionsByTenantId [{}] ", auditLog);
|
||||
@ -163,35 +195,66 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
return getFuture(executeAsyncWrite(stmt), rs -> null);
|
||||
}
|
||||
|
||||
private PreparedStatement getPartitionInsertStmt() {
|
||||
// TODO: ADD CACHE LOGIC
|
||||
return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF +
|
||||
"(" + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" +
|
||||
" VALUES(?, ?)");
|
||||
private PreparedStatement getSaveByTenantIdAndEntityIdStmt() {
|
||||
if (saveByTenantIdAndEntityIdStmt == null) {
|
||||
saveByTenantIdAndEntityIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_ENTITY_ID_CF);
|
||||
}
|
||||
return saveByTenantIdAndEntityIdStmt;
|
||||
}
|
||||
|
||||
private PreparedStatement getSaveByTenantIdAndEntityIdStmt() {
|
||||
// TODO: ADD CACHE LOGIC
|
||||
return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_ENTITY_ID_CF +
|
||||
private PreparedStatement getSaveByTenantIdAndCustomerIdStmt() {
|
||||
if (saveByTenantIdAndCustomerIdStmt == null) {
|
||||
saveByTenantIdAndCustomerIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_CUSTOMER_ID_CF);
|
||||
}
|
||||
return saveByTenantIdAndCustomerIdStmt;
|
||||
}
|
||||
|
||||
private PreparedStatement getSaveByTenantIdAndUserIdStmt() {
|
||||
if (saveByTenantIdAndUserIdStmt == null) {
|
||||
saveByTenantIdAndUserIdStmt = getSaveByTenantIdAndCFName(ModelConstants.AUDIT_LOG_BY_USER_ID_CF);
|
||||
}
|
||||
return saveByTenantIdAndUserIdStmt;
|
||||
}
|
||||
|
||||
private PreparedStatement getSaveByTenantIdAndCFName(String cfName) {
|
||||
return getSession().prepare(INSERT_INTO + cfName +
|
||||
"(" + ModelConstants.AUDIT_LOG_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_CUSTOMER_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY + ")" +
|
||||
" VALUES(?, ?, ?, ?, ?)");
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_NAME_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_USER_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_USER_NAME_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_DATA_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_STATUS_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_FAILURE_DETAILS_PROPERTY + ")" +
|
||||
" VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
}
|
||||
|
||||
private PreparedStatement getPartitionInsertStmt() {
|
||||
if (partitionInsertStmt == null) {
|
||||
partitionInsertStmt = getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF +
|
||||
"(" + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" +
|
||||
" VALUES(?, ?)");
|
||||
}
|
||||
return partitionInsertStmt;
|
||||
}
|
||||
|
||||
private PreparedStatement getSaveByTenantStmt() {
|
||||
// TODO: ADD CACHE LOGIC
|
||||
return getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_CF +
|
||||
"(" + ModelConstants.AUDIT_LOG_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" +
|
||||
" VALUES(?, ?, ?, ?, ?, ?)");
|
||||
if (saveByTenantStmt == null) {
|
||||
saveByTenantStmt = getSession().prepare(INSERT_INTO + ModelConstants.AUDIT_LOG_BY_TENANT_ID_CF +
|
||||
"(" + ModelConstants.AUDIT_LOG_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_ACTION_TYPE_PROPERTY +
|
||||
"," + ModelConstants.AUDIT_LOG_PARTITION_PROPERTY + ")" +
|
||||
" VALUES(?, ?, ?, ?, ?, ?)");
|
||||
}
|
||||
return saveByTenantStmt;
|
||||
}
|
||||
|
||||
private long toPartitionTs(long ts) {
|
||||
@ -199,7 +262,6 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
return tsFormat.truncatedTo(time).toInstant(ZoneOffset.UTC).toEpochMilli();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink) {
|
||||
log.trace("Try to find audit logs by tenant [{}], entity [{}] and pageLink [{}]", tenantId, entityId, pageLink);
|
||||
@ -212,31 +274,76 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
||||
return DaoUtil.convertDataList(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink) {
|
||||
log.trace("Try to find audit logs by tenant [{}], customer [{}] and pageLink [{}]", tenantId, customerId, pageLink);
|
||||
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_CUSTOMER_ID_CF,
|
||||
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
|
||||
eq(ModelConstants.AUDIT_LOG_CUSTOMER_ID_PROPERTY, customerId.getId())),
|
||||
pageLink);
|
||||
log.trace("Found audit logs by tenant [{}], customer [{}] and pageLink [{}]", tenantId, customerId, pageLink);
|
||||
return DaoUtil.convertDataList(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink) {
|
||||
log.trace("Try to find audit logs by tenant [{}], user [{}] and pageLink [{}]", tenantId, userId, pageLink);
|
||||
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_USER_ID_CF,
|
||||
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
|
||||
eq(ModelConstants.AUDIT_LOG_USER_ID_PROPERTY, userId.getId())),
|
||||
pageLink);
|
||||
log.trace("Found audit logs by tenant [{}], user [{}] and pageLink [{}]", tenantId, userId, pageLink);
|
||||
return DaoUtil.convertDataList(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) {
|
||||
log.trace("Try to find audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink);
|
||||
|
||||
// TODO: ADD AUDIT LOG PARTITION CURSOR LOGIC
|
||||
|
||||
long minPartition;
|
||||
long maxPartition;
|
||||
|
||||
if (pageLink.getStartTime() != null && pageLink.getStartTime() != 0) {
|
||||
minPartition = toPartitionTs(pageLink.getStartTime());
|
||||
} else {
|
||||
minPartition = toPartitionTs(LocalDate.now().minusMonths(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||
}
|
||||
|
||||
long maxPartition;
|
||||
if (pageLink.getEndTime() != null && pageLink.getEndTime() != 0) {
|
||||
maxPartition = toPartitionTs(pageLink.getEndTime());
|
||||
} else {
|
||||
maxPartition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||
}
|
||||
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_TENANT_ID_CF,
|
||||
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
|
||||
eq(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY, maxPartition)),
|
||||
pageLink);
|
||||
|
||||
List<Long> partitions = fetchPartitions(tenantId, minPartition, maxPartition)
|
||||
.all()
|
||||
.stream()
|
||||
.map(row -> row.getLong(ModelConstants.PARTITION_COLUMN))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
AuditLogQueryCursor cursor = new AuditLogQueryCursor(tenantId, pageLink, partitions);
|
||||
List<AuditLogEntity> entities = fetchSequentiallyWithLimit(cursor);
|
||||
log.trace("Found audit logs by tenant [{}] and pageLink [{}]", tenantId, pageLink);
|
||||
return DaoUtil.convertDataList(entities);
|
||||
}
|
||||
|
||||
private List<AuditLogEntity> fetchSequentiallyWithLimit(AuditLogQueryCursor cursor) {
|
||||
if (cursor.isFull() || !cursor.hasNextPartition()) {
|
||||
return cursor.getData();
|
||||
} else {
|
||||
cursor.addData(findPageWithTimeSearch(AUDIT_LOG_BY_TENANT_ID_CF,
|
||||
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, cursor.getTenantId()),
|
||||
eq(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY, cursor.getNextPartition())),
|
||||
cursor.getPageLink()));
|
||||
return fetchSequentiallyWithLimit(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private ResultSet fetchPartitions(UUID tenantId, long minPartition, long maxPartition) {
|
||||
Select.Where select = QueryBuilder.select(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY).from(ModelConstants.AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF)
|
||||
.where(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId));
|
||||
select.and(QueryBuilder.gte(ModelConstants.PARTITION_COLUMN, minPartition));
|
||||
select.and(QueryBuilder.lte(ModelConstants.PARTITION_COLUMN, maxPartition));
|
||||
return getSession().execute(select);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.dao.audit;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.audit.ActionStatus;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.page.TimePageData;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "false")
|
||||
public class DummyAuditLogServiceImpl implements AuditLogService {
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<List<Void>> logEntityAction(User user, EntityId entityId, String entityName, CustomerId customerId, ActionType actionType, JsonNode actionData, ActionStatus actionStatus, String actionFailureDetails) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -147,6 +147,8 @@ public class ModelConstants {
|
||||
public static final String AUDIT_LOG_COLUMN_FAMILY_NAME = "audit_log";
|
||||
|
||||
public static final String AUDIT_LOG_BY_ENTITY_ID_CF = "audit_log_by_entity_id";
|
||||
public static final String AUDIT_LOG_BY_CUSTOMER_ID_CF = "audit_log_by_customer_id";
|
||||
public static final String AUDIT_LOG_BY_USER_ID_CF = "audit_log_by_user_id";
|
||||
public static final String AUDIT_LOG_BY_TENANT_ID_CF = "audit_log_by_tenant_id";
|
||||
public static final String AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF = "audit_log_by_tenant_id_partitions";
|
||||
|
||||
|
||||
@ -41,4 +41,20 @@ public interface AuditLogRepository extends CrudRepository<AuditLogEntity, Strin
|
||||
@Param("entityType") EntityType entityType,
|
||||
@Param("idOffset") String idOffset,
|
||||
Pageable pageable);
|
||||
|
||||
@Query("SELECT al FROM AuditLogEntity al WHERE al.tenantId = :tenantId " +
|
||||
"AND al.customerId = :customerId " +
|
||||
"AND al.id > :idOffset ORDER BY al.id")
|
||||
List<AuditLogEntity> findByTenantIdAndCustomerId(@Param("tenantId") String tenantId,
|
||||
@Param("customerId") String customerId,
|
||||
@Param("idOffset") String idOffset,
|
||||
Pageable pageable);
|
||||
|
||||
@Query("SELECT al FROM AuditLogEntity al WHERE al.tenantId = :tenantId " +
|
||||
"AND al.userId = :userId " +
|
||||
"AND al.id > :idOffset ORDER BY al.id")
|
||||
List<AuditLogEntity> findByTenantIdAndUserId(@Param("tenantId") String tenantId,
|
||||
@Param("userId") String userId,
|
||||
@Param("idOffset") String idOffset,
|
||||
Pageable pageable);
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.audit.AuditLog;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.audit.AuditLogDao;
|
||||
@ -76,6 +78,16 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp
|
||||
return insertService.submit(() -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> saveByTenantIdAndCustomerId(AuditLog auditLog) {
|
||||
return insertService.submit(() -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> saveByTenantIdAndUserId(AuditLog auditLog) {
|
||||
return insertService.submit(() -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> savePartitionsByTenantId(AuditLog auditLog) {
|
||||
return insertService.submit(() -> null);
|
||||
@ -92,6 +104,26 @@ public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> imp
|
||||
new PageRequest(0, pageLink.getLimit())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink) {
|
||||
return DaoUtil.convertDataList(
|
||||
auditLogRepository.findByTenantIdAndCustomerId(
|
||||
fromTimeUUID(tenantId),
|
||||
fromTimeUUID(customerId.getId()),
|
||||
pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
|
||||
new PageRequest(0, pageLink.getLimit())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink) {
|
||||
return DaoUtil.convertDataList(
|
||||
auditLogRepository.findByTenantIdAndUserId(
|
||||
fromTimeUUID(tenantId),
|
||||
fromTimeUUID(userId.getId()),
|
||||
pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
|
||||
new PageRequest(0, pageLink.getLimit())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditLog> findAuditLogsByTenantId(UUID tenantId, TimePageLink pageLink) {
|
||||
return DaoUtil.convertDataList(
|
||||
|
||||
@ -566,6 +566,40 @@ CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_entity_id (
|
||||
PRIMARY KEY ((tenant_id, entity_id, entity_type), id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_customer_id (
|
||||
tenant_id timeuuid,
|
||||
id timeuuid,
|
||||
customer_id timeuuid,
|
||||
entity_id timeuuid,
|
||||
entity_type text,
|
||||
entity_name text,
|
||||
user_id timeuuid,
|
||||
user_name text,
|
||||
action_type text,
|
||||
action_data text,
|
||||
action_status text,
|
||||
action_failure_details text,
|
||||
PRIMARY KEY ((tenant_id, customer_id), id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_user_id (
|
||||
tenant_id timeuuid,
|
||||
id timeuuid,
|
||||
customer_id timeuuid,
|
||||
entity_id timeuuid,
|
||||
entity_type text,
|
||||
entity_name text,
|
||||
user_id timeuuid,
|
||||
user_name text,
|
||||
action_type text,
|
||||
action_data text,
|
||||
action_status text,
|
||||
action_failure_details text,
|
||||
PRIMARY KEY ((tenant_id, user_id), id)
|
||||
);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id (
|
||||
tenant_id timeuuid,
|
||||
id timeuuid,
|
||||
|
||||
@ -7,4 +7,6 @@ zk.enabled=false
|
||||
zk.url=localhost:2181
|
||||
zk.zk_dir=/thingsboard
|
||||
|
||||
updates.enabled=false
|
||||
updates.enabled=false
|
||||
|
||||
audit_log.enabled=true
|
||||
Loading…
x
Reference in New Issue
Block a user