Merge pull request #278 from Kitzanos/feature/GEPAFINBE-210

GEPAFINBE-210 ( Manage error in PEC )
This commit is contained in:
Rinaldo
2025-05-02 15:41:11 +02:00
committed by GitHub
44 changed files with 636 additions and 75 deletions

View File

@@ -12,10 +12,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationAmendmentPagination
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest;
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean;
import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestViewResponse;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.model.response.GetAllAmendmentResponseBean;
import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository;
import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository;
import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService;
@@ -145,17 +142,18 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm
}
@Override
public void sendReminderEmail(HttpServletRequest request,Long amendmentId) {
public EmailReminderResponse sendReminderEmail(HttpServletRequest request, Long amendmentId) {
ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId)
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND,
Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)));
EmailReminderResponse response = new EmailReminderResponse();
Optional<ApplicationEvaluationEntity> entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId());
if (entityOptional.isPresent()) {
UserEntity user = validator.validatePreInstructor(request, entityOptional.get().getUserId());
applicationAmendmentRequestDao.sendReminderEmail(amendmentId);
response = applicationAmendmentRequestDao.sendReminderEmail(amendmentId);
}
return response;
}
@Override

View File

@@ -15,10 +15,7 @@ import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.enums.*;
import net.gepafin.tendermanagement.model.request.LoginReq;
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
import net.gepafin.tendermanagement.model.response.CompanyResponse;
import net.gepafin.tendermanagement.model.response.LoginResponse;
import net.gepafin.tendermanagement.model.response.RoleResponseBean;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.repositories.LoginAttemptRepository;
import net.gepafin.tendermanagement.repositories.SamlResponseRepository;
@@ -122,7 +119,7 @@ public class AuthenticationService {
createFailedLoginAttempt(loginAttemptEntity, e.getMessage());
throw e;
}
return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId());
return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId(),null);
}
public LoginAttemptEntity prepareLoginAttemptEntity(LoginReq loginUserReq, HttpServletRequest request) {
@@ -145,7 +142,7 @@ public class AuthenticationService {
loginAttemptEntity.setErrorMsg(errorMsg);
loginAttemptDao.createLoginAttempt(loginAttemptEntity);
}
public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId) {
public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, EmailSendResponse emailSendResponse) {
UserEntity oldUserEntity = Utils.getClonedEntityForData(user);
user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
user = userRepository.save(user);
@@ -156,7 +153,7 @@ public class AuthenticationService {
LoginResponse loginResponse = getLoginResponse(user, roleResponseBean);
JWTToken jwtToken = new JWTToken(token, loginResponse);
JWTToken jwtToken = new JWTToken(token, loginResponse , emailSendResponse);
/** This code is responsible for adding a version history log for the "Create user Or Update user" operation. **/
loggingUtil.addVersionHistoryWithoutToken(VersionHistoryRequest.builder().request(request).oldData(oldUserEntity).newData(user).actionType(VersionActionTypeEnum.UPDATE).build());
@@ -238,7 +235,7 @@ public class AuthenticationService {
loginAttemptEntity = prepareLoginAttemptEntity(loginReq, request);
loginAttemptEntity.setUserId(userEntity.getId());
LoginAttemptEntity loginAttempt = createSuccessLoginAttempt(loginAttemptEntity);
return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId());
return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId(),null);
} catch (Exception e) {
log.info("Authentication login failed for email: {}",e.getMessage());
loginAttemptEntity.setUserId(userId);

View File

@@ -1,25 +1,32 @@
package net.gepafin.tendermanagement.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import lombok.extern.slf4j.Slf4j;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.dao.ApplicationDao;
import net.gepafin.tendermanagement.dao.EmailLogDao;
import net.gepafin.tendermanagement.entities.EmailLogEntity;
import net.gepafin.tendermanagement.dao.NotificationDao;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum;
import net.gepafin.tendermanagement.enums.NotificationTypeEnum;
import net.gepafin.tendermanagement.enums.StatusTypeEnum;
import net.gepafin.tendermanagement.model.request.EmailConfig;
import net.gepafin.tendermanagement.model.request.EmailLogRequest;
import net.gepafin.tendermanagement.model.request.NotificationReq;
import net.gepafin.tendermanagement.model.request.PecEmailRequest;
import net.gepafin.tendermanagement.util.Utils;
import net.gepafin.tendermanagement.util.Validator;
import org.opensaml.xmlsec.signature.G;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@@ -30,20 +37,26 @@ public class PecEmailService implements EmailService {
@Value("${isPecServiceEnabled}")
private String isPecServiceEnabled;
@Autowired
private Validator validator;
@Autowired
private EmailLogDao emailLogDao;
@Autowired
private NotificationDao notificationDao;
@Autowired
private ApplicationDao applicationDao;
@Override
public void sendEmail(String subject, String body, List<String> recipientEmails, EmailConfig emailConfig, EmailLogRequest emailLogRequest) {
if (Boolean.FALSE.equals(Boolean.parseBoolean(isEmailSendingEnabled))) {
return;
}
PecEmailRequest emailRequest = new PecEmailRequest();
emailRequest.setSender(emailConfig.getSender());
emailRequest.setSubject(subject);
@@ -67,13 +80,27 @@ public class PecEmailService implements EmailService {
.header("Content-Type", "application/json")
.body(Utils.convertObjectToJson(emailRequest)) // Serialize the emailRequest object to JSON
.asString();
if (!isSuccessfulPecResponse(response2.getBody())) {
String errorMsg = "PEC sending failed: " + response2.getBody();
emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue());
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogRequest.setErrorMessage(errorMsg);
sendNotificationOnFailure(emailLogRequest.getUserId(),emailLogRequest.getEmailType());
if (EmailScenarioTypeEnum.APPLICATION_SUBMITTED.equals(emailLogRequest.getEmailType())) {
applicationDao.sendApplicationSubmissionFailureEmail(emailLogRequest);
}
}
}
}catch(Exception e) {
emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue());
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogRequest.setErrorMessage(e.getMessage());
emailLogDao.createEmailLog(emailLogRequest);
throw new RuntimeException("Failed to send email via PEC: " + response2.getStatus());
sendNotificationOnFailure(emailLogRequest.getUserId(),emailLogRequest.getEmailType());
if (EmailScenarioTypeEnum.APPLICATION_SUBMITTED.equals(emailLogRequest.getEmailType())) {
applicationDao.sendApplicationSubmissionFailureEmail(emailLogRequest);
}
}
if(response2 != null) {
emailLogRequest.setEmailServiceResponse(response2.getBody());
@@ -82,6 +109,57 @@ public class PecEmailService implements EmailService {
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogDao.createEmailLog(emailLogRequest);
}
private void sendNotificationOnFailure(Long userId, EmailScenarioTypeEnum emailScenarioTypeEnum) {
if (userId == null) {
log.warn("Cannot send notification: userId is null.");
return;
}
Map<String, String> placeholders = new HashMap<>();
placeholders.put("{{email_scenario}}", emailScenarioTypeEnum.getValue());
NotificationReq notificationReq = notificationDao.createNotificationReq(
NotificationTypeEnum.PEC_EMAIL_SENDING_FAILURE.getValue(),
placeholders,
userId,
null,
null
);
try {
notificationDao.sendNotification(notificationReq);
log.info("Sent PEC failure notification to user {}", userId);
} catch (Exception e) {
log.error("Failed to send PEC failure notification to user {}: {}", userId, e.getMessage());
}
}
private boolean isSuccessfulPecResponse(String responseBody) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(responseBody);
boolean success = jsonNode.has("success") && jsonNode.get("success").asBoolean();
boolean hasNoError = !jsonNode.has("error") || jsonNode.get("error").isNull();
if (jsonNode.has("success") && !success) {
log.error("PEC response indicates failure: {}", responseBody);
return false;
}
if (responseBody.contains("403") || responseBody.toLowerCase().contains("<html") || responseBody.toLowerCase().contains("<!doctype html>")) {
log.error("PEC response is a 403 HTML Forbidden page or invalid format: {}", responseBody);
return false;
}
return success && hasNoError;
} catch (Exception e) {
log.error("Invalid PEC response format: {}", responseBody);
return false;
}
}
}

View File

@@ -0,0 +1,25 @@
package net.gepafin.tendermanagement.service.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.dao.EmailDao;
import net.gepafin.tendermanagement.model.response.EmailResendResponseBean;
import net.gepafin.tendermanagement.service.ResendEmailService;
import net.gepafin.tendermanagement.util.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ResendEmailServiceImpl implements ResendEmailService {
@Autowired
Validator validator;
@Autowired
EmailDao emailDao;
@Override
public EmailResendResponseBean resendEmail(HttpServletRequest request, Long userActionId) {
validator.validateUser(request);
return emailDao.resendEmail(request,userActionId);
}
}

View File

@@ -55,7 +55,7 @@ public class SystemEmailService implements EmailService {
emailLogRequest.setEmailBody(body);
emailLogRequest.setSendStatus(StatusTypeEnum.SUCCESS.getValue());
emailLogRequest.setRecipientEmails(Utils.listToCommaSeparatedString(recipientEmails));
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE);
if (Boolean.FALSE.equals(validator.isTestProfileActivated())) {
MessageResponse response = null;
try {

View File

@@ -11,9 +11,7 @@ import net.gepafin.tendermanagement.model.request.UpdateUserReq;
import net.gepafin.tendermanagement.model.request.UserReq;
import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.UserResponseBean;
import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.service.UserService;
import net.gepafin.tendermanagement.util.LoggingUtil;
@@ -78,8 +76,8 @@ public class UserServiceImpl implements UserService {
}
@Override
public void initiatePasswordReset(InitiatePasswordResetReq resetReq) {
userDao.initiatePasswordReset(resetReq);
public InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq) {
return userDao.initiatePasswordReset(resetReq);
}
@Override