From 7d04e4ab5837ce9022bedd07924ff09c1fae384d Mon Sep 17 00:00:00 2001 From: piyushkag Date: Tue, 26 Nov 2024 12:47:03 +0530 Subject: [PATCH] Added user action log and versioning for communication. --- .../dao/CommunicationDao.java | 34 +++++++++++++++++-- .../enums/UserActionContextEnum.java | 8 ++++- .../response/CommunicationResponseBean.java | 9 +++-- .../repositories/CommunicationRepository.java | 10 +++--- .../impl/CommunicationServiceImpl.java | 2 +- .../tendermanagement/util/LoggingUtil.java | 31 +++++++++++++++-- .../api/impl/CommunicationController.java | 19 +++++++++++ 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CommunicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CommunicationDao.java index b752a755..d7ef7c83 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CommunicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CommunicationDao.java @@ -5,14 +5,19 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; import net.gepafin.tendermanagement.entities.CommunicationEntity; +import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.CommunicationRequestBean; +import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.model.response.ApplicationAmendmentResponse; import net.gepafin.tendermanagement.model.response.CommunicationResponseBean; import net.gepafin.tendermanagement.repositories.CommunicationRepository; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; +import net.gepafin.tendermanagement.util.LoggingUtil; +import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; +import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -34,24 +39,41 @@ public class CommunicationDao { @Autowired private Validator validator; + @Autowired + private LoggingUtil loggingUtil; + + @Autowired + private HttpServletRequest request; + public CommunicationResponseBean addCommentToAmendmentRequest(HttpServletRequest request, CommunicationRequestBean communicationReq, Long amendmentId) { log.info("Adding communication request..."); CommunicationEntity communicationEntity = convertToCommunicationCommentEntity(communicationReq, amendmentId); communicationEntity = communicationRepository.save(communicationEntity); + + /** This code is responsible for adding a version history log for the "adding comment to amendment request" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(communicationEntity).build()); + log.info("Added comment: {}", communicationEntity); return convertToCommunicationResponseBean(communicationEntity); } public String deleteComment(Long amendmentId, Long commentId) { - CommunicationEntity data = communicationRepository.findById(commentId) + CommunicationEntity data = communicationRepository.findByIdAndIsDeletedFalse(commentId) .orElseThrow(() -> new CustomValidationException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.COMMENT_NOT_FOUND))); + //cloned for old commentData + CommunicationEntity oldComment = Utils.getClonedEntityForData(data); + if (!data.getApplicationAmendmentRequest().getId().equals(amendmentId)) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.INVALID_AMENDMENT_FOR_COMMENT)); } data.setIsDeleted(true); - communicationRepository.save(data); + data = communicationRepository.save(data); + + /** This code is responsible for adding a version history log for the "soft deleting comment to amendment request" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldComment).newData(data).build()); + return "Deleted Comment Successfully."; } @@ -70,6 +92,9 @@ public class CommunicationDao { log.info("Updating communication comment..."); CommunicationEntity existingComment = communicationRepository.findById(commentId) .orElseThrow(() -> new CustomValidationException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.COMMENT_NOT_FOUND))); + //cloned for old data for communication + CommunicationEntity oldCommentData = Utils.getClonedEntityForData(existingComment); + if (!existingComment.getApplicationAmendmentRequest().getId().equals(amendmentId)) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.COMMENT_NOT_ASSOCIATE_WITH_AMENDMENT_ID_ERROR_MSG)); } @@ -78,6 +103,10 @@ public class CommunicationDao { existingComment.setCommentedDate(LocalDateTime.now()); existingComment = communicationRepository.save(existingComment); log.info("Updated Comment: {}", existingComment); + + /** This code is responsible for adding a version history log for the "updating comment to amendment request" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCommentData).newData(existingComment).build()); + return convertToCommunicationResponseBean(existingComment); } @@ -92,6 +121,7 @@ public class CommunicationDao { response.setTitle(entity.getCommunicationTitle()); response.setSenderUserId(entity.getSenderUserId()); response.setReceiverUserId(entity.getReceiverUserId()); + response.setId(entity.getId()); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index d19d9d33..fefc12a9 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -135,7 +135,13 @@ public enum UserActionContextEnum { GET_EVALUATION_CRITERIA("GET_EVALUATION_CRITERIA"), UPDATE_EVALUATION_CRITERIA("UPDATE_EVALUATION_CRITERIA"), DELETE_EVALUATION_CRITERIA("DELETE_EVALUATION_CRITERIA"), - CREATE_EVALUATION_CRITERIA("CREATE_EVALUATION_CRITERIA"); + CREATE_EVALUATION_CRITERIA("CREATE_EVALUATION_CRITERIA"), + + /** communication action context **/ + ADD_COMMENT_TO_AMENDMENT_REQUEST("ADD_COMMENT_TO_AMENDMENT_REQUEST"), + UPDATE_COMMUNICATION_COMMENT("UPDATE_COMMUNICATION_COMMENT"), + GET_AMENDMENT_COMMENT("GET_AMENDMENT_COMMENT"), + DELETE_COMMENT_FROM_AMENDMENT("DELETE_COMMENT_FROM_AMENDMENT"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CommunicationResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/CommunicationResponseBean.java index 4593db84..170e1318 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/CommunicationResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/CommunicationResponseBean.java @@ -10,6 +10,8 @@ public class CommunicationResponseBean { private String comment; + private Long id; + private String title; private LocalDateTime createdDate; @@ -21,7 +23,8 @@ public class CommunicationResponseBean { private Long receiverUserId; private Long amendmentId; - public CommunicationResponseBean(LocalDateTime commentedDate, String comment, String title, LocalDateTime createdDate, LocalDateTime updatedDate, Long amendmentId) { + + public CommunicationResponseBean(LocalDateTime commentedDate, String comment, String title, LocalDateTime createdDate, LocalDateTime updatedDate, Long amendmentId, Long id) { this.commentedDate = commentedDate; this.comment = comment; @@ -29,9 +32,10 @@ public class CommunicationResponseBean { this.createdDate = createdDate; this.updatedDate = updatedDate; this.amendmentId = amendmentId; + this.id = id; } - public CommunicationResponseBean(LocalDateTime commentedDate, String comment, String title, LocalDateTime createdDate, LocalDateTime updatedDate, Long amendmentId,Long senderUserId,Long receiverUserId) { + public CommunicationResponseBean(LocalDateTime commentedDate, String comment, String title, LocalDateTime createdDate, LocalDateTime updatedDate, Long amendmentId,Long senderUserId,Long receiverUserId, Long id) { this.commentedDate = commentedDate; this.comment = comment; @@ -41,6 +45,7 @@ public class CommunicationResponseBean { this.amendmentId = amendmentId; this.senderUserId = senderUserId; this.receiverUserId = receiverUserId; + this.id = id; } public CommunicationResponseBean() { diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CommunicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CommunicationRepository.java index f92b9a06..2894d57b 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/CommunicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/CommunicationRepository.java @@ -7,16 +7,14 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.util.List; +import java.util.Optional; public interface CommunicationRepository extends JpaRepository { - @Query("Select new net.gepafin.tendermanagement.model.response.CommunicationResponseBean(c.commentedDate, c.communicationComment, c.communicationTitle, c.createdDate, c.updatedDate, c.applicationAmendmentRequest.id) " + - "from CommunicationEntity c Where c.applicationAmendmentRequest.id = :applicationAmendmentRequestId") - List findCommentsByApplicationAmendmentRequestId(@Param("applicationAmendmentRequestId") Long amendmentRequestId); - @Query("SELECT new net.gepafin.tendermanagement.model.response.CommunicationResponseBean( " + "c.commentedDate, c.communicationComment, c.communicationTitle, c.createdDate, c" + - ".updatedDate, c.applicationAmendmentRequest.id,c.senderUserId, c.receiverUserId) " + "FROM CommunicationEntity c " + "WHERE c.applicationAmendmentRequest.id = :amendmentId AND c.isDeleted = false") + ".updatedDate, " + "c.applicationAmendmentRequest.id, c.senderUserId, c.receiverUserId, c.id " + ") " + "FROM CommunicationEntity c " + "WHERE c" + + ".applicationAmendmentRequest.id = :amendmentId AND c.isDeleted = false") List findCommentListDetailsByAmendmentId(@Param("amendmentId") Long amendmentId); - + Optional findByIdAndIsDeletedFalse(Long commentId); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CommunicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CommunicationServiceImpl.java index de3e5030..ad3513e3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CommunicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CommunicationServiceImpl.java @@ -63,7 +63,7 @@ public class CommunicationServiceImpl implements CommunicationService { } @Override - @Transactional(readOnly = true) + @Transactional(rollbackFor = Exception.class) public ApplicationAmendmentResponse getAmendmentComments(HttpServletRequest request,Long id) { ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = applicationAmendmentRequestDao.validateApplicationAmendmentRequest(id); if (Boolean.FALSE.equals(validator.checkIsBeneficiary())) { diff --git a/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java b/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java index d3a60884..53ed01cb 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java +++ b/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java @@ -19,6 +19,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -55,12 +57,26 @@ public class LoggingUtil { if (userActionRequest.getRequest() instanceof CachedBodyHttpServletRequest cachedRequest) { requestBody = cachedRequest.getCachedBodyAsString(); } + // Decode the raw URI to handle encoded placeholders like %7BcommentId%7D + String rawUrl = userActionRequest.getRequest().getRequestURI(); + String decodedUrl = URLDecoder.decode(rawUrl, StandardCharsets.UTF_8); + + // Append query parameters if they exist + if (userActionRequest.getRequest().getQueryString() != null) { + decodedUrl += "?" + userActionRequest.getRequest().getQueryString(); + } + + // Use the decoded URL as-is (optional normalization step if needed) + String normalizedUrl = normalizeUrl(decodedUrl); + + // Set the normalized URL in the user action log userAction.setActionType(userActionRequest.getActionType().getValue()); userAction.setUserId(userId); userAction.setActionContext(userActionRequest.getActionContext().getValue()); userAction.setMethodType(userActionRequest.getRequest().getMethod()); userAction.setHubId(userEntity.getHub().getId()); - userAction.setUrl(userActionRequest.getRequest().getRequestURI()); +// userAction.setUrl(userActionRequest.getRequest().getRequestURI()); + userAction.setUrl(normalizedUrl); userAction.setLoginAttemptId(loginAttemptId); userAction.setIpAddress(IpAddressUtils.getClientIp(userActionRequest.getRequest())); userAction.setRequestBody(requestBody); @@ -74,7 +90,18 @@ public class LoggingUtil { return userAction; } -// @Transactional + private String normalizeUrl(String url) { + + url = url.replaceAll("(? 1 && url.endsWith("/")) { + url = url.substring(0, url.length() - 1); + } + url = URLDecoder.decode(url, StandardCharsets.UTF_8); + return url; + } + + + // @Transactional // public UserActionEntity updateUserAction(HttpServletResponse response, UserActionEntity userAction) { // try { // String requestBody = null; diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CommunicationController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CommunicationController.java index 92aa71cf..15552e95 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CommunicationController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CommunicationController.java @@ -3,11 +3,15 @@ package net.gepafin.tendermanagement.web.rest.api.impl; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.enums.UserActionContextEnum; +import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.model.request.CommunicationRequestBean; +import net.gepafin.tendermanagement.model.request.UserActionRequest; import net.gepafin.tendermanagement.model.response.ApplicationAmendmentResponse; import net.gepafin.tendermanagement.model.response.CommunicationResponseBean; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.CommunicationService; +import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.web.rest.api.CommunicationApi; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.springframework.beans.factory.annotation.Autowired; @@ -23,10 +27,16 @@ public class CommunicationController implements CommunicationApi { @Autowired CommunicationService communicationService; + @Autowired + private LoggingUtil loggingUtil; + @Override public ResponseEntity> addCommentToAmendmentRequest(HttpServletRequest request, CommunicationRequestBean communicationRequestBean, Long amendmentId) { + /** This code is responsible for creating user action logs for the "Adding comment to amendment request" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.INSERT).actionContext(UserActionContextEnum.ADD_COMMENT_TO_AMENDMENT_REQUEST).build()); + CommunicationResponseBean communicationResponseBean = communicationService.addCommentToAmendmentRequest(request,communicationRequestBean, amendmentId); return ResponseEntity.status(HttpStatus.CREATED) .body(new Response<>(communicationResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMMUNICATION_ADDED_TO_AMENDMENT_REQUEST_SUCCESS))); @@ -34,6 +44,9 @@ public class CommunicationController implements CommunicationApi { @Override public ResponseEntity> getAmendmentComments(HttpServletRequest request,Long amendmentId) { + /** This code is responsible for creating user action logs for the "getting comment of amendment" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_AMENDMENT_COMMENT).build()); + ApplicationAmendmentResponse response = communicationService.getAmendmentComments(request,amendmentId); return ResponseEntity.ok(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.AMENDMENT_FOUND_SUCCESS))); } @@ -41,6 +54,9 @@ public class CommunicationController implements CommunicationApi { public ResponseEntity> updateCommunicationAmendment(HttpServletRequest request, CommunicationRequestBean communicationRequestBean, Long amendmentId, Long commentId) { + /** This code is responsible for creating user action logs for the "update communication comment of amendment request" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.UPDATE_COMMUNICATION_COMMENT).build()); + CommunicationResponseBean communicationResponseBean = communicationService.updateAmendmentComment(request,communicationRequestBean, amendmentId, commentId); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(communicationResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMMENT_UPDATED_SUCCESS_MSG))); @@ -48,6 +64,9 @@ public class CommunicationController implements CommunicationApi { @Override public ResponseEntity> deleteApplicationAmendmentComment(HttpServletRequest request, Long applicationAmendId, Long commentId) { + /** This code is responsible for creating user action logs for the "Delete communication comment of amendment request" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.DELETE).actionContext(UserActionContextEnum.DELETE_COMMENT_FROM_AMENDMENT).build()); + String communicationResponseBean = communicationService.deleteComment(request,applicationAmendId, commentId); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(communicationResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMMENT_DELETED_SUCCESS_MSG)));