From fa51f1110917afdae791a43d94d30d428c6ad123 Mon Sep 17 00:00:00 2001 From: Francesco Date: Sat, 30 Sep 2023 11:22:56 +0200 Subject: [PATCH] Implemented sorting on Action logs and standardized filtering/pagination mechanics --- .../controller/DefaultDbAdminController.java | 11 ++--- .../external/dbmapping/DbAdminRepository.java | 6 +-- .../external/dto/FacetedSearchRequest.java | 35 ++++++++++++++ .../dbadmin/external/dto/FilterRequest.java | 12 +++++ .../external/dto/LogsSearchRequest.java | 17 ++++++- .../dbadmin/external/dto/PaginationInfo.java | 17 ++++--- .../ailef/dbadmin/external/misc/Utils.java | 36 +++++++------- .../repository/CustomActionRepository.java | 5 +- .../CustomActionRepositoryImpl.java | 16 ++++++- .../internal/service/UserActionService.java | 14 ++++-- .../templates/fragments/table_selectable.html | 36 ++++++++------ src/main/resources/templates/logs.html | 48 +++++++++++++++++-- 12 files changed, 190 insertions(+), 63 deletions(-) create mode 100644 src/main/java/tech/ailef/dbadmin/external/dto/FacetedSearchRequest.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dto/FilterRequest.java diff --git a/src/main/java/tech/ailef/dbadmin/external/controller/DefaultDbAdminController.java b/src/main/java/tech/ailef/dbadmin/external/controller/DefaultDbAdminController.java index dbeb90f..98ff9d2 100644 --- a/src/main/java/tech/ailef/dbadmin/external/controller/DefaultDbAdminController.java +++ b/src/main/java/tech/ailef/dbadmin/external/controller/DefaultDbAdminController.java @@ -33,6 +33,7 @@ import tech.ailef.dbadmin.external.dbmapping.DbAdminRepository; import tech.ailef.dbadmin.external.dbmapping.DbObject; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.dto.FacetedSearchRequest; import tech.ailef.dbadmin.external.dto.LogsSearchRequest; import tech.ailef.dbadmin.external.dto.PaginatedResult; import tech.ailef.dbadmin.external.dto.QueryFilter; @@ -140,7 +141,8 @@ public class DefaultDbAdminController { queryFilters.removeIf(f -> f.equals(toRemove)); } - MultiValueMap parameterMap = Utils.computeParams(queryFilters); + FacetedSearchRequest filterRequest = new FacetedSearchRequest(queryFilters); + MultiValueMap parameterMap = filterRequest.computeParams(); MultiValueMap filteredParams = new LinkedMultiValueMap<>(); request.getParameterMap().entrySet().stream() @@ -437,12 +439,7 @@ public class DefaultDbAdminController { model.addAttribute("activePage", "logs"); model.addAttribute( "page", - userActionService.findActions( - searchRequest.getTable(), - searchRequest.getActionType(), - searchRequest.getItemId(), - searchRequest.toPageRequest() - ) + userActionService.findActions(searchRequest) ); model.addAttribute("schemas", dbAdmin.getSchemas()); model.addAttribute("searchRequest", searchRequest); diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java index 6f22b46..5b401c9 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java @@ -3,7 +3,6 @@ package tech.ailef.dbadmin.external.dbmapping; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -21,6 +20,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import tech.ailef.dbadmin.external.dto.FacetedSearchRequest; import tech.ailef.dbadmin.external.dto.PaginatedResult; import tech.ailef.dbadmin.external.dto.PaginationInfo; import tech.ailef.dbadmin.external.dto.QueryFilter; @@ -118,7 +118,7 @@ public class DbAdminRepository { return new PaginatedResult( - new PaginationInfo(page, maxPage, pageSize, maxElement, null, new HashSet<>()), + new PaginationInfo(page, maxPage, pageSize, maxElement, null, null), results ); } @@ -231,7 +231,7 @@ public class DbAdminRepository { } return new PaginatedResult( - new PaginationInfo(page, maxPage, pageSize, maxElement, query, queryFilters), + new PaginationInfo(page, maxPage, pageSize, maxElement, query, new FacetedSearchRequest(queryFilters)), jpaRepository.search(query, page, pageSize, sortKey, sortOrder, queryFilters).stream() .map(o -> new DbObject(o, schema)) .toList() diff --git a/src/main/java/tech/ailef/dbadmin/external/dto/FacetedSearchRequest.java b/src/main/java/tech/ailef/dbadmin/external/dto/FacetedSearchRequest.java new file mode 100644 index 0000000..6371ce9 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dto/FacetedSearchRequest.java @@ -0,0 +1,35 @@ +package tech.ailef.dbadmin.external.dto; + +import java.util.ArrayList; +import java.util.Set; + +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class FacetedSearchRequest implements FilterRequest { + private Set filters; + + public FacetedSearchRequest(Set filters) { + this.filters = filters; + } + + @Override + public MultiValueMap computeParams() { + MultiValueMap r = new LinkedMultiValueMap<>(); + if (filters == null) + return r; + + r.put("filter_field", new ArrayList<>()); + r.put("filter_op", new ArrayList<>()); + r.put("filter_value", new ArrayList<>()); + + for (QueryFilter filter : filters) { + r.get("filter_field").add(filter.getField().getJavaName()); + r.get("filter_op").add(filter.getOp().toString()); + r.get("filter_value").add(filter.getValue()); + } + + return r; + } + +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dto/FilterRequest.java b/src/main/java/tech/ailef/dbadmin/external/dto/FilterRequest.java new file mode 100644 index 0000000..343a1ff --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dto/FilterRequest.java @@ -0,0 +1,12 @@ +package tech.ailef.dbadmin.external.dto; + +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public interface FilterRequest { + public MultiValueMap computeParams(); + + public static MultiValueMap empty() { + return new LinkedMultiValueMap<>(); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dto/LogsSearchRequest.java b/src/main/java/tech/ailef/dbadmin/external/dto/LogsSearchRequest.java index 3d66a3a..0179ad6 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dto/LogsSearchRequest.java +++ b/src/main/java/tech/ailef/dbadmin/external/dto/LogsSearchRequest.java @@ -2,13 +2,15 @@ package tech.ailef.dbadmin.external.dto; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; /** * A client request for the Action logs page where * several filtering parameters are present * */ -public class LogsSearchRequest { +public class LogsSearchRequest implements FilterRequest { /** * The table name to filter on */ @@ -124,5 +126,18 @@ public class LogsSearchRequest { return PageRequest.of(actualPage, actualPageSize, Sort.by(sortKey).ascending()); } } + + @Override + public MultiValueMap computeParams() { + LinkedMultiValueMap params = new LinkedMultiValueMap<>(); + if (table != null) + params.add("table", table); + if (itemId != null) + params.add("itemId", itemId); + if (actionType != null) + params.add("actionType", actionType); + + return params; + } } diff --git a/src/main/java/tech/ailef/dbadmin/external/dto/PaginationInfo.java b/src/main/java/tech/ailef/dbadmin/external/dto/PaginationInfo.java index 7e87237..d0e977c 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dto/PaginationInfo.java +++ b/src/main/java/tech/ailef/dbadmin/external/dto/PaginationInfo.java @@ -2,7 +2,6 @@ package tech.ailef.dbadmin.external.dto; import java.util.ArrayList; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -38,17 +37,17 @@ public class PaginationInfo { // TODO: Check if used private long maxElement; - private Set queryFilters; + private FilterRequest filterRequest; private String query; - public PaginationInfo(int currentPage, int maxPage, int pageSize, long maxElement, String query, Set queryFilters) { + public PaginationInfo(int currentPage, int maxPage, int pageSize, long maxElement, String query, FilterRequest request) { this.currentPage = currentPage; this.maxPage = maxPage; this.pageSize = pageSize; this.query = query; this.maxElement = maxElement; - this.queryFilters = queryFilters; + this.filterRequest = request; } public int getCurrentPage() { @@ -80,7 +79,10 @@ public class PaginationInfo { } public String getSortedPageLink(String sortKey, String sortOrder) { - MultiValueMap params = Utils.computeParams(queryFilters); + MultiValueMap params = FilterRequest.empty(); + + if (filterRequest != null) + params = filterRequest.computeParams(); if (query != null) { params.put("query", new ArrayList<>()); @@ -96,7 +98,10 @@ public class PaginationInfo { } public String getLink(int page) { - MultiValueMap params = Utils.computeParams(queryFilters); + MultiValueMap params = FilterRequest.empty(); + + if (filterRequest != null) + params = filterRequest.computeParams(); if (query != null) { params.put("query", new ArrayList<>()); diff --git a/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java b/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java index 24ec730..5f5aba2 100644 --- a/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java +++ b/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java @@ -1,12 +1,10 @@ package tech.ailef.dbadmin.external.misc; import java.util.ArrayList; - import java.util.HashSet; import java.util.List; import java.util.Set; -import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; @@ -61,23 +59,23 @@ public interface Utils { * @param filters * @return */ - public static MultiValueMap computeParams(Set filters) { - MultiValueMap r = new LinkedMultiValueMap<>(); - if (filters == null) - return r; - - r.put("filter_field", new ArrayList<>()); - r.put("filter_op", new ArrayList<>()); - r.put("filter_value", new ArrayList<>()); - - for (QueryFilter filter : filters) { - r.get("filter_field").add(filter.getField().getJavaName()); - r.get("filter_op").add(filter.getOp().toString()); - r.get("filter_value").add(filter.getValue()); - } - - return r; - } +// public static MultiValueMap computeParams(Set filters) { +// MultiValueMap r = new LinkedMultiValueMap<>(); +// if (filters == null) +// return r; +// +// r.put("filter_field", new ArrayList<>()); +// r.put("filter_op", new ArrayList<>()); +// r.put("filter_value", new ArrayList<>()); +// +// for (QueryFilter filter : filters) { +// r.get("filter_field").add(filter.getField().getJavaName()); +// r.get("filter_op").add(filter.getOp().toString()); +// r.get("filter_value").add(filter.getValue()); +// } +// +// return r; +// } /** * Converts a multi value map of parameters containing query filters applied diff --git a/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepository.java b/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepository.java index 50db002..4998dd1 100644 --- a/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepository.java +++ b/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepository.java @@ -2,12 +2,11 @@ package tech.ailef.dbadmin.internal.repository; import java.util.List; -import org.springframework.data.domain.PageRequest; - +import tech.ailef.dbadmin.external.dto.LogsSearchRequest; import tech.ailef.dbadmin.internal.model.UserAction; public interface CustomActionRepository { - public List findActions(String table, String actionType, String itemId, PageRequest pageRequest); + public List findActions(LogsSearchRequest r); public long countActions(String table, String actionType, String itemId); diff --git a/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepositoryImpl.java b/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepositoryImpl.java index 467b307..075a48c 100644 --- a/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepositoryImpl.java +++ b/src/main/java/tech/ailef/dbadmin/internal/repository/CustomActionRepositoryImpl.java @@ -12,6 +12,7 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import tech.ailef.dbadmin.external.dto.LogsSearchRequest; import tech.ailef.dbadmin.internal.model.UserAction; @Component @@ -21,7 +22,11 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { private EntityManager entityManager; @Override - public List findActions(String table, String actionType, String itemId, PageRequest page) { + public List findActions(LogsSearchRequest request) { + String table = request.getTable(); + String actionType = request.getActionType(); + String itemId = request.getItemId(); + PageRequest page = request.toPageRequest(); CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(UserAction.class); @@ -41,6 +46,15 @@ public class CustomActionRepositoryImpl implements CustomActionRepository { predicates.toArray(new Predicate[predicates.size()]))); } + if (request.getSortKey() != null) { + String key = request.getSortKey(); + if (request.getSortOrder().equalsIgnoreCase("ASC")) { + query.orderBy(cb.asc(userAction.get(key))); + } else { + query.orderBy(cb.desc(userAction.get(key))); + } + } + return entityManager.createQuery(query) .setMaxResults(page.getPageSize()) .setFirstResult((int)page.getOffset()) diff --git a/src/main/java/tech/ailef/dbadmin/internal/service/UserActionService.java b/src/main/java/tech/ailef/dbadmin/internal/service/UserActionService.java index cbd0a0c..90c3aee 100644 --- a/src/main/java/tech/ailef/dbadmin/internal/service/UserActionService.java +++ b/src/main/java/tech/ailef/dbadmin/internal/service/UserActionService.java @@ -7,6 +7,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import tech.ailef.dbadmin.external.dto.LogsSearchRequest; import tech.ailef.dbadmin.external.dto.PaginatedResult; import tech.ailef.dbadmin.external.dto.PaginationInfo; import tech.ailef.dbadmin.internal.model.UserAction; @@ -26,13 +27,18 @@ public class UserActionService { return repo.save(a); } - public PaginatedResult findActions(String table, String actionType, String userId, PageRequest page) { - long count = customRepo.countActions(table, actionType, userId); - List actions = customRepo.findActions(table, actionType, userId, page); + 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); + List actions = customRepo.findActions(request); int maxPage = (int)(Math.ceil ((double)count / page.getPageSize())); return new PaginatedResult<>( - new PaginationInfo(page.getPageNumber() + 1, maxPage, page.getPageSize(), count, null, null), + new PaginationInfo(page.getPageNumber() + 1, maxPage, page.getPageSize(), count, null, request), actions ); } diff --git a/src/main/resources/templates/fragments/table_selectable.html b/src/main/resources/templates/fragments/table_selectable.html index ff98883..53beebd 100644 --- a/src/main/resources/templates/fragments/table_selectable.html +++ b/src/main/resources/templates/fragments/table_selectable.html @@ -2,6 +2,23 @@ + + + + + + + + + + + + + + +

This table contains no data.

@@ -28,21 +45,10 @@

- - - - - - - - - - - - - +

diff --git a/src/main/resources/templates/logs.html b/src/main/resources/templates/logs.html index 8955775..4b46fea 100644 --- a/src/main/resources/templates/logs.html +++ b/src/main/resources/templates/logs.html @@ -59,10 +59,50 @@ - - - - + + + +
Action typeTableItem IDTime +
+
Action type
+

+ +

+
+
+
+
Table
+

+ +

+
+
+
+
Item ID
+

+ +

+
+
+
+
Time
+

+ +

+
+