package net.gepafin.tendermanagement.dao; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.TimePeriodEnum; import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; import net.gepafin.tendermanagement.model.request.UserActionPaginationRequest; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.repositories.RoleActionContextRepository; import net.gepafin.tendermanagement.repositories.UserActionsRepository; import net.gepafin.tendermanagement.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isEmpty; @Component public class UserActionDao { @Autowired private UserService userService; @Autowired private UserActionsRepository userActionsRepository; @Autowired private AssignedApplicationsRepository assignedApplicationsRepository; @Autowired private RoleActionContextRepository roleActionContextRepository; public SummaryPageResponseBean getUserAction(HttpServletRequest request, UserEntity userEntity){ Long numberOfLoginAttempts = userActionsRepository.countUserLoginAttempts(userEntity.getId()); Long applicationsProcessed = assignedApplicationsRepository.countAssignedApplicationsByUserId(userEntity.getId()); return createSummaryPageResponse(userEntity,numberOfLoginAttempts,applicationsProcessed); } public SummaryPageResponseBean createSummaryPageResponse(UserEntity user, Long numberOfLoginAttempts, Long applicationsProcessed){ SummaryPageResponseBean response = new SummaryPageResponseBean(); response.setRole(user.getRoleEntity().getRoleName()); response.setLastLogin(user.getLastLogin()); response.setRegistrationDate(user.getCreatedDate()); response.setUsername(user.getFirstName()); response.setEmail(user.getEmail()); response.setNumberOfLoginAttempts(numberOfLoginAttempts); response.setApplicationsProcessed(applicationsProcessed); return response; } public List getFilterUserActions(Long userId ,TimePeriodEnum timeFilter, List actionContextList) { LocalDateTime endDate = LocalDateTime.now(); LocalDateTime startDate = (timeFilter != null) ? getStartTimeFromFilter(timeFilter) : null; Pageable pageable = PageRequest.of(0, 25); // String actionContextLabel = (actionContext != null) ? actionContext.toString() : null; List actionContextLabels = (actionContextList != null && !actionContextList.isEmpty()) ? actionContextList.stream().map(Enum::toString).collect(Collectors.toList()) : null; Specification spec = getUserActionsSpecification(userId, startDate, endDate, actionContextLabels); Page pageResult = userActionsRepository.findAll(spec, pageable); return pageResult.getContent(); } private LocalDateTime getStartTimeFromFilter(TimePeriodEnum timeFilter) { LocalDateTime now = LocalDateTime.now(); if (timeFilter.equals(TimePeriodEnum.LAST_WEEK)) { return now.minusDays(7); } else if (timeFilter.equals(TimePeriodEnum.LAST_QUARTER)) { return now.minusMonths(4); } else if (timeFilter.equals(TimePeriodEnum.LAST_SEMESTER)) { return now.minusMonths(6); } else if (timeFilter.equals(TimePeriodEnum.LAST_YEAR)) { return now.minusYears(1); } else { return null; } } public Specification getUserActionsSpecification(Long userId, LocalDateTime startDate, LocalDateTime endDate, List actionContextList) { return (root, query, builder) -> { Predicate predicate = builder.isFalse(root.get("isDeleted")); predicate = builder.and(predicate, builder.equal(root.get("userId"), userId)); if (startDate != null && endDate != null) { predicate = builder.and(predicate, builder.between(root.get("createdDate"), startDate, endDate)); } if (actionContextList != null && !actionContextList.isEmpty()) { CriteriaBuilder.In inClause = builder.in(root.get("actionContext")); for (String actionContext : actionContextList) { inClause.value(actionContext); } predicate = builder.and(predicate, inClause); } query.orderBy(builder.desc(root.get("createdDate"))); return predicate; }; } private List convertEntityToResponse(List userActions) { return userActions.stream().map(action -> { UserActionResponseBean responseBean = new UserActionResponseBean(); responseBean.setId(action.getId()); responseBean.setUserId(action.getUserId()); responseBean.setActionType(action.getActionType()); responseBean.setRequestBody(action.getRequestBody()); responseBean.setLoginAttemptId(action.getLoginAttemptId()); responseBean.setIpAddress(action.getIpAddress()); responseBean.setActionContext(action.getActionContext()); responseBean.setHubId(action.getHubId()); responseBean.setUrl(action.getUrl()); responseBean.setResponse(action.getResponse()); responseBean.setCreatedDate(action.getCreatedDate()); responseBean.setUpdatedDate(action.getUpdatedDate()); responseBean.setMethodType(action.getMethodType()); return responseBean; }).collect(Collectors.toList()); } public List getActionContextLabels(HttpServletRequest request, UserEntity userEntity){ List actionContextLabel = roleActionContextRepository.findActionContextLabel(userEntity.getRoleEntity().getId()); return convertRoleContextEntityToResponse(actionContextLabel); } private List convertRoleContextEntityToResponse(List actionContextEntities){ return actionContextEntities.stream().map(actionContext -> { ActionContextLabelResponse responseBean = new ActionContextLabelResponse(); responseBean.setId(actionContext.getId()); responseBean.setActionContext(UserActionContextEnum.valueOf(actionContext.getActionContext())); responseBean.setRoleId(actionContext.getRoleId()); responseBean.setDescription(actionContext.getDescription()); responseBean.setIsViewed(actionContext.getIsViewed()); return responseBean; }).collect(Collectors.toList()); } public PageableResponseBean> getUserActionByPagination(UserEntity user, UserActionPaginationRequest userActionPaginationRequest) { Integer pageNo = null; Integer pageLimit = null; if (userActionPaginationRequest.getGlobalFilters() != null) { pageNo = userActionPaginationRequest.getGlobalFilters().getPage(); pageLimit = userActionPaginationRequest.getGlobalFilters().getLimit(); } if (pageLimit == null || pageLimit <= 0) { pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; } if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } Specification spec = search(userActionPaginationRequest,user); Page entityPage = userActionsRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response Long numberOfLoginAttempts = userActionsRepository.countUserLoginAttempts(user.getId()); Long applicationsProcessed = assignedApplicationsRepository.countAssignedApplicationsByUserId(user.getId()); List userActionResponseBeans = convertEntityToResponse(entityPage.stream().toList()); PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); pageableResponseBean.setBody(userActionResponseBeans); pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); // Page numbers typically start from 0, so add 1 for user-friendly indexing pageableResponseBean.setTotalPages(entityPage.getTotalPages()); pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); pageableResponseBean.setPageSize(entityPage.getSize()); return pageableResponseBean; } public Specification search(UserActionPaginationRequest userActionPaginationRequest,UserEntity userEntity) { return (root, query, criteriaBuilder) -> { List predicates = getPredicates(userActionPaginationRequest, criteriaBuilder, root,userEntity); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (userActionPaginationRequest .getGlobalFilters() != null && userActionPaginationRequest.getGlobalFilters().getSortBy() != null && userActionPaginationRequest.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( isEmpty(userActionPaginationRequest.getGlobalFilters().getSortBy().getColumnName()))) { sortBy.setColumnName(userActionPaginationRequest.getGlobalFilters().getSortBy().getColumnName()); sortBy.setSortDesc(true); if (userActionPaginationRequest.getGlobalFilters().getSortBy().getSortDesc() != null) { sortBy.setSortDesc(userActionPaginationRequest.getGlobalFilters().getSortBy().getSortDesc()); } } query.orderBy(criteriaBuilder.desc(root.get(sortBy.getColumnName()))); if (Boolean.FALSE.equals(sortBy.getSortDesc())) { query.orderBy(criteriaBuilder.asc(root.get(sortBy.getColumnName()))); } return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); }; } private List getPredicates(UserActionPaginationRequest userActionPaginationRequest, CriteriaBuilder criteriaBuilder, Root root,UserEntity userEntity) { Integer year = null; String search = null; if (userActionPaginationRequest.getGlobalFilters() != null) { year = userActionPaginationRequest.getGlobalFilters().getYear(); search = userActionPaginationRequest.getGlobalFilters().getSearch(); } List predicates = new ArrayList<>(); if (year != null && year > 0) { int filterYear = userActionPaginationRequest.getGlobalFilters().getYear(); // Create LocalDateTime boundaries for the start and end of the year LocalDateTime startOfYear = LocalDateTime.of(filterYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(filterYear, 12, 31, 23, 59, 59); // Add the range comparison to filter records within the year predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); } // Search in `title` and `message` (if search term is provided) if (search != null && !search.isEmpty()) { Predicate actionType = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.ACTION_TYPE)), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(actionType)); Predicate actionContext = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.ACTION_CONTEXT)), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(actionContext)); Predicate methodType = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.METHOD_TYPE)), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(methodType)); } // Filter by `status` (if status list is provided) if (userActionPaginationRequest.getActionContext() != null && !userActionPaginationRequest.getActionContext().isEmpty()) { List statusValues = userActionPaginationRequest.getActionContext().stream() .map(UserActionContextEnum::name) // Convert enum to string .toList(); predicates.add(root.get("actionContext").in(statusValues)); } if (userActionPaginationRequest.getActionType() != null && !userActionPaginationRequest.getActionType().isEmpty()) { List statusValues = userActionPaginationRequest.getActionType().stream() .map(UserActionLogsEnum::name) // Convert enum to string .toList(); predicates.add(root.get("actionType").in(statusValues)); } TimePeriodEnum timeRange= userActionPaginationRequest.getTimeFilter(); if (timeRange != null) { LocalDateTime startDate = null; LocalDateTime endDate = LocalDateTime.now(); switch (timeRange) { case LAST_WEEK -> startDate = endDate.minusWeeks(1); case LAST_QUARTER -> startDate = endDate.minusMonths(3); case LAST_SEMESTER -> startDate = endDate.minusMonths(6); case LAST_YEAR -> startDate = endDate.minusYears(1); } if (startDate != null) { predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startDate, endDate)); } } predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_ID), userEntity.getId())); return predicates; } }