UserService.kt

  1. package delta.codecharacter.server.user

  2. import delta.codecharacter.dtos.CompleteProfileRequestDto
  3. import delta.codecharacter.dtos.RegisterUserRequestDto
  4. import delta.codecharacter.dtos.UpdatePasswordRequestDto
  5. import delta.codecharacter.server.exception.CustomException
  6. import delta.codecharacter.server.user.activate_user.ActivateUserService
  7. import delta.codecharacter.server.user.public_user.PublicUserService
  8. import delta.codecharacter.server.user.rating_history.RatingHistoryService
  9. import org.springframework.beans.factory.annotation.Autowired
  10. import org.springframework.context.annotation.Lazy
  11. import org.springframework.dao.DuplicateKeyException
  12. import org.springframework.http.HttpStatus
  13. import org.springframework.security.core.authority.SimpleGrantedAuthority
  14. import org.springframework.security.core.userdetails.UserDetailsService
  15. import org.springframework.security.core.userdetails.UsernameNotFoundException
  16. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
  17. import org.springframework.stereotype.Service
  18. import java.util.Optional
  19. import java.util.UUID

  20. @Service
  21. class UserService(
  22.     @Autowired private val userRepository: UserRepository,
  23.     @Autowired private val publicUserService: PublicUserService,
  24.     @Autowired private val ratingHistoryService: RatingHistoryService,
  25.     @Autowired private val activateUserService: ActivateUserService
  26. ) : UserDetailsService {

  27.     @Lazy @Autowired private lateinit var passwordEncoder: BCryptPasswordEncoder

  28.     override fun loadUserByUsername(email: String?): UserEntity {
  29.         if (email == null) {
  30.             throw UsernameNotFoundException("User not found")
  31.         }
  32.         val user = userRepository.findFirstByEmail(email)
  33.         if (user.isEmpty) {
  34.             throw UsernameNotFoundException("User not found")
  35.         } else if (!user.get().isEnabled) {
  36.             throw CustomException(HttpStatus.UNAUTHORIZED, "Email not verified")
  37.         } else if (!user.get().isAccountNonExpired) {
  38.             throw CustomException(HttpStatus.UNAUTHORIZED, "Account expired")
  39.         } else {
  40.             return user.get()
  41.         }
  42.     }

  43.     private fun createUserWithPassword(userId: UUID, password: String, email: String) {
  44.         val user =
  45.             UserEntity(
  46.                 id = userId,
  47.                 password = passwordEncoder.encode(password),
  48.                 email = email,
  49.                 loginType = LoginType.PASSWORD,
  50.                 isProfileComplete = true,
  51.                 isEnabled = false,
  52.                 isAccountNonExpired = true,
  53.                 isAccountNonLocked = true,
  54.                 isCredentialsNonExpired = true,
  55.                 userAuthorities = mutableListOf(SimpleGrantedAuthority("ROLE_USER"))
  56.             )
  57.         userRepository.save(user)
  58.     }

  59.     fun createUserWithOAuth(email: String, oauthProvider: LoginType): UserEntity {
  60.         val userId = UUID.randomUUID()
  61.         val user =
  62.             UserEntity(
  63.                 id = userId,
  64.                 password = passwordEncoder.encode(UUID.randomUUID().toString()),
  65.                 email = email,
  66.                 loginType = oauthProvider,
  67.                 isProfileComplete = false,
  68.                 isEnabled = true,
  69.                 isAccountNonExpired = true,
  70.                 isAccountNonLocked = true,
  71.                 isCredentialsNonExpired = true,
  72.                 userAuthorities = mutableListOf(SimpleGrantedAuthority("ROLE_USER_INCOMPLETE_PROFILE"))
  73.             )
  74.         ratingHistoryService.create(userId)
  75.         return userRepository.save(user)
  76.     }

  77.     fun getUserByEmail(email: String): Optional<UserEntity> {
  78.         return userRepository.findFirstByEmail(email)
  79.     }

  80.     fun updateUserPassword(userId: UUID, password: String) {
  81.         val user = userRepository.findById(userId).get()
  82.         userRepository.save(user.copy(password = passwordEncoder.encode(password)))
  83.     }

  84.     fun verifyUserPassword(userId: UUID, password: String): Boolean {
  85.         val user = userRepository.findById(userId)
  86.         return passwordEncoder.matches(password, user.get().password)
  87.     }

  88.     fun updatePassword(userId: UUID, updatePasswordRequestDto: UpdatePasswordRequestDto) {
  89.         val (oldPassword, password, passwordConfirmation) = updatePasswordRequestDto
  90.         if (password != passwordConfirmation) {
  91.             throw CustomException(HttpStatus.BAD_REQUEST, "Passwords do not match")
  92.         }
  93.         if (verifyUserPassword(userId, oldPassword)) {
  94.             val user = userRepository.findById(userId).get()
  95.             userRepository.save(user.copy(password = passwordEncoder.encode(password)))
  96.         } else {
  97.             throw CustomException(HttpStatus.BAD_REQUEST, "Old password is incorrect")
  98.         }
  99.     }

  100.     fun registerUser(registerUserRequestDto: RegisterUserRequestDto) {
  101.         val (username, name, email, password, passwordConfirmation, country, college, avatarId) =
  102.             registerUserRequestDto

  103.         if (password != passwordConfirmation) {
  104.             throw CustomException(
  105.                 HttpStatus.BAD_REQUEST, "Password and password confirmation don't match"
  106.             )
  107.         }

  108.         if (!publicUserService.isUsernameUnique(username)) {
  109.             throw CustomException(HttpStatus.BAD_REQUEST, "Username already taken")
  110.         }

  111.         val userId = UUID.randomUUID()
  112.         try {
  113.             createUserWithPassword(userId, password, email)
  114.             publicUserService.create(userId, username, name, country, college, avatarId)
  115.             ratingHistoryService.create(userId)
  116.             activateUserService.sendActivationToken(userId, name, email)
  117.         } catch (duplicateError: DuplicateKeyException) {
  118.             throw CustomException(HttpStatus.BAD_REQUEST, "Username/Email already exists")
  119.         }
  120.     }

  121.     fun activateUser(userId: UUID, token: String) {
  122.         activateUserService.processActivationToken(userId, token)
  123.         val user = userRepository.findFirstById((userId)).get()
  124.         val activatedUser = user.copy(isEnabled = true)
  125.         userRepository.save(activatedUser)
  126.     }

  127.     fun completeUserProfile(userId: UUID, completeProfileRequestDto: CompleteProfileRequestDto) {
  128.         val (username, name, country, college, avatarId) = completeProfileRequestDto
  129.         val user = userRepository.findFirstById(userId).get()
  130.         publicUserService.create(userId, username, name, country, college, avatarId)
  131.         userRepository.save(
  132.             user.copy(
  133.                 isProfileComplete = true,
  134.                 userAuthorities = mutableListOf(SimpleGrantedAuthority("ROLE_USER"))
  135.             )
  136.         )
  137.     }
  138. }