package net.gepafin.tendermanagement.util; import io.jsonwebtoken.Claims; import jakarta.persistence.Table; import lombok.extern.slf4j.Slf4j; import net.gepafin.tendermanagement.config.CachedBodyHttpServletRequest; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.UserActionEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.entities.VersionHistoryEntity; import net.gepafin.tendermanagement.model.request.UserActionRequest; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.repositories.UserActionsRepository; import net.gepafin.tendermanagement.repositories.VersionHistoryRepository; import net.gepafin.tendermanagement.service.UserService; 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; @Slf4j @Component @RequestScope public class LoggingUtil { @Autowired private UserActionsRepository userActionsRepository; @Autowired private VersionHistoryRepository versionHistoryRepository; @Autowired private UserService userService; @Autowired private TokenProvider tokenProvider; public UserActionEntity logUserAction(UserActionRequest userActionRequest) { UserActionEntity userAction = new UserActionEntity(); try { String token = tokenProvider.extractTokenFromRequest(userActionRequest.getRequest()); Claims claims = tokenProvider.getClaimsFromToken(token); Map parameters = userActionRequest.getRequest().getParameterMap(); parameters.forEach((key, value) -> log.info("Query Parameter: {} = {}", key, Arrays.toString(value))); Long userId = claims.get(GepafinConstant.USER_ID, Long.class); Long loginAttemptId = claims.get(GepafinConstant.LOGIN_ATTEMPT_ID, Long.class); UserEntity userEntity = userService.validateUser(userId); String requestBody = null; 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(normalizedUrl); userAction.setLoginAttemptId(loginAttemptId); userAction.setIpAddress(IpAddressUtils.getClientIp(userActionRequest.getRequest())); userAction.setRequestBody(requestBody); String response = Utils.convertEntityToJsonForLogging(userActionRequest.getResponse()); userAction.setResponse(response); userActionsRepository.save(userAction); userActionRequest.getRequest().setAttribute(GepafinConstant.USER_ACTION_ID, userAction.getId()); } catch (Exception e) { log.error("Error logging user action: {}", e.getMessage(), e); } return userAction; } 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; // if (userAction. instanceof CachedBodyHttpServletRequest cachedRequest) { // requestBody = cachedRequest.getCachedBodyAsString(); // } // // LogResponse logResponse = new LogResponse<>(); // logResponse.setStatus(response.getStatus()); // logResponse.setStatusCode(String.valueOf(response.getStatus())); // logResponse.setMessage("SUCCESS"); // // String serializedResponse; // try { // ObjectMapper objectMapper = new ObjectMapper(); // serializedResponse = objectMapper.writeValueAsString(logResponse); // } catch (Exception e) { // serializedResponse = "Error serializing LogResponse: " + e.getMessage(); // } // // userAction.setResponse(serializedResponse); // userActionsRepository.save(userAction); // } catch (Exception e) { // log.error("Error updating user action: {}", e.getMessage(), e); // } // return userAction; // } public void logVersionHistory(VersionHistoryRequest versionHistoryRequest, Long recordId, Long userActionId, String tableName) { try { VersionHistoryEntity history = new VersionHistoryEntity(); String token = tokenProvider.extractTokenFromRequest(versionHistoryRequest.getRequest()); if(versionHistoryRequest.getRequest() != null && token != null) { Claims claims = tokenProvider.getClaimsFromToken(token); Long userId = claims.get(GepafinConstant.USER_ID, Long.class); history.setUserId(userId); } String oldData = Utils.convertEntityToJsonForLogging(versionHistoryRequest.getOldData()); String newData = Utils.convertEntityToJsonForLogging(versionHistoryRequest.getNewData()); history.setUserActionId(userActionId); history.setActionType(versionHistoryRequest.getActionType().getValue()); history.setOldData(oldData); history.setNewData(newData); history.setRecordId(recordId); history.setTableName(tableName); versionHistoryRepository.save(history); } catch (Exception e) { log.error("Error logging version history: {}", e.getMessage(), e); } } public void logVersionHistoryWithoutToken(VersionHistoryRequest versionHistoryRequest, Long recordId, Long userActionId, String tableName) { try { VersionHistoryEntity history = new VersionHistoryEntity(); Long userId = null; String token = tokenProvider.extractTokenFromRequest(versionHistoryRequest.getRequest()); if(versionHistoryRequest.getRequest() != null && token != null) { Claims claims = tokenProvider.getClaimsFromToken(token); userId = claims.get(GepafinConstant.USER_ID, Long.class); } String oldData = Utils.convertEntityToJsonForLogging(versionHistoryRequest.getOldData()); String newData = Utils.convertEntityToJsonForLogging(versionHistoryRequest.getNewData()); history.setUserActionId(userActionId); history.setActionType(versionHistoryRequest.getActionType().getValue()); history.setOldData(oldData); history.setNewData(newData); history.setRecordId(recordId); history.setTableName(tableName); history.setUserId(userId); versionHistoryRepository.save(history); } catch (Exception e) { log.error("Error logging version history: {}", e.getMessage(), e); } } public String getTableName(Class entityClass) { try { if (entityClass.isAnnotationPresent(Table.class)) { Table tableAnnotation = entityClass.getAnnotation(Table.class); return tableAnnotation.name(); } } catch (Exception e) { log.error("Error retrieving table name: {}", e.getMessage(), e); } return null; } public void addVersionHistory(VersionHistoryRequest versionHistoryRequest) { try { Long userActionId = (Long) versionHistoryRequest.getRequest().getAttribute(GepafinConstant.USER_ACTION_ID); Long recordId = null; String tableName = null; if(versionHistoryRequest.getNewData() != null) { recordId = versionHistoryRequest.getNewData().getId(); tableName = getTableName(versionHistoryRequest.getNewData().getClass()).toUpperCase(); } else if(versionHistoryRequest.getOldData() != null){ recordId = versionHistoryRequest.getOldData().getId(); tableName = getTableName(versionHistoryRequest.getOldData().getClass()).toUpperCase(); } logVersionHistory(versionHistoryRequest, recordId, userActionId, tableName); } catch (Exception e) { log.error("Error adding version history: {}", e.getMessage(), e); } } public void addVersionHistoryWithoutToken(VersionHistoryRequest versionHistoryRequest) { try { Long userActionId = (Long) versionHistoryRequest.getRequest().getAttribute(GepafinConstant.USER_ACTION_ID); Long recordId = null; String tableName = null; if(versionHistoryRequest.getNewData() != null) { recordId = versionHistoryRequest.getNewData().getId(); tableName = getTableName(versionHistoryRequest.getNewData().getClass()).toUpperCase(); } else if(versionHistoryRequest.getOldData() != null){ recordId = versionHistoryRequest.getOldData().getId(); tableName = getTableName(versionHistoryRequest.getOldData().getClass()).toUpperCase(); } versionHistoryRequest.setNewData(versionHistoryRequest.getNewData()); versionHistoryRequest.setRequest(versionHistoryRequest.getRequest()); logVersionHistoryWithoutToken(versionHistoryRequest, recordId, userActionId, tableName); } catch (Exception e) { log.error("Error adding version history: {}", e.getMessage(), e); } } public UserActionEntity logUserActionWithoutToken(UserActionRequest userActionRequest) { UserActionEntity userAction = new UserActionEntity(); try { Long userId = null; Long loginAttemptId = null; Long hubId = null; String token = tokenProvider.extractTokenFromRequest(userActionRequest.getRequest()); Map parameters = userActionRequest.getRequest().getParameterMap(); parameters.forEach((key, value) -> log.info("Query Parameter : {} = {}", key, Arrays.toString(value))); if(userActionRequest.getRequest() != null && token != null) { Claims claims = tokenProvider.getClaimsFromToken(token); userId = claims.get(GepafinConstant.USER_ID, Long.class); loginAttemptId = claims.get(GepafinConstant.LOGIN_ATTEMPT_ID, Long.class); UserEntity userEntity = userService.validateUser(userId); hubId = userEntity.getHub().getId(); } String requestBody = null; if (userActionRequest.getRequest() instanceof CachedBodyHttpServletRequest cachedRequest) { requestBody = cachedRequest.getCachedBodyAsString(); } userAction.setActionType(userActionRequest.getActionType().getValue()); userAction.setUserId(userId); userAction.setActionContext(userActionRequest.getActionContext().getValue()); userAction.setMethodType(userActionRequest.getRequest().getMethod()); userAction.setHubId(hubId); userAction.setUrl(userActionRequest.getRequest().getRequestURI()); userAction.setLoginAttemptId(loginAttemptId); userAction.setIpAddress(IpAddressUtils.getClientIp(userActionRequest.getRequest())); userAction.setRequestBody(requestBody); String response = Utils.convertEntityToJsonForLogging(userActionRequest.getResponse()); userAction.setResponse(response); userActionsRepository.save(userAction); userActionRequest.getRequest().setAttribute(GepafinConstant.USER_ACTION_ID, userAction.getId()); } catch (Exception e) { log.error("Error logging user action: {}", e.getMessage(), e); } return userAction; } public void updateUserActionWithTokenDetails(Long actionId, String token, Object response) { try { UserActionEntity userAction = getUserActionLogById(actionId); if (userAction != null && token != null) { Claims claims = tokenProvider.getClaimsFromToken(token); Long userId = claims.get(GepafinConstant.USER_ID, Long.class); Long loginAttemptId = claims.get(GepafinConstant.LOGIN_ATTEMPT_ID, Long.class); UserEntity userEntity = userService.validateUser(userId); userAction.setUserId(userId); String responseData = Utils.convertEntityToJsonForLogging(response); userAction.setResponse(responseData); userAction.setLoginAttemptId(loginAttemptId); userAction.setHubId(userEntity.getHub().getId()); // Save updated entity userActionsRepository.save(userAction); log.info("User action log updated with token details: {}", userAction.getId()); } } catch (Exception e) { log.error("Failed to update user action with token details: {}", e.getMessage(), e); } } public void updateVersionHistoriesWithTokenDetails(Long userActionId, String token) { try { // Fetch version history entities for the given user action ID List versionHistoryEntities = getVersionHistoryLogById(userActionId); if (versionHistoryEntities != null && !versionHistoryEntities.isEmpty() && token != null) { // Extract claims from the token Claims claims = tokenProvider.getClaimsFromToken(token); Long userId = claims.get(GepafinConstant.USER_ID, Long.class); // Update each version history entity with the user ID for (VersionHistoryEntity versionHistoryEntity : versionHistoryEntities) { versionHistoryEntity.setUserId(userId); } // Save all updated entities versionHistoryRepository.saveAll(versionHistoryEntities); log.info("Version History logs updated with userId: {}", userId); } else { log.warn("No version history or token provided for userActionId: {}", userActionId); } } catch (Exception e) { log.error("Failed to update version histories with token details: {}", e.getMessage(), e); } } public UserActionEntity getUserActionLogById(Long id) { return userActionsRepository.findUserActionById(id); } public List getVersionHistoryLogById(Long id) { return versionHistoryRepository.findVersionHistoryByUserActionId(id); } }