package net.gepafin.tendermanagement.dao; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.RoleEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.response.RoleResponseBean; import net.gepafin.tendermanagement.model.response.UserResponseBean; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.service.impl.AuthenticationService; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Repository; import java.security.SecureRandom; import java.util.Base64; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; @Repository public class UserDao { private final Logger log = LoggerFactory.getLogger(UserDao.class); @Autowired private UserRepository userRepository; @Autowired private AuthenticationService authService; @Autowired private PasswordEncoder passwordEncoder; @Autowired private RoleDao roleDao; public UserResponseBean createUser(UserReq userReq) { log.info("Creating user with email: {}", userReq.getEmail()); if (userRepository.existsByEmailIgnoreCase(userReq.getEmail())) { log.error("User creation failed: Email {} already exists", userReq.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS)); } if (!userReq.getPassword().equals(userReq.getConfPassword())) { log.error("User creation failed: Passwords do not match for email {}", userReq.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_DOESNT_MATCH)); } if (userReq.getPassword().length() < 8) { log.error("User creation failed: Password length is less than 8 characters for email {}", userReq.getEmail()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_MIN_LEN)); } UserEntity userEntity = convertUserRequestToUserEntity(userReq); userEntity = userRepository.save(userEntity); log.info("User created with ID: {}", userEntity.getId()); return convertUserEntityToUserResponse(userEntity); } public UserResponseBean updateUser(Long userId, UpdateUserReq userReq) { log.info("Updating user with ID: {}", userId); UserEntity userEntity = userRepository.findById(userId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND_MSG))); log.info("Current user details: {}", userEntity); log.info("New user details: {}", userReq); String newStatus = userReq.getStatus() != null ? userReq.getStatus().getValue() : null; if (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()); if (userReq.getRoleId() != null) { RoleEntity roleEntity = roleDao.validateRole(userReq.getRoleId()); setIfUpdated(userEntity::getRoleEntity, userEntity::setRoleEntity, roleEntity); } userEntity = userRepository.save(userEntity); log.info("User updated with ID: {}", userEntity.getId()); return convertUserEntityToUserResponse(userEntity); } private UserEntity convertUserRequestToUserEntity(UserReq userReq) { UserEntity userEntity = new UserEntity(); userEntity.setPassword(passwordEncoder.encode(userReq.getPassword())); userEntity.setEmail(userReq.getEmail()); userEntity.setFirstName(userReq.getFirstName()); userEntity.setStatus(UserStatusEnum.PENDING_VERIFICATION.getValue()); userEntity.setLastName(userReq.getLastName()); userEntity.setOrganization(userReq.getOrganization()); userEntity.setAddress(userReq.getAddress()); userEntity.setPhoneNumber(userReq.getPhoneNumber()); userEntity.setRoleEntity(roleDao.validateRole(userReq.getRoleId())); return userEntity; } 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.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.setStatus(UserStatusEnum.valueOf(userEntity.getStatus())); RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity()); userResponseBean.setRole(roleResponseBean); userResponseBean.setLastLogin(userEntity.getLastLogin()); return userResponseBean; } public UserResponseBean getUserById(Long id) { log.info("Fetching user with ID: {}", id); UserEntity userEntity = userRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); // 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); userRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); userRepository.deleteById(id); log.info("User deleted with ID: {}", id); } public JWTToken login(LoginReq loginReq) { log.info("User login attempt for email: {}", loginReq.getEmail()); JWTToken jwtToken = authService.login(loginReq); log.info("Login successful for email: {}", loginReq.getEmail()); return jwtToken; } public UserEntity validateUser(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); } public String generateSecureToken() { SecureRandom secureRandom = new SecureRandom(); byte[] tokenBytes = new byte[24]; secureRandom.nextBytes(tokenBytes); String token = Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes); log.debug("Generated secure token: {}", token); return token; } public String initiatePasswordReset(InitiatePasswordResetReq resetReq) { UserEntity user = userRepository.findByEmail(resetReq.getEmail()); if (user == null) { log.info("Password reset attempt for non-existent user: {}", resetReq.getEmail()); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); } String token = generateSecureToken(); user.setResetPasswordToken(token); userRepository.save(user); log.info("Password reset token generated for user: {}", resetReq.getEmail()); return token; } public Boolean resetPassword(ResetPasswordReq resetPasswordReq) { UserEntity user = userRepository.findByEmail(resetPasswordReq.getEmail()); if (user == null) { log.info("Password reset attempt for non-existent user: {}", resetPasswordReq.getEmail()); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); } 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); log.info("Password successfully reset for user: {}", resetPasswordReq.getEmail()); return true; } public Boolean changePassword(ChangePasswordRequest request) { UserEntity user = userRepository.findByEmail(request.getEmail()); if (user == null) { log.info("Password reset attempt for non-existent user: {}", request.getEmail()); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); } if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.CURRENT_PASSWORD_INCORRECT)); } if (!request.getNewPassword().equals(request.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(request.getNewPassword())); userRepository.save(user); 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 = userRepository.findById(userId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); userEntity.setStatus(statusReq.getValue()); userEntity = userRepository.save(userEntity); log.info("User status updated to {} for user ID: {}", statusReq, userId); return convertUserEntityToUserResponse(userEntity); } }