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 jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.SamlSuccessHandler; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.repositories.BeneficiaryRepository; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.RoleService; import net.gepafin.tendermanagement.service.SystemEmailTemplatesService; import net.gepafin.tendermanagement.service.impl.AuthenticationService; 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.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; import static org.apache.commons.lang3.StringUtils.isEmpty; @Component public class UserDao { private final Logger log = LoggerFactory.getLogger(UserDao.class); @Autowired private UserRepository userRepository; @Autowired private CompanyDao companyDao; @Autowired private AuthenticationService authService; @Autowired private PasswordEncoder passwordEncoder; @Autowired private RoleDao roleDao; @Autowired private BeneficiaryRepository beneficiaryRepository; @Autowired private RoleService roleService; @Value("${default.hub.uuid}") private String defaultHubUuid; @Value("${app.confidi.login.url.suffix}") private String confidiLogin; @Value("${app.bandi.login.url.suffix}") private String bandiLoginUrlSuffix; @Autowired private Validator validator; @Autowired private SamlSuccessHandler samlSuccessHandler; @Autowired private HubService hubService; @Autowired private AuthenticationService authenticationService; @Autowired private LoggingUtil loggingUtil; @Autowired private HttpServletRequest request; @Autowired private SystemEmailTemplatesService systemEmailTemplatesService; @Autowired private EmailLogDao emailLogDao; @Autowired private EmailNotificationDao emailNotificationDao; @Value("${fe.base.url}") private String feBaseUrl; public JWTToken createUser(HttpServletRequest request, String tempToken, UserReq userReq) { if (StringUtils.isEmpty(userReq.getHubUuid())) { userReq.setHubUuid(defaultHubUuid); } HubEntity hub = hubService.getHubByUuid(userReq.getHubUuid()); validateUserRequest(request, tempToken, userReq, hub); validatePassword(userReq.getPassword(), userReq.getConfPassword(), tempToken); RoleEntity roleEntity = getRoleEntity(userReq.getRoleId()); BeneficiaryEntity beneficiary = createBeneficiary(roleEntity, userReq, hub); UserEntity userEntity = convertUserRequestToUserEntity(beneficiary, roleEntity, userReq, hub); log.info("User created with ID: {}", userEntity.getId()); LoginReq loginReq = new LoginReq(); loginReq.setEmail(userEntity.getEmail()); LoginAttemptEntity loginAttemptEntity = null; if (userEntity != null) { loginAttemptEntity = authenticationService.prepareLoginAttemptEntity(loginReq, request); log.info("Authentication failed for email: {}", loginReq.getEmail()); loginAttemptEntity.setUserId(userEntity.getId()); authenticationService.createSuccessLoginAttempt(loginAttemptEntity); } JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId()); /** This code is responsible for adding a version history log for the "Create beneficiary" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(beneficiary).build()); /** This code is responsible for adding a version history log for the "Create user" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build()); if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){ sendEmailToOnboardingUser(userEntity, userReq ); } return token; } public void sendEmailToOnboardingUser(UserEntity userEntity,UserReq userReq){ SystemEmailTemplateResponse emailTemplate; RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType()); SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum templateType = roleStatus.equals(RoleStatusEnum.ROLE_CONFIDI) ? SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.USER_ONBOARDING_CONFIDI : SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.USER_ONBOARDING_BANDI; emailTemplate = systemEmailTemplatesService.retrieveTemplateByTypeAndCall(templateType, userEntity.getHub(), null); EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, userEntity.getId(), userEntity.getEmail(), userEntity.getId(), null, null, null); Map placeholders = replacePlaceholders(userEntity, userReq); String body = Utils.replacePlaceholders(emailTemplate.getHtmlContent(), placeholders); emailNotificationDao.sendMail( userEntity.getHub().getId(), emailTemplate.getSubject(), body, List.of(userEntity.getEmail()), emailLogRequest ); } private Map replacePlaceholders(UserEntity userEntity, UserReq userReq) { RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType()); String confidiLoginUrl = userEntity.getHub().getDomainName() + confidiLogin; String bandiLoginUrl = userEntity.getHub().getDomainName() + bandiLoginUrlSuffix; String hubConfigText = userEntity.getHub().getHubConfig(); JSONObject hubConfig = new JSONObject(hubConfigText); String gepafinEmail = hubConfig.optString(GepafinConstant.EMAIL_SUPPORT, ""); String gepafinPhoneNumber = hubConfig.optString(GepafinConstant.PHONE_SUPPORT, ""); Map placeholders = new HashMap<>(); placeholders.put("{{username}}", userEntity.getEmail()); placeholders.put("{{userpassword}}",userReq.getPassword()); String loginUrl = roleStatus.equals(RoleStatusEnum.ROLE_CONFIDI) ? confidiLoginUrl : bandiLoginUrl; placeholders.put("{{login_url}}",loginUrl); placeholders.put("{{gepafinphonenumber}}", gepafinPhoneNumber); placeholders.put("{{gepafinemail}}", gepafinEmail); return placeholders; } private BeneficiaryEntity createBeneficiary(RoleEntity roleEntity, UserReq userReq, HubEntity hub) { BeneficiaryEntity beneficiaryEntity = null; if (RoleStatusEnum.ROLE_BENEFICIARY.getValue().equals(roleEntity.getRoleType()) || RoleStatusEnum.ROLE_CONFIDI.getValue().equals(roleEntity.getRoleType())) { beneficiaryEntity = new BeneficiaryEntity(); beneficiaryEntity.setAddress(userReq.getAddress()); beneficiaryEntity.setCity(userReq.getCity()); beneficiaryEntity.setCodiceFiscale(userReq.getCodiceFiscale()); beneficiaryEntity.setCountry(userReq.getCountry()); beneficiaryEntity.setDateOfBirth(userReq.getDateOfBirth()); beneficiaryEntity.setEmail(userReq.getEmail()); beneficiaryEntity.setFirstName(userReq.getFirstName()); beneficiaryEntity.setLastName(userReq.getLastName()); beneficiaryEntity.setOrganization(userReq.getOrganization()); beneficiaryEntity.setPhoneNumber(userReq.getPhoneNumber()); beneficiaryEntity.setPrivacy(userReq.getPrivacy()); beneficiaryEntity.setTerms(userReq.getTerms()); beneficiaryEntity.setOffers(userReq.getOffers()); beneficiaryEntity.setMarketing(userReq.getMarketing()); beneficiaryEntity.setThirdParty(userReq.getThirdParty()); beneficiaryEntity.setEmailPec(userReq.getEmailPec()); beneficiaryEntity.setHubId(hub.getId()); beneficiaryEntity =beneficiaryRepository.save(beneficiaryEntity); } return beneficiaryEntity; } private void validateUserRequest(HttpServletRequest request, String tempToken, UserReq userReq, HubEntity hub) { if (tempToken == null) { validator.validateRequest(request,RoleStatusEnum.ROLE_SUPER_ADMIN); UserEntity userEntity = validator.validateUser(request); userReq.setHubUuid(userEntity.getHub().getUniqueUuid()); }else { samlSuccessHandler.validateToken(tempToken, userReq.getCodiceFiscale(), userReq.getHubUuid()); RoleEntity roleEntity = roleDao.getRoleByType(RoleStatusEnum.ROLE_BENEFICIARY); userReq.setRoleId(roleEntity.getId()); } if (Boolean.FALSE.equals(Utils.isValidEmail(userReq.getEmail()))) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATE_EMAIL)); } log.info("Creating user with email: {}", userReq.getEmail()); RoleEntity roleEntity = roleService.validateRole(userReq.getRoleId()); validateDuplicateEmail(userReq.getEmail(), userReq.getHubUuid(), roleEntity.getRoleType()); if (Boolean.FALSE.equals(StringUtils.isEmpty(userReq.getCodiceFiscale())) && userRepository.existsByBeneficiaryCodiceFiscaleAndHubId(userReq.getCodiceFiscale(), hub.getId())) { log.error("User creation failed: CodiceFiscale {} already exists", userReq.getCodiceFiscale()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.CODICE_FISCALE_EXISTS)); } if (tempToken == null && userReq.getRoleId() == null) { throw new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.ROLE_ID_MANDATORY)); } if (tempToken != null) { userReq.setRoleId(null); } if (tempToken == null) { RoleEntity role = roleService.validateRole(userReq.getRoleId()); if (Boolean.TRUE.equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue().equals(role.getRoleType()))) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.CANNOT_CREATE_BENEFICIARY_USER)); } } } private void validateDuplicateEmail(String email, String hubUuid, String roleType) { String beneficiaryRoleType = RoleStatusEnum.ROLE_BENEFICIARY.getValue(); if (beneficiaryRoleType.equals(roleType)) { Boolean beneficiaryExistsInHub = userRepository.existsByEmailIgnoreCaseForBeneficiaries( email, hubUuid, beneficiaryRoleType); if (Boolean.TRUE.equals(beneficiaryExistsInHub)) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS)); } } else { Boolean existsForNonBeneficiaries = userRepository.existsByEmailIgnoreCaseForNonBeneficiaries( email, hubUuid, beneficiaryRoleType); if (Boolean.TRUE.equals(existsForNonBeneficiaries)) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS)); } } } private void validatePassword(String password, String confirmPassword, String tempToken) { if (StringUtils.isEmpty(password) || StringUtils.isEmpty(confirmPassword)) { if(tempToken == null) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATE_PASSWORD)); }else if(Boolean.FALSE.equals(StringUtils.isEmpty(password) && StringUtils.isEmpty(confirmPassword))){ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATE_PASSWORD)); } } if (password != null && !password.equals(confirmPassword)) { log.error("User creation failed: Passwords do not match"); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_DOESNT_MATCH)); } if (password != null && password.length() < 8) { log.error("User creation failed: Password length is less than 8 characters"); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_MIN_LEN)); } } public UserResponseBean updateUser(Long userId, UpdateUserReq userReq) { log.info("Updating user with ID: {}", userId); UserEntity userEntity=validateUser(userId); UserEntity oldUserEntity = Utils.getClonedEntityForData(userEntity); log.info("Current user details: {}", userEntity); log.info("New user details: {}", userReq); String newStatus = userReq.getStatus() != null ? userReq.getStatus().getValue() : null; if (newStatus!=null && Boolean.FALSE.equals(userEntity.getStatus().equals(newStatus))) { userEntity.setStatus(newStatus); } setIfUpdated(userEntity::getFirstName, userEntity::setFirstName, userReq.getFirstName()); setIfUpdated(userEntity::getLastName, userEntity::setLastName, userReq.getLastName()); setIfUpdated(userEntity::getOrganization, userEntity::setOrganization, userReq.getOrganization()); setIfUpdated(userEntity::getAddress, userEntity::setAddress, userReq.getAddress()); setIfUpdated(userEntity::getPhoneNumber, userEntity::setPhoneNumber, userReq.getPhoneNumber()); setIfUpdated(userEntity::getDateOfBirth, userEntity::setDateOfBirth, userReq.getDateOfBirth()); if (userReq.getRoleId() != null) { RoleEntity roleEntity = roleDao.validateRole(userReq.getRoleId()); if((userEntity.getRoleEntity().getRoleType().equals(RoleStatusEnum.ROLE_INSTRUCTOR_MANAGER.getValue()) && roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_PRE_INSTRUCTOR.getValue())) || (userEntity.getRoleEntity().getRoleType().equals(RoleStatusEnum.ROLE_PRE_INSTRUCTOR.getValue()) && roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_INSTRUCTOR_MANAGER.getValue()))) { setIfUpdated(userEntity::getRoleEntity, userEntity::setRoleEntity, roleEntity); } } if(userEntity.getBeneficiary()!=null) { setIfUpdated(userEntity.getBeneficiary()::getCodiceFiscale, userEntity.getBeneficiary()::setCodiceFiscale, userReq.getCodiceFiscale()); setIfUpdated(userEntity.getBeneficiary()::getMarketing, userEntity.getBeneficiary()::setMarketing, userReq.getMarketing()); setIfUpdated(userEntity.getBeneficiary()::getOffers, userEntity.getBeneficiary()::setOffers, userReq.getOffers()); setIfUpdated(userEntity.getBeneficiary()::getThirdParty, userEntity.getBeneficiary()::setThirdParty, userReq.getThirdParty()); setIfUpdated(userEntity.getBeneficiary()::getEmailPec, userEntity.getBeneficiary()::setEmailPec, userReq.getEmailPec()); } userEntity = userRepository.save(userEntity); /** This code is responsible for adding a version history log for the "Update user details" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldUserEntity).newData(userEntity).build()); log.info("User updated with ID: {}", userEntity.getId()); return convertUserEntityToUserResponse(userEntity); } private UserEntity convertUserRequestToUserEntity(BeneficiaryEntity beneficiary, RoleEntity roleEntity, UserReq userReq, HubEntity hub) { UserEntity userEntity = new UserEntity(); if(Boolean.FALSE.equals(StringUtils.isEmpty(userReq.getPassword()))) { userEntity.setPassword(passwordEncoder.encode(userReq.getPassword())); } userEntity.setRoleEntity(roleEntity); userEntity.setEmail(userReq.getEmail()); userEntity.setStatus(UserStatusEnum.ACTIVE.getValue()); userEntity.setBeneficiary(beneficiary); userEntity.setHub(hub); if (Boolean.FALSE.equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue().equals(roleEntity.getRoleType()))) { userEntity.setFirstName(userReq.getFirstName()); userEntity.setLastName(userReq.getLastName()); userEntity.setOrganization(userReq.getOrganization()); userEntity.setAddress(userReq.getAddress()); userEntity.setPhoneNumber(userReq.getPhoneNumber()); userEntity.setDateOfBirth(userReq.getDateOfBirth()); } return userRepository.save(userEntity); } private RoleEntity getRoleEntity(Long roleId) { if(roleId != null) { return roleDao.validateRole(roleId); } else { return roleDao.getRoleByType(RoleStatusEnum.ROLE_BENEFICIARY); } } private UserResponseBean convertUserEntityToUserResponse(UserEntity userEntity) { UserResponseBean userResponseBean = new UserResponseBean(); userResponseBean.setId(userEntity.getId()); userResponseBean.setCreatedDate(userEntity.getCreatedDate()); userResponseBean.setUpdatedDate(userEntity.getUpdatedDate()); userResponseBean.setEmail(userEntity.getEmail()); userResponseBean.setStatus(UserStatusEnum.valueOf(userEntity.getStatus())); RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity()); userResponseBean.setRole(roleResponseBean); userResponseBean.setLastLogin(userEntity.getLastLogin()); List companyResponseBeans = companyDao.getCompanyByUserId(userEntity.getId()); userResponseBean.setCompanies(companyResponseBeans); if (userEntity.getBeneficiary() == null) { userResponseBean.setFirstName(userEntity.getFirstName()); userResponseBean.setLastName(userEntity.getLastName()); userResponseBean.setPhoneNumber(userEntity.getPhoneNumber()); userResponseBean.setOrganization(userEntity.getOrganization()); userResponseBean.setAddress(userEntity.getAddress()); userResponseBean.setCity(userEntity.getCity()); userResponseBean.setCountry(userEntity.getCountry()); userResponseBean.setDateOfBirth(userEntity.getDateOfBirth()); } else { userResponseBean.setFirstName(userEntity.getBeneficiary().getFirstName()); userResponseBean.setLastName(userEntity.getBeneficiary().getLastName()); userResponseBean.setPhoneNumber(userEntity.getBeneficiary().getPhoneNumber()); userResponseBean.setOrganization(userEntity.getBeneficiary().getOrganization()); userResponseBean.setAddress(userEntity.getBeneficiary().getAddress()); userResponseBean.setCity(userEntity.getBeneficiary().getCity()); userResponseBean.setCountry(userEntity.getBeneficiary().getCountry()); userResponseBean.setCodiceFiscale(userEntity.getBeneficiary().getCodiceFiscale()); userResponseBean.setDateOfBirth(userEntity.getBeneficiary().getDateOfBirth()); userResponseBean.setPrivacy(userEntity.getBeneficiary().getPrivacy()); userResponseBean.setTerms(userEntity.getBeneficiary().getTerms()); userResponseBean.setOffers(userEntity.getBeneficiary().getOffers()); userResponseBean.setMarketing(userEntity.getBeneficiary().getMarketing()); userResponseBean.setThirdParty(userEntity.getBeneficiary().getThirdParty()); userResponseBean.setEmailPec(userEntity.getBeneficiary().getEmailPec()); } return userResponseBean; } public UserResponseBean getUserById(Long id) { log.info("Fetching user with ID: {}", id); UserEntity userEntity = validateUser(id); // if (!UserStatusEnum.ACTIVE.getValue().equals(userEntity.getStatus())) { // log.info("User with ID: {} is not active", id); // throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); // } log.info("User found: {}", userEntity); return convertUserEntityToUserResponse(userEntity); } public void deleteUser(Long id) { log.info("Deleting user with ID: {}", id); UserEntity oldUserData = validateUser(id); /** This code is responsible for adding a version history log for the "Delete user" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(oldUserData).build()); userRepository.deleteById(id); log.info("User deleted with ID: {}", id); } public JWTToken login(LoginReq loginReq,HttpServletRequest request) { log.info("User login attempt for email: {}", loginReq.getEmail()); if(StringUtils.isEmpty(loginReq.getHubUuid())) { loginReq.setHubUuid(defaultHubUuid); } JWTToken jwtToken = authService.login(loginReq,request); log.info("Login successful for email: {}", loginReq.getEmail()); return jwtToken; } public UserEntity validateUser(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); } public UserEntity getUserByBeneficiaryId(Long beneficiaryId) { UserEntity user = userRepository.findByBeneficiaryId(beneficiaryId); if (user == null) { throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_WITH_BENEFICIARYID_MSG)); } return user; } public void initiatePasswordReset(InitiatePasswordResetReq resetReq) { UserEntity user = userRepository.findUserExcludingRoleType( resetReq.getEmail(), resetReq.getHubUuid(), RoleStatusEnum.ROLE_BENEFICIARY.getValue() ).orElseThrow(() -> new ResourceNotFoundException( Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG) )); UserEntity oldUserEntity = Utils.getClonedEntityForData(user); String token = Utils.generateSecureToken(); user.setResetPasswordToken(token); userRepository.save(user); /** This code is responsible for adding a version history log for the "Initiate password reset request" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build()); log.info("Password reset token generated for user: {}", resetReq.getEmail()); sendResetPasswordTokenEmail(user, token); } public void sendResetPasswordTokenEmail(UserEntity user, String token) { SystemEmailTemplateResponse emailTemplate = systemEmailTemplatesService.retrieveTemplateByTypeAndCall( SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.PASSWORD_RESET, user.getHub(), null); String redirectUrl = feBaseUrl; if (Boolean.FALSE.equals(StringUtils.isEmpty(user.getHub().getDomainName()))) { redirectUrl = user.getHub().getDomainName(); } EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest( emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, user.getId(), user.getEmail(), user.getId(), null, null, null); redirectUrl = String.format( user.getHub().getDomainName() + GepafinConstant.RESET_PASSWORD_URL_FORMAT, token, user.getEmail() ); String firstName = user.getFirstName() != null ? user.getFirstName() : ""; String lastName = user.getLastName() != null ? user.getLastName() : ""; String userName = String.join(" ", firstName, lastName).trim(); String subject = Utils.replacePlaceholders(emailTemplate.getSubject(), Map.of( "{{user_name}}", userName )); String body = Utils.replacePlaceholders(emailTemplate.getHtmlContent(), Map.of( "{{user_name}}", userName, "{{reset_password_link}}", redirectUrl )); emailNotificationDao.sendMail( user.getHub().getId(), subject, body, List.of(user.getEmail()), emailLogRequest ); log.info("Password reset token email sent to: {}", user.getEmail()); } public Boolean resetPassword(ResetPasswordReq resetPasswordReq) { UserEntity user = userRepository.findUserExcludingRoleType( resetPasswordReq.getEmail(), resetPasswordReq.getHubUuid(), RoleStatusEnum.ROLE_BENEFICIARY.getValue() ).orElseThrow(() -> new ResourceNotFoundException( Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG) )); UserEntity oldUserEntity = Utils.getClonedEntityForData(user); if (!resetPasswordReq.getNewPassword().equals(resetPasswordReq.getConfirmPassword())) { log.info("User creation failed: Passwords do not match for email {}", user.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_DOESNT_MATCH)); } String dbToken = user.getResetPasswordToken(); if (dbToken == null || !dbToken.equals(resetPasswordReq.getToken())) { log.info("Invalid password reset token for user: {}", resetPasswordReq.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_TOKEN_MSG)); } user.setPassword(passwordEncoder.encode(resetPasswordReq.getNewPassword())); user.setResetPasswordToken(null); userRepository.save(user); /** This code is responsible for adding a version history log for the "Reset Password " operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build()); log.info("Password successfully reset for user: {}", resetPasswordReq.getEmail()); return true; } public Boolean changePassword(UserEntity userEntity, ChangePasswordRequest changePasswordRequest) { UserEntity user = userRepository .findUserExcludingRoleType(changePasswordRequest.getEmail(), userEntity.getHub().getUniqueUuid(),RoleStatusEnum.ROLE_BENEFICIARY.getValue()) .orElseThrow(() -> new ResourceNotFoundException( Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG) )); UserEntity oldUserEntity = Utils.getClonedEntityForData(userEntity); if (!passwordEncoder.matches(changePasswordRequest.getPassword(), user.getPassword())) { throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.CURRENT_PASSWORD_INCORRECT)); } if (!changePasswordRequest.getNewPassword().equals(changePasswordRequest.getConfirmPassword())) { log.info("User creation failed: Passwords do not match for email {}", user.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_DOESNT_MATCH)); } user.setPassword(passwordEncoder.encode(changePasswordRequest.getNewPassword())); userRepository.save(user); /** This code is responsible for adding a version history log for the "Change user password" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build()); return true; } public void logout(HttpServletRequest request, HttpServletResponse response) { authService.logout(request, response); log.info("User successfully logged out."); } public UserResponseBean updateUserStatus(Long userId, UserStatusEnum statusReq) { log.info("Updating status for user with ID: {}", userId); UserEntity userEntity=validateUser(userId); userEntity.setStatus(statusReq.getValue()); userEntity = userRepository.save(userEntity); log.info("User status updated to {} for user ID: {}", statusReq, userId); return convertUserEntityToUserResponse(userEntity); } public List getUserByHubId(String hubId) { // log.info("Fetching users for hub ID: {}", hubId); // List userHubMappings = userHubRepository.findByHubId(hubId); List userResponseBeans = new ArrayList<>(); // for (UserHubEntity mapping : userHubMappings) { // UserEntity userEntity = validateUser(mapping.getUserId()); // userResponseBeans.add(convertUserEntityToUserResponse(userEntity)); // } return userResponseBeans; } public JWTToken validateExistingUserToken(HttpServletRequest request,String token) { return authService.validateExistingUserToken(request,token); } public UserSamlResponse validateNewUserToken(String token) { return authService.validateNewUserToken(token); } public List getAllUsers(UserEntity user, List roleIds) { List users; if (roleIds != null) { log.info("Fetching users by role ID: {}", roleIds); List roleEntities = roleIds.stream() .map(roleService::validateRole) // Assuming `validateRole` takes an ID and returns a RoleEntity .collect(Collectors.toList()); users = userRepository.findByRoleEntityIdInAndHubId(roleIds, user.getHub().getId()); } else { log.info("Fetching all users"); users = userRepository.findByHubId(user.getHub().getId()); } List userResponseBeans = users.stream() .map(this::convertUserEntityToUserResponse) .collect(Collectors.toList()); log.info("Total users found with role ID {}: {}", roleIds, userResponseBeans.size()); return userResponseBeans; } public PageableResponseBean> getUserByPagination(UserPaginationRequestBean userPaginationRequestBean,UserEntity userEntity) { Integer pageNo = null; Integer pageLimit = null; if (userPaginationRequestBean.getGlobalFilters() != null) { pageNo = userPaginationRequestBean.getGlobalFilters().getPage(); pageLimit = userPaginationRequestBean.getGlobalFilters().getLimit(); } if (pageLimit == null || pageLimit <= 0) { pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; } if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } Specification spec = search(userPaginationRequestBean,userEntity); Page entityPage = userRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); List applicationResponses = entityPage.getContent().stream() .map(user -> { UserResponseBean response = convertUserEntityToUserResponse(user); return response; }) .collect(Collectors.toList()); PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); pageableResponseBean.setBody(applicationResponses); 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(UserPaginationRequestBean userPaginationRequestBean,UserEntity userEntity) { return (root, query, criteriaBuilder) -> { List predicates = getPredicates(userPaginationRequestBean, criteriaBuilder, root,userEntity); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (userPaginationRequestBean .getGlobalFilters() != null && userPaginationRequestBean.getGlobalFilters().getSortBy() != null && userPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( isEmpty(userPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName()))) { sortBy.setColumnName(userPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName()); sortBy.setSortDesc(true); if (userPaginationRequestBean.getGlobalFilters().getSortBy().getSortDesc() != null) { sortBy.setSortDesc(userPaginationRequestBean.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(UserPaginationRequestBean userPaginationRequestBean, CriteriaBuilder criteriaBuilder, Root root,UserEntity user) { Integer year = null; String search = null; if (userPaginationRequestBean.getGlobalFilters() != null) { year = userPaginationRequestBean.getGlobalFilters().getYear(); search = userPaginationRequestBean.getGlobalFilters().getSearch(); } List predicates = new ArrayList<>(); if (year != null && year > 0) { int filterYear = userPaginationRequestBean.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 predicate = criteriaBuilder.like( criteriaBuilder.upper(root.get("firstName")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate)); Predicate predicate1 = criteriaBuilder.like( criteriaBuilder.upper(root.get("lastName")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate1)); Predicate predicate2 = criteriaBuilder.like( criteriaBuilder.upper(root.get("phoneNumber")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate2)); Predicate predicate3 = criteriaBuilder.like( criteriaBuilder.upper(root.get("organization")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate3)); Predicate predicate4 = criteriaBuilder.like( criteriaBuilder.upper(root.get("address")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate4)); Predicate predicate5 = criteriaBuilder.like( criteriaBuilder.upper(root.get("city")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate5)); Predicate predicate6 = criteriaBuilder.like( criteriaBuilder.upper(root.get("country")), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(predicate6)); } // Filter by `status` (if status list is provided) if (userPaginationRequestBean.getStatus() != null && !userPaginationRequestBean.getStatus().isEmpty()) { List statusValues = userPaginationRequestBean.getStatus().stream() .map(UserStatusEnum::name) // Convert enum to string .toList(); predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); } if (userPaginationRequestBean.getRole() != null && !userPaginationRequestBean.getRole().isEmpty()) { List roleValues = userPaginationRequestBean.getRole().stream() .map(RoleStatusEnum::name) // Convert enum to string .toList(); predicates.add(root.get("roleEntity").get("roleType").in(roleValues)); } predicates.add(root.get(GepafinConstant.HUB).get("id").in(user.getHub().getId())); return predicates; } public UserResponseBean updateUserDetails(HttpServletRequest request , Long userId, UpdateUserReqForBeneficiary userReq){ log.info("Updating user by beneficiary with ID: {}", userId); UserEntity userEntity = validator.validateUserId(request, userId); UserEntity oldUserEntity = Utils.getClonedEntityForData(userEntity); log.info("Current user details: {}", userEntity); log.info("New user details: {}", userReq); HubEntity hubEntity = hubService.valdateHub(userEntity.getHub().getId()); String beneficiaryRoleType = RoleStatusEnum.ROLE_BENEFICIARY.getValue(); if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { // Validate if the new email already exists for another beneficiary in the same hub boolean emailExistsForBeneficiary = userRepository.existsByEmailIgnoreCaseForBeneficiaries( userReq.getEmail(), hubEntity.getUniqueUuid(), beneficiaryRoleType); if (emailExistsForBeneficiary) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS)); } setIfUpdated(userEntity::getEmail,userEntity::setEmail,userReq.getEmail()); // Only update email if role is beneficiary } BeneficiaryEntity oldBeneficiaryEntity = null; if(userEntity.getBeneficiary()!=null) { oldBeneficiaryEntity = Utils.getClonedEntityForData(userEntity.getBeneficiary()); setIfUpdated(userEntity.getBeneficiary()::getFirstName, userEntity.getBeneficiary()::setFirstName, userReq.getFirstName()); setIfUpdated(userEntity.getBeneficiary()::getLastName, userEntity.getBeneficiary()::setLastName, userReq.getLastName()); setIfUpdated(userEntity.getBeneficiary()::getOrganization, userEntity.getBeneficiary()::setOrganization, userReq.getOrganization()); setIfUpdated(userEntity.getBeneficiary()::getAddress, userEntity.getBeneficiary()::setAddress, userReq.getAddress()); setIfUpdated(userEntity.getBeneficiary()::getPhoneNumber, userEntity.getBeneficiary()::setPhoneNumber, userReq.getPhoneNumber()); setIfUpdated(userEntity.getBeneficiary()::getDateOfBirth, userEntity.getBeneficiary()::setDateOfBirth, userReq.getDateOfBirth()); setIfUpdated(userEntity.getBeneficiary()::getCity, userEntity.getBeneficiary()::setCity, userReq.getCity()); setIfUpdated(userEntity.getBeneficiary()::getCountry, userEntity.getBeneficiary()::setCountry, userReq.getCountry()); /** This code is responsible for adding a version history log for the "Update beneficiary details " operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldBeneficiaryEntity).newData(userEntity.getBeneficiary()).build()); } userEntity = userRepository.save(userEntity); /** This code is responsible for adding a version history log for the "Update user details by beneficiary" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldUserEntity).newData(userEntity).build()); return convertUserEntityToUserResponse(userEntity); } }