From d438e99dd6d7ce984021fb45403eb7457eb4e0d7 Mon Sep 17 00:00:00 2001 From: pmcphee77 <150798161+pmcphee77@users.noreply.github.com> Date: Fri, 12 Jan 2024 09:11:29 +0000 Subject: [PATCH] PI-1785: Added get user details by id (#3008) * PI-1785: Added get user details by id --- .../justice/digital/hmpps/data/DataLoader.kt | 10 +++---- .../hmpps/data/generator/UserGenerator.kt | 8 ++--- .../hmpps/UserDetailsIntegrationTest.kt | 29 +++++++++++++++++++ .../hmpps/controller/UserController.kt | 6 ++++ .../gov/justice/digital/hmpps/entity/User.kt | 29 +++++++++++++++++++ .../digital/hmpps/service/UserService.kt | 20 ++++++++----- 6 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/User.kt diff --git a/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 9be1e46bcd..fc1400ab6b 100644 --- a/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -7,22 +7,22 @@ import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.ApplicationListener import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.data.generator.UserGenerator -import uk.gov.justice.digital.hmpps.user.AuditUserRepository +import uk.gov.justice.digital.hmpps.entity.UserRepository @Component @ConditionalOnProperty("seed.database") class DataLoader( - private val auditUserRepository: AuditUserRepository + private val userRepository: UserRepository ) : ApplicationListener { @PostConstruct fun saveAuditUser() { - auditUserRepository.save(UserGenerator.AUDIT_USER) + userRepository.save(UserGenerator.USER) } @Transactional override fun onApplicationEvent(are: ApplicationReadyEvent) { - auditUserRepository.save(UserGenerator.TEST_USER) - auditUserRepository.save(UserGenerator.INACTIVE_USER) + userRepository.save(UserGenerator.TEST_USER) + userRepository.save(UserGenerator.INACTIVE_USER) } } diff --git a/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt b/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt index 5a993c33e4..1090a3ba15 100644 --- a/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt +++ b/projects/hmpps-auth-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt @@ -1,9 +1,9 @@ package uk.gov.justice.digital.hmpps.data.generator -import uk.gov.justice.digital.hmpps.user.AuditUser +import uk.gov.justice.digital.hmpps.entity.User object UserGenerator { - val AUDIT_USER = AuditUser(IdGenerator.getAndIncrement(), "HmppsAuthAndDelius") - val TEST_USER = AuditUser(IdGenerator.getAndIncrement(), "test.user") - val INACTIVE_USER = AuditUser(IdGenerator.getAndIncrement(), "test.user.inactive") + val USER = User(IdGenerator.getAndIncrement(), "HmppsAuthAndDelius") + val TEST_USER = User(IdGenerator.getAndIncrement(), "test.user") + val INACTIVE_USER = User(IdGenerator.getAndIncrement(), "test.user.inactive") } diff --git a/projects/hmpps-auth-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserDetailsIntegrationTest.kt b/projects/hmpps-auth-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserDetailsIntegrationTest.kt index 5ec918ccd6..6fdb6b80cd 100644 --- a/projects/hmpps-auth-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserDetailsIntegrationTest.kt +++ b/projects/hmpps-auth-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserDetailsIntegrationTest.kt @@ -42,6 +42,35 @@ internal class UserDetailsIntegrationTest { ) } + @Test + fun `calling user by id without userId returns 400`() { + mockMvc.perform(get("/user").withToken()) + .andExpect(status().isBadRequest) + } + + @Test + fun `missing user by id returns 404`() { + mockMvc.perform(get("/user/details/99999").withToken()) + .andExpect(status().isNotFound) + } + + @Test + fun `get user by id`() { + mockMvc.perform(get("/user/details/" + TEST_USER.id).withToken()) + .andExpect(status().isOk) + .andExpectJson( + UserDetails( + userId = TEST_USER.id, + username = "test.user", + firstName = "Test", + surname = "User", + email = "test.user@example.com", + enabled = true, + roles = listOf("ABC001", "ABC002") + ) + ) + } + @Test fun `search by email`() { mockMvc.perform(get("/user?email=test.user@example.com").withToken()) diff --git a/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/UserController.kt b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/UserController.kt index bbeeaae695..99cca7cfc7 100644 --- a/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/UserController.kt +++ b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/UserController.kt @@ -28,6 +28,12 @@ class UserController(private val userService: UserService) { fun getUserDetails(@PathVariable username: String) = userService.getUserDetails(username) ?: throw NotFoundException("User", "username", username) + @GetMapping(value = ["/user/details/{userId}"]) + @PreAuthorize("hasAnyRole('ROLE_DELIUS_USER_AUTH', 'ROLE_DELIUS_USER_DETAILS')") + @Operation(description = "Get user details by Id. Requires `ROLE_DELIUS_USER_AUTH` or `ROLE_DELIUS_USER_DETAILS`.") + fun getUserDetailsById(@PathVariable(required = true) userId: Long) = userService.getUserDetailsById(userId) + ?: throw NotFoundException("User", "userId", userId) + @GetMapping(value = ["/user"]) @PreAuthorize("hasAnyRole('ROLE_DELIUS_USER_AUTH')") @Operation(description = "Get users by email. Requires `ROLE_DELIUS_USER_AUTH`.") diff --git a/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/User.kt b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/User.kt new file mode 100644 index 0000000000..df023c0a32 --- /dev/null +++ b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/User.kt @@ -0,0 +1,29 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +@Immutable +@Entity +@Table(name = "user_") +class User( + @Id + @Column(name = "user_id") + val id: Long, + + @Column(name = "distinguished_name") + val username: String +) + +interface UserRepository : JpaRepository { + fun findUserById(userId: Long): User? + + @Query("select u from User u where upper(u.username) = upper(:username)") + fun findUserByUsername(username: String): User? +} + diff --git a/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt index 4eb2a23972..b6789616e7 100644 --- a/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt +++ b/projects/hmpps-auth-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt @@ -7,21 +7,26 @@ import org.springframework.ldap.query.LdapQueryBuilder.query import org.springframework.ldap.query.SearchScope import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.entity.LdapUser +import uk.gov.justice.digital.hmpps.entity.UserRepository import uk.gov.justice.digital.hmpps.exception.NotFoundException import uk.gov.justice.digital.hmpps.ldap.byUsername import uk.gov.justice.digital.hmpps.ldap.findByUsername import uk.gov.justice.digital.hmpps.model.UserDetails -import uk.gov.justice.digital.hmpps.user.AuditUserService import javax.naming.Name @Service class UserService( private val ldapTemplate: LdapTemplate, - private val auditUserService: AuditUserService + private val userRepository: UserRepository ) { fun getUserDetails(username: String) = ldapTemplate.findByUsername(username)?.toUserDetails() + fun getUserDetailsById(userId: Long) = + userRepository.findUserById(userId)?.let { + ldapTemplate.findByUsername(it.username)?.toUserDetails(it.id) + } + fun getUsersByEmail(email: String) = ldapTemplate.find( query() .base("ou=Users") @@ -47,12 +52,11 @@ class UserService( AttributesMapper { it["cn"].get().toString() } ) - private fun LdapUser.toUserDetails() = UserDetails( - userId = auditUserService.findUser(username)?.id ?: throw NotFoundException( - "User entity", - "username", - username - ), + private fun LdapUser.toUserDetails() = userRepository.findUserByUsername(username)?.let { toUserDetails(it.id) } + ?: throw NotFoundException("User entity", "username", username) + + private fun LdapUser.toUserDetails(userId: Long) = UserDetails( + userId = userId, username = username, firstName = forename, surname = surname,