From 7625462eaeb594ad90cb757c4f8a2ec56c54ed8e Mon Sep 17 00:00:00 2001 From: Francesco Date: Fri, 10 Nov 2023 10:20:03 +0100 Subject: [PATCH] Search by username in audit logs (#34) --- .../external/controller/GlobalController.java | 1 - .../dbmapping/query/DbQueryOutputField.java | 5 +++ .../dbmapping/query/DbQueryResult.java | 4 ++ .../dbmapping/query/DbQueryResultRow.java | 4 ++ .../external/dto/LogsSearchRequest.java | 13 +++++++ .../dto/ValidationErrorsContainer.java | 4 ++ .../SnapAdminForbiddenException.java | 38 ------------------- .../repository/CustomActionRepository.java | 2 +- .../CustomActionRepositoryImpl.java | 16 ++++++-- .../internal/service/UserActionService.java | 5 +-- src/main/resources/templates/logs.html | 3 ++ 11 files changed, 48 insertions(+), 47 deletions(-) delete mode 100644 src/main/java/tech/ailef/snapadmin/external/exceptions/SnapAdminForbiddenException.java diff --git a/src/main/java/tech/ailef/snapadmin/external/controller/GlobalController.java b/src/main/java/tech/ailef/snapadmin/external/controller/GlobalController.java index bb5c57f..26422f0 100644 --- a/src/main/java/tech/ailef/snapadmin/external/controller/GlobalController.java +++ b/src/main/java/tech/ailef/snapadmin/external/controller/GlobalController.java @@ -33,7 +33,6 @@ import jakarta.servlet.http.HttpServletResponse; import tech.ailef.snapadmin.external.SnapAdmin; import tech.ailef.snapadmin.external.SnapAdminProperties; import tech.ailef.snapadmin.external.exceptions.SnapAdminException; -import tech.ailef.snapadmin.external.exceptions.SnapAdminForbiddenException; import tech.ailef.snapadmin.external.exceptions.SnapAdminNotFoundException; import tech.ailef.snapadmin.internal.UserConfiguration; diff --git a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryOutputField.java b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryOutputField.java index 7e44755..16e4b11 100644 --- a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryOutputField.java +++ b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryOutputField.java @@ -30,6 +30,11 @@ import tech.ailef.snapadmin.external.dbmapping.fields.DbFieldType; import tech.ailef.snapadmin.external.exceptions.SnapAdminException; import tech.ailef.snapadmin.external.exceptions.UnsupportedFieldTypeException; +/* + * A class that holds output fields from a user-provided SQL query + * run in the SQL console. If possible, this field is mapped to a proper + * {@link Dbfield} object, otherwise it is left as a raw object. + */ public class DbQueryOutputField { private String name; diff --git a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResult.java b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResult.java index 3f234bb..0c005b7 100644 --- a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResult.java +++ b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResult.java @@ -23,6 +23,10 @@ package tech.ailef.snapadmin.external.dbmapping.query; import java.util.ArrayList; import java.util.List; +/** + * A wrapper for results returned by user-provided SQL queries run via + * the SQL console. + */ public class DbQueryResult { private List rows; diff --git a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResultRow.java b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResultRow.java index b67f90b..75e588e 100644 --- a/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResultRow.java +++ b/src/main/java/tech/ailef/snapadmin/external/dbmapping/query/DbQueryResultRow.java @@ -26,6 +26,10 @@ import java.util.Map; import tech.ailef.snapadmin.external.exceptions.SnapAdminException; +/** + * A single row of results coming from a user-provided SQL query + * run via the SQL console. + */ public class DbQueryResultRow { private Map values; diff --git a/src/main/java/tech/ailef/snapadmin/external/dto/LogsSearchRequest.java b/src/main/java/tech/ailef/snapadmin/external/dto/LogsSearchRequest.java index 313ac47..7b910b6 100644 --- a/src/main/java/tech/ailef/snapadmin/external/dto/LogsSearchRequest.java +++ b/src/main/java/tech/ailef/snapadmin/external/dto/LogsSearchRequest.java @@ -64,6 +64,11 @@ public class LogsSearchRequest implements FilterRequest { * The requested sort order, possibly null */ private String sortOrder; + + /** + * The requested username filter + */ + private String username; /** * Returns the table specified in this search request. If the value is blank or 'Any', @@ -170,6 +175,14 @@ public class LogsSearchRequest implements FilterRequest { + page + ", pageSize=" + pageSize + ", sortKey=" + sortKey + ", sortOrder=" + sortOrder + "]"; } + public void setUsername(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + /** * Build a Spring PageRequest object from the parameters in this request * @return a Spring PageRequest object diff --git a/src/main/java/tech/ailef/snapadmin/external/dto/ValidationErrorsContainer.java b/src/main/java/tech/ailef/snapadmin/external/dto/ValidationErrorsContainer.java index 5ba0869..6165756 100644 --- a/src/main/java/tech/ailef/snapadmin/external/dto/ValidationErrorsContainer.java +++ b/src/main/java/tech/ailef/snapadmin/external/dto/ValidationErrorsContainer.java @@ -26,6 +26,10 @@ import java.util.Map; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; +/** + * Holds information about JPA validation errors occurring during + * creation or editing of items. + */ public class ValidationErrorsContainer { private Map>> errors = new HashMap<>(); diff --git a/src/main/java/tech/ailef/snapadmin/external/exceptions/SnapAdminForbiddenException.java b/src/main/java/tech/ailef/snapadmin/external/exceptions/SnapAdminForbiddenException.java deleted file mode 100644 index 51e6ec6..0000000 --- a/src/main/java/tech/ailef/snapadmin/external/exceptions/SnapAdminForbiddenException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SnapAdmin - An automatically generated CRUD admin UI for Spring Boot apps - - * Copyright (C) 2023 Ailef (http://ailef.tech) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -package tech.ailef.snapadmin.external.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ResponseStatusException; - -public class SnapAdminForbiddenException extends ResponseStatusException { - private static final long serialVersionUID = 4090093290330473479L; - - public SnapAdminForbiddenException(String message) { - super(HttpStatus.NOT_FOUND, message); - } - - @Override - public String getMessage() { - return getReason(); - } - -} diff --git a/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepository.java b/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepository.java index 89338d4..b8b8ee0 100644 --- a/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepository.java +++ b/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepository.java @@ -27,6 +27,6 @@ import tech.ailef.snapadmin.internal.model.UserAction; public interface CustomActionRepository { public List findActions(LogsSearchRequest r); - public long countActions(String table, String actionType, String itemId); + public long countActions(LogsSearchRequest request); } diff --git a/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepositoryImpl.java b/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepositoryImpl.java index 07a16ee..f1a4c2d 100644 --- a/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepositoryImpl.java +++ b/src/main/java/tech/ailef/snapadmin/internal/repository/CustomActionRepositoryImpl.java @@ -54,6 +54,7 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { public List findActions(LogsSearchRequest request) { String table = request.getTable(); String actionType = request.getActionType(); + String username = request.getUsername(); String itemId = request.getItemId(); PageRequest page = request.toPageRequest(); @@ -68,7 +69,9 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { predicates.add(cb.equal(userAction.get("actionType"), actionType)); if (itemId != null) predicates.add(cb.equal(userAction.get("primaryKey"), itemId)); - + if (username != null) + predicates.add(cb.equal(userAction.get("username"), username)); + if (!predicates.isEmpty()) { query.select(userAction) .where(cb.and( @@ -95,12 +98,17 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { * @return the number of user actions matching the filtering parameters */ @Override - public long countActions(String table, String actionType, String itemId) { + public long countActions(LogsSearchRequest request) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(Long.class); Root userAction = query.from(UserAction.class); + String table = request.getTable(); + String actionType = request.getActionType(); + String itemId = request.getItemId(); + String username = request.getUsername(); + List predicates = new ArrayList<>(); if (table != null) predicates.add(cb.equal(userAction.get("onTable"), table)); @@ -108,7 +116,9 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { predicates.add(cb.equal(userAction.get("actionType"), actionType)); if (itemId != null) predicates.add(cb.equal(userAction.get("primaryKey"), itemId)); - + if (username != null) + predicates.add(cb.equal(userAction.get("username"), username)); + if (!predicates.isEmpty()) { query.select(cb.count(userAction)) .where(cb.and( diff --git a/src/main/java/tech/ailef/snapadmin/internal/service/UserActionService.java b/src/main/java/tech/ailef/snapadmin/internal/service/UserActionService.java index 97a9026..9817487 100644 --- a/src/main/java/tech/ailef/snapadmin/internal/service/UserActionService.java +++ b/src/main/java/tech/ailef/snapadmin/internal/service/UserActionService.java @@ -60,12 +60,9 @@ public class UserActionService { * @return a page of results matching the input request */ public PaginatedResult findActions(LogsSearchRequest request) { - String table = request.getTable(); - String actionType = request.getActionType(); - String itemId = request.getItemId(); PageRequest page = request.toPageRequest(); - long count = customRepo.countActions(table, actionType, itemId); + long count = customRepo.countActions(request); List actions = customRepo.findActions(request); int maxPage = (int)(Math.ceil ((double)count / page.getPageSize())); diff --git a/src/main/resources/templates/logs.html b/src/main/resources/templates/logs.html index fb13575..c7e78cb 100644 --- a/src/main/resources/templates/logs.html +++ b/src/main/resources/templates/logs.html @@ -44,6 +44,9 @@ Item ID + User +