diff --git a/pom.xml b/pom.xml
index c463be91..02b5fb51 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,6 +245,12 @@
reactor-netty
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ 2.15.2
+
+
diff --git a/src/main/java/net/gepafin/tendermanagement/config/JacksonConfig.java b/src/main/java/net/gepafin/tendermanagement/config/JacksonConfig.java
new file mode 100644
index 00000000..51ad3191
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/JacksonConfig.java
@@ -0,0 +1,20 @@
+package net.gepafin.tendermanagement.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class JacksonConfig {
+
+ @Bean
+ public ObjectMapper objectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(new JavaTimeModule());
+ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ return mapper;
+ }
+}
+
diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java
index 8c11eac2..462d5cc9 100644
--- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java
+++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java
@@ -12,6 +12,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@@ -97,7 +98,9 @@ public class SecurityConfig {
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(auth -> auth
+ http.csrf(AbstractHttpConfigurer::disable).headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
+ .contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'self' https://bandi-staging.memento.credit https://bandi.gepafin.it")))
+ .authorizeHttpRequests(auth -> auth
// Allow public access to the login endpoints
.requestMatchers("/v1/user/login").permitAll() // JWT-based login
.requestMatchers("/v1/user").permitAll() // User registration
diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java
index 42853112..5869fc81 100644
--- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java
+++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java
@@ -355,5 +355,10 @@ public class GepafinConstant {
public static final String NOTIFICATION_DELETED_SUCCESSFULLY="notification.deleted.successfully";
public static final String NOTIFICATION_UPDATED_SUCCESSFULLY="notification.updated.successfully";
public static final String USER_WITH_COMPANY_NOT_FOUND = "user.with.company.not.found";
+
+ //action log response
+ public static final String STATUS_CODE_STRING = "statusCode";
+ public static final String GET_STATUS_CODE_STRING = "status";
+ public static final String MESSAGE_STRING = "message";
}
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java
index d9b3ed91..2cf5d3ca 100644
--- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java
+++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java
@@ -306,7 +306,7 @@ public class ApplicationAmendmentRequestDao {
ApplicationAmendmentRequestEntity applicationAmendment = saveApplicationAmendmentRequestEntity(applicationAmendmentRequestEntity, null, VersionActionTypeEnum.INSERT);
String evaluationStatusType = applicationEvaluationEntity.getStatus();
if (Boolean.FALSE.equals(evaluationStatusType.equals((ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue())))){
- applicationEvaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue());
+// applicationEvaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue());
//Set Status
applicationEvaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue());
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java
index 5992314b..c264a078 100644
--- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java
+++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java
@@ -24,7 +24,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
+import java.time.Duration;
import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -1800,6 +1802,11 @@ public class ApplicationEvaluationDao {
existingEntity.setClosingDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
assignedApplicationsEntity.setStatus(AssignedApplicationEnum.CLOSE.getValue());
}
+ if (existingEntity.getStartDate() != null && existingEntity.getClosingDate() != null) {
+ long activeDays = ChronoUnit.DAYS.between(existingEntity.getStartDate(), existingEntity.getClosingDate());
+ activeDays -= existingEntity.getSuspendedDays() != null ? existingEntity.getSuspendedDays() : 0;
+ existingEntity.setActiveDays(activeDays);
+ }
entity = applicationEvaluationRepository.save(existingEntity);
assignedApplicationsRepository.save(assignedApplicationsEntity);
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java
index c87c863a..97fef3cb 100644
--- a/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java
+++ b/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java
@@ -4,6 +4,7 @@ import net.gepafin.tendermanagement.entities.*;
import net.gepafin.tendermanagement.enums.CallStatusEnum;
import net.gepafin.tendermanagement.enums.RoleStatusEnum;
import net.gepafin.tendermanagement.enums.UserStatusEnum;
+import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.Widget1;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -13,6 +14,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.List;
import java.util.List;
import java.util.stream.Collectors;
@@ -37,6 +42,9 @@ public class DashboardDao {
private BeneficiaryPreferredCallRepository beneficiaryPreferredCallRepository;
+ @Autowired
+ private ApplicationEvaluationRepository applicationEvaluationRepository;
+
public SuperAdminWidgetResponseBean getDashboardWidget(UserEntity requestedUserEntity) {
SuperAdminWidgetResponseBean widgetResponseBean = new SuperAdminWidgetResponseBean();
widgetResponseBean.setWidget1(createWidget1(requestedUserEntity));
@@ -133,4 +141,70 @@ public class DashboardDao {
}
return beneficiaryWidgetResponseBean;
}
+
+ public ApplicationWidgetResponseBean getApplicationDetails(UserEntity userEntity) {
+ ApplicationWidgetResponseBean applicationWidgetResponseBean = initializeResponseBean();
+
+ Long hubId = userEntity.getHub().getId();
+
+ setApplicationCounts(applicationWidgetResponseBean, hubId);
+ calculateEvaluationAverageTime(applicationWidgetResponseBean, hubId);
+
+ return applicationWidgetResponseBean;
+ }
+
+ private ApplicationWidgetResponseBean initializeResponseBean() {
+ return ApplicationWidgetResponseBean.builder()
+ .numberOfApplication(0L)
+ .numberOfAssignedApplication(0L)
+ .numberOfAcceptedApplication(0L)
+ .numberOfApplicationInAmendmentState(0L)
+ .numberOfDueApplication(0L)
+ .evaluationAverageTime(BigDecimal.ZERO)
+ .build();
+ }
+
+ private void setApplicationCounts(ApplicationWidgetResponseBean responseBean, Long hubId) {
+ Long activeApplications = applicationRepository.countApplicationsByHubId(hubId);
+ if (activeApplications != null) {
+ responseBean.setNumberOfApplication(activeApplications);
+ }
+
+ Long assignedApplications = applicationRepository.countAssignedApplicationsByHubId(hubId);
+ if (assignedApplications != null) {
+ responseBean.setNumberOfAssignedApplication(assignedApplications);
+ }
+
+ Long approvedApplications = applicationRepository.countApprovedApplicationsByHubId(hubId);
+ if (approvedApplications != null) {
+ responseBean.setNumberOfAcceptedApplication(approvedApplications);
+ }
+
+ Long soccorsoApplications = applicationRepository.countSoccorsoApplicationsByHubId(hubId);
+ if (soccorsoApplications != null) {
+ responseBean.setNumberOfApplicationInAmendmentState(soccorsoApplications);
+ }
+ }
+
+ private void calculateEvaluationAverageTime(ApplicationWidgetResponseBean responseBean, Long hubId) {
+ List applicationIds = applicationRepository.findApplicationIdsByHubId(hubId);
+
+ if (Boolean.FALSE.equals(applicationIds.isEmpty())) {
+ BigDecimal averageTime = applicationEvaluationRepository.findAverageEvaluationTimeByApplicationIds(applicationIds);
+ responseBean.setEvaluationAverageTime(averageTime != null ? averageTime : BigDecimal.ZERO);
+ }
+ LocalDate twoDaysLater = LocalDate.now().plusDays(2);
+
+ Long dueApplications = applicationEvaluationRepository.countDueApplicationsBetween(
+ applicationIds,
+ LocalDate.now(),
+ twoDaysLater
+ );
+
+ if (dueApplications != null) {
+ responseBean.setNumberOfDueApplication(dueApplications);
+ }
+ }
+
+
}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java
index 15e3d3d7..6ab7b72c 100644
--- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java
+++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java
@@ -65,4 +65,7 @@ public class ApplicationEvaluationEntity extends BaseEntity{
@Column(name = "CLOSING_DATE")
private LocalDateTime closingDate;
+ @Column(name = "ACTIVE_DAYS")
+ private Long activeDays;
+
}
diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java
index 8863f715..013535e6 100644
--- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java
+++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java
@@ -136,6 +136,7 @@ public enum UserActionContextEnum {
/** Dashboard action context **/
GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN("GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN"),
GET_DASHBOARD_WIDGET_FOR_BENEFICIARY("GET_DASHBOARD_WIDGET_FOR_BENEFICIARY"),
+ GET_APPLICATION_DETAILS("GET_APPLICATION_DETAILS"),
/** Evaluation criteria action context **/
GET_EVALUATION_CRITERIA("GET_EVALUATION_CRITERIA"),
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationWidgetResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationWidgetResponseBean.java
new file mode 100644
index 00000000..c119121b
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationWidgetResponseBean.java
@@ -0,0 +1,23 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Builder
+@Data
+public class ApplicationWidgetResponseBean {
+
+ private Long numberOfApplication;
+
+ private Long numberOfAssignedApplication;
+
+ private Long numberOfAcceptedApplication;
+
+ private Long numberOfApplicationInAmendmentState;
+
+ private Long numberOfDueApplication;
+
+ private BigDecimal evaluationAverageTime;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java
index f9a7b0ac..daaae5a8 100644
--- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java
@@ -7,6 +7,8 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
+import java.math.BigDecimal;
+import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@@ -31,4 +33,27 @@ public interface ApplicationEvaluationRepository extends JpaRepository findAllByIsDeletedFalseAndEndDateBefore(@Param("currentDate") LocalDateTime currentDate);
+// @Query("SELECT AVG(DATEDIFF(DAY, e.startDate, e.endDate)) FROM ApplicationEvaluationEntity e WHERE e.applicationId IN :applicationIds AND e.startDate IS NOT NULL AND e.endDate IS NOT NULL AND e.isDeleted = false ")
+ @Query("""
+ SELECT AVG(e.activeDays)
+ FROM ApplicationEvaluationEntity e
+ WHERE e.applicationId IN :applicationIds
+ AND e.activeDays IS NOT NULL
+ AND e.isDeleted = false
+ """)
+ BigDecimal findAverageEvaluationTimeByApplicationIds(@Param("applicationIds") List applicationIds);
+ @Query("""
+ SELECT COUNT(e)
+ FROM ApplicationEvaluationEntity e
+ WHERE e.applicationId IN :applicationIds
+ AND FUNCTION('DATE', e.endDate) BETWEEN :startDate AND :endDate
+ AND e.isDeleted = false
+""")
+ Long countDueApplicationsBetween(
+ @Param("applicationIds") List applicationIds,
+ @Param("startDate") LocalDate startDate,
+ @Param("endDate") LocalDate endDate
+ );
+
+
}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java
index db645f95..3b35e921 100644
--- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java
@@ -44,4 +44,20 @@ public interface ApplicationRepository extends JpaRepository findApplicationIdsByHubId(@Param("hubId") Long hubId);
+
+
}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/UserActionsRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/UserActionsRepository.java
index f0163c47..804fdb9b 100644
--- a/src/main/java/net/gepafin/tendermanagement/repositories/UserActionsRepository.java
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/UserActionsRepository.java
@@ -6,5 +6,5 @@ import org.springframework.stereotype.Repository;
@Repository
public interface UserActionsRepository extends JpaRepository {
- UserActionEntity findUserActionById(Long id);
+ UserActionEntity findUserActionByIdAndIsDeletedFalse(Long id);
}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java b/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java
index 6328ca6e..0e34c1b6 100644
--- a/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java
+++ b/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java
@@ -1,6 +1,7 @@
package net.gepafin.tendermanagement.service;
import jakarta.servlet.http.HttpServletRequest;
+import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -9,5 +10,5 @@ public interface DashboardService {
public SuperAdminWidgetResponseBean getDashboardWidgetForSuperAdmin(HttpServletRequest request);
public BeneficiaryWidgetResponseBean getDashboardWidgetForBeneficiary(HttpServletRequest request, Long companyId);
-
+ public ApplicationWidgetResponseBean getApplicationDetails(HttpServletRequest request);
}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java
index 1a6cd6fd..e578a3dc 100644
--- a/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java
+++ b/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java
@@ -4,6 +4,7 @@ import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.dao.DashboardDao;
import net.gepafin.tendermanagement.entities.CompanyEntity;
import net.gepafin.tendermanagement.entities.UserEntity;
+import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
import net.gepafin.tendermanagement.service.DashboardService;
@@ -32,4 +33,10 @@ public class DashboardServiceImpl implements DashboardService {
CompanyEntity company = validator.validateUserWithCompany(request, companyId);
return dashboardDao.getDashboardWidgetForBeneficiary(userEntity, company);
}
+
+ @Override
+ public ApplicationWidgetResponseBean getApplicationDetails(HttpServletRequest request) {
+ UserEntity userEntity=validator.validateUser(request);
+ return dashboardDao.getApplicationDetails(userEntity);
+ }
}
diff --git a/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java b/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java
index e2ab4521..90b7a052 100644
--- a/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java
+++ b/src/main/java/net/gepafin/tendermanagement/util/LoggingUtil.java
@@ -41,6 +41,8 @@ public class LoggingUtil {
@Autowired
private TokenProvider tokenProvider;
+ private static final ThreadLocal userActionIdHolder = new ThreadLocal<>();
+
public UserActionEntity logUserAction(UserActionRequest userActionRequest) {
UserActionEntity userAction = new UserActionEntity();
try {
@@ -83,12 +85,22 @@ public class LoggingUtil {
userAction.setResponse(response);
userActionsRepository.save(userAction);
userActionRequest.getRequest().setAttribute(GepafinConstant.USER_ACTION_ID, userAction.getId());
+ userActionIdHolder.set(userAction.getId());
} catch (Exception e) {
log.error("Error logging user action: {}", e.getMessage(), e);
}
return userAction;
}
+ public Long getUserActionId() {
+ return userActionIdHolder.get();
+ }
+
+ public void clearUserActionId() {
+ userActionIdHolder.remove();
+ log.info("UserActionId cleared from ThreadLocal");
+ }
+
private String normalizeUrl(String url) {
url = url.replaceAll("(? getVersionHistoryLogById(Long id) {
return versionHistoryRepository.findVersionHistoryByUserActionId(id);
}
+
+ public void updateUserActionWithError(Long userActionId, String errorDetails) {
+ if (userActionId == null) {
+ return;
+ }
+
+ UserActionEntity userAction = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId);
+ if (userAction != null) {
+ userAction.setResponse(errorDetails);
+ userActionsRepository.save(userAction);
+ }
+ }
+
+ public void updateUserActionWithResponse(Long userActionId, String response) {
+ if (userActionId == null) {
+ return;
+ }
+
+ UserActionEntity userAction = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId);
+ if (userAction != null) {
+ userAction.setResponse(response);
+ userActionsRepository.save(userAction);
+ }
+ }
+
}
diff --git a/src/main/java/net/gepafin/tendermanagement/util/UserActionAspect.java b/src/main/java/net/gepafin/tendermanagement/util/UserActionAspect.java
new file mode 100644
index 00000000..0064bb82
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/util/UserActionAspect.java
@@ -0,0 +1,148 @@
+package net.gepafin.tendermanagement.util;
+
+import com.amazonaws.services.alexaforbusiness.model.UnauthorizedException;
+import jakarta.persistence.EntityNotFoundException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.AccessDeniedException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Aspect
+@Component
+@Slf4j
+public class UserActionAspect {
+
+ @Autowired
+ private LoggingUtil loggingUtil;
+
+ @Around("execution(public * net.gepafin.tendermanagement.web.rest.api.impl..*(..))")
+ public Object logApiResponse(ProceedingJoinPoint joinPoint) throws Throwable {
+
+ Object result;
+
+ HttpServletRequest request = getRequestFromContext();
+ try {
+ Long userActionId = getUserActionIdFromRequest(request);
+
+ if (userActionId != null) {
+ request.setAttribute(GepafinConstant.USER_ACTION_ID, userActionId);
+ log.info("Stored userActionId in RequestContext: {}", userActionId);
+ } else {
+ userActionId = loggingUtil.getUserActionId();
+ if (userActionId != null) {
+ request.setAttribute(GepafinConstant.USER_ACTION_ID, userActionId);
+ }
+ }
+
+ result = joinPoint.proceed();
+
+ if (result instanceof ResponseEntity>) {
+ Long storedUserActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID);
+ handleSuccessResponse((ResponseEntity>) result, storedUserActionId == null ? userActionId : storedUserActionId);
+ }
+ } catch (Exception ex) {
+ log.error("Exception occurred: ", ex);
+ handleError(ex, getUserActionIdFromRequest(request));
+ throw ex;
+ } finally {
+ loggingUtil.clearUserActionId();
+ }
+
+ return result;
+ }
+
+ private void handleSuccessResponse(ResponseEntity> responseEntity, Long userActionId) {
+
+ if (userActionId != null) {
+ Map responseWithUserAction = new LinkedHashMap<>();
+ responseWithUserAction.put(GepafinConstant.STATUS_CODE_STRING, responseEntity.getStatusCode().value());
+
+ // Log and update user action
+ loggingUtil.updateUserActionWithResponse(userActionId, Utils.convertMapIntoJsonString(responseWithUserAction));
+ log.info("Updated userActionId with response: {}", userActionId);
+ }
+ }
+
+ private void handleError(Throwable ex, Long userActionId) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+
+ HttpStatus status = getStatusCodeFromException(ex);
+ log.info("Status Code received from exception : {}", status);
+ String errorMessage = ex.getMessage();
+
+ Map errorResponse = new LinkedHashMap<>();
+ errorResponse.put(GepafinConstant.STATUS_CODE_STRING, status.value());
+ errorResponse.put(GepafinConstant.GET_STATUS_CODE_STRING, status);
+ errorResponse.put(GepafinConstant.MESSAGE_STRING, errorMessage);
+
+ if (userActionId != null) {
+ String errorDetails = Utils.convertMapIntoJsonString(errorResponse);
+ loggingUtil.updateUserActionWithError(userActionId, errorDetails);
+ log.info("Updated userActionId with error details: {}", userActionId);
+ }
+ }
+
+ private HttpServletRequest getRequestFromContext() {
+
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ return attributes != null ? attributes.getRequest() : null;
+ }
+
+ private Long getUserActionIdFromRequest(HttpServletRequest request) {
+
+ if (request != null) {
+ Object userActionIdAttr = request.getAttribute(GepafinConstant.USER_ACTION_ID);
+ return userActionIdAttr != null ? Long.valueOf(userActionIdAttr.toString()) : null;
+ }
+ return null;
+ }
+
+ private HttpStatus getStatusCodeFromException(Throwable ex) {
+
+ if (ex instanceof ResourceNotFoundException) {
+ return HttpStatus.NOT_FOUND;
+ }
+
+ if (ex instanceof ResponseStatusException responseStatusException) {
+ return (HttpStatus) responseStatusException.getStatusCode();
+ }
+
+ if (ex instanceof CustomValidationException) {
+ return HttpStatus.BAD_REQUEST;
+ }
+
+ if (ex instanceof EntityNotFoundException) {
+ return HttpStatus.NOT_FOUND;
+ }
+ if (ex instanceof IllegalArgumentException || ex instanceof MissingServletRequestParameterException || ex instanceof MethodArgumentNotValidException) {
+ return HttpStatus.BAD_REQUEST;
+ }
+ if (ex instanceof AccessDeniedException) {
+ return HttpStatus.FORBIDDEN;
+ }
+ if (ex instanceof UnauthorizedException) {
+ return HttpStatus.UNAUTHORIZED;
+ }
+
+ return HttpStatus.INTERNAL_SERVER_ERROR;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java
index 40f95e3b..0770bce5 100644
--- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java
+++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java
@@ -154,6 +154,9 @@ public class Utils {
public static String convertMapIntoJsonString(Map map) {
try {
ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(new JavaTimeModule());
+ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
if (MapUtils.isNotEmpty(map)) {
return mapper.writeValueAsString(map);
}
diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java
index 753473f2..31ae1be3 100644
--- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java
+++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java
@@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
+import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
@@ -46,7 +47,19 @@ public interface DashboardApi {
produces = { "application/json" })
ResponseEntity> getDashboardWidgetForBeneficiary(HttpServletRequest request,
@Parameter(description = "The company id", required = true) @PathVariable(value = "companyId", required = true) Long companyId);
-
+ @Operation(summary = "Api to get Application details",
+ responses = {
+ @ApiResponse(responseCode = "200", description = "OK"),
+ @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
+ @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
+ @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
+ @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
+ @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
+ @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) })
+ @GetMapping(value = "/application",
+ produces = { "application/json" })
+ @PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')")
+ ResponseEntity> getApplicationDetails(HttpServletRequest request);
}
diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java
index 7ff7be61..ed1f3d68 100644
--- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java
+++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java
@@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.UserActionRequest;
+import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
@@ -49,5 +50,14 @@ public class DashboardApiController implements DashboardApi {
return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY)));
}
+ @Override
+ public ResponseEntity> getApplicationDetails(HttpServletRequest request) {
+ /** This code is responsible for creating user action logs for the "Get complete application page" operation. **/
+ loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_APPLICATION_DETAILS).build());
+
+ ApplicationWidgetResponseBean widgetResponseBean= dashboardService.getApplicationDetails(request);
+ return ResponseEntity.status(HttpStatus.CREATED)
+ .body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY)));
+ }
}
diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml
index 125cd42a..994c3941 100644
--- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml
+++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml
@@ -2093,6 +2093,11 @@
+
+
+
+
+