From c9caca9b705621addcd4d2c42b5ba9cb0e7da03c Mon Sep 17 00:00:00 2001 From: JasCon Date: Tue, 8 Oct 2024 17:20:22 +0100 Subject: [PATCH 01/12] PRSD-358: Add a placeholder controller and page --- .../controllers/ManageLAUsersController.kt | 20 +++++++++++++++++++ .../resources/templates/manageLAUsers.html | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt create mode 100644 src/main/resources/templates/manageLAUsers.html diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt new file mode 100644 index 000000000..e29ba269e --- /dev/null +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt @@ -0,0 +1,20 @@ +package uk.gov.communities.prsdb.webapp.controllers + +import org.springframework.stereotype.Controller +import org.springframework.ui.Model +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import uk.gov.communities.prsdb.webapp.constants.SERVICE_NAME + +// @PreAuthorize("hasRole('LA_ADMIN')") +@Controller +@RequestMapping("/manage-users") +class ManageLAUsersController { + @GetMapping + fun index(model: Model): String { + model.addAttribute("contentHeader", "Manage Local Authority Users") + model.addAttribute("title", "Manage Local Authority Users") + model.addAttribute("serviceName", SERVICE_NAME) + return "manageLAUsers" + } +} diff --git a/src/main/resources/templates/manageLAUsers.html b/src/main/resources/templates/manageLAUsers.html new file mode 100644 index 000000000..5e747ecfa --- /dev/null +++ b/src/main/resources/templates/manageLAUsers.html @@ -0,0 +1,6 @@ + + +
+

Default page template

+
+ \ No newline at end of file From 484d404b73cc2adb30a962a327ba6b734688f441 Mon Sep 17 00:00:00 2001 From: JasCon Date: Wed, 9 Oct 2024 15:47:27 +0100 Subject: [PATCH 02/12] PRSD-358: Get list of users from database for a given given local authority id --- build.gradle.kts | 4 ++++ ....kt => ManageLocalAuthorityUsersController.kt} | 10 +++++++++- .../repository/LocalAuthorityUserRepository.kt | 5 ++++- .../webapp/models/LocalAuthorityUserDataModel.kt | 9 +++++++++ .../services/ManageLocalAuthorityUserService.kt | 15 +++++++++++++++ src/main/resources/data-local.sql | 6 ++++-- src/main/resources/templates/manageLAUsers.html | 1 + 7 files changed, 46 insertions(+), 4 deletions(-) rename src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/{ManageLAUsersController.kt => ManageLocalAuthorityUsersController.kt} (59%) create mode 100644 src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt create mode 100644 src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5d124cfde..4e62a597f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") version "1.9.25" kotlin("plugin.spring") version "1.9.25" + kotlin("plugin.serialization") version "2.0.20" id("org.springframework.boot") version "3.3.3" id("io.spring.dependency-management") version "1.1.6" kotlin("plugin.jpa") version "1.9.25" @@ -70,6 +71,9 @@ dependencies { testImplementation("org.springframework.security:spring-security-test") testImplementation("com.microsoft.playwright:playwright:1.47.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + // Serialization + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") } kotlin { diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt similarity index 59% rename from src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt rename to src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt index e29ba269e..35601d851 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLAUsersController.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt @@ -1,20 +1,28 @@ package uk.gov.communities.prsdb.webapp.controllers +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import uk.gov.communities.prsdb.webapp.constants.SERVICE_NAME +import uk.gov.communities.prsdb.webapp.services.ManageLocalAuthorityUserService // @PreAuthorize("hasRole('LA_ADMIN')") @Controller @RequestMapping("/manage-users") -class ManageLAUsersController { +class ManageLocalAuthorityUsersController( + val manageLocalAuthorityUserService: ManageLocalAuthorityUserService, +) { @GetMapping fun index(model: Model): String { + val users = manageLocalAuthorityUserService.getLocalAuthorityUsersForLocalAuthority(1) + val usersJson = Json.encodeToString(users) model.addAttribute("contentHeader", "Manage Local Authority Users") model.addAttribute("title", "Manage Local Authority Users") model.addAttribute("serviceName", SERVICE_NAME) + model.addAttribute("usersJson", usersJson) return "manageLAUsers" } } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt index 235fecea3..a30fcd90b 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt @@ -3,4 +3,7 @@ package uk.gov.communities.prsdb.webapp.database.repository import org.springframework.data.jpa.repository.JpaRepository import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthorityUser -interface LocalAuthorityUserRepository : JpaRepository +interface LocalAuthorityUserRepository : JpaRepository { + @Suppress("ktlint:standard:function-naming") + fun findByLocalAuthority_Id(localAuthorityId: Int): List +} diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt new file mode 100644 index 000000000..7606977dd --- /dev/null +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt @@ -0,0 +1,9 @@ +package uk.gov.communities.prsdb.webapp.models + +import kotlinx.serialization.Serializable + +@Serializable +data class LocalAuthorityUserDataModel( + val userName: String, + val isManager: Boolean, +) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt new file mode 100644 index 000000000..75bbf050e --- /dev/null +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt @@ -0,0 +1,15 @@ +package uk.gov.communities.prsdb.webapp.services + +import org.springframework.stereotype.Service +import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository +import uk.gov.communities.prsdb.webapp.models.LocalAuthorityUserDataModel + +@Service +class ManageLocalAuthorityUserService( + val localAuthorityUserRepository: LocalAuthorityUserRepository, +) { + fun getLocalAuthorityUsersForLocalAuthority(localAuthorityId: Int): List { + val usersInThisLocalAuthority = localAuthorityUserRepository.findByLocalAuthority_Id(localAuthorityId) + return usersInThisLocalAuthority.map { LocalAuthorityUserDataModel(it.baseUser.name, it.isManager) } + } +} diff --git a/src/main/resources/data-local.sql b/src/main/resources/data-local.sql index 3bb68b73a..30eb78b5a 100644 --- a/src/main/resources/data-local.sql +++ b/src/main/resources/data-local.sql @@ -1,7 +1,8 @@ INSERT INTO one_login_user (id, name, email, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:ABCDE', 'Bob T Builder', 'bobthebuilder@gmail.com', '09/13/24', '09/13/24'), ('urn:fdc:gov.uk:2022:FGHIJ', 'Anne Other', 'Anne.Other@hotmail.com', '09/13/24', '09/13/24'), - ('urn:fdc:gov.uk:2022:KLMNO', 'Ford Prefect', 'Ford.Prefect@hotmail.com', '10/07/24', '10/07/24'); + ('urn:fdc:gov.uk:2022:KLMNO', 'Ford Prefect', 'Ford.Prefect@hotmail.com', '10/07/24', '10/07/24'), + ('urn:fdc:gov.uk:2022:PQRST', 'Arthur Dent', 'Arthur.Dent@hotmail.com', '10/09/24', '10/09/24'); INSERT INTO landlord_user (subject_identifier, phone_number, date_of_birth, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:ABCDE', '07712345678', '01/01/00', '09/13/24', '09/13/24'), @@ -11,4 +12,5 @@ INSERT INTO local_authority (name, created_date, last_modified_date) VALUES ('Betelgeuse','09/13/24', '09/13/24'); INSERT INTO local_authority_user (subject_identifier, is_manager, local_authority_id, created_date, last_modified_date) -VALUES ('urn:fdc:gov.uk:2022:KLMNO',true, 1,'10/07/24', '10/07/24') \ No newline at end of file +VALUES ('urn:fdc:gov.uk:2022:KLMNO',true, 1,'10/07/24', '10/07/24'), + ('urn:fdc:gov.uk:2022:PQRST',false, 1,'10/09/24', '10/09/24') \ No newline at end of file diff --git a/src/main/resources/templates/manageLAUsers.html b/src/main/resources/templates/manageLAUsers.html index 5e747ecfa..35b873f62 100644 --- a/src/main/resources/templates/manageLAUsers.html +++ b/src/main/resources/templates/manageLAUsers.html @@ -2,5 +2,6 @@

Default page template

+

\ No newline at end of file From 82889adea027126139095ee73cf3edbb8dbd69b9 Mon Sep 17 00:00:00 2001 From: JasCon Date: Thu, 10 Oct 2024 14:37:09 +0100 Subject: [PATCH 03/12] PRSD-358: Get and use the LA id for the logged in user --- .../ManageLocalAuthorityUsersController.kt | 25 +++++++++++++------ .../webapp/database/entity/LocalAuthority.kt | 2 +- .../LocalAuthorityUserRepository.kt | 4 +++ ...ervice.kt => LocalAuthorityDataService.kt} | 12 ++++++++- .../prsdb/webapp/services/UserRolesService.kt | 13 ++++++++++ src/main/resources/data-local.sql | 9 ++++--- .../V1_0_0__initial_user_tables.sql | 6 ++--- 7 files changed, 56 insertions(+), 15 deletions(-) rename src/main/kotlin/uk/gov/communities/prsdb/webapp/services/{ManageLocalAuthorityUserService.kt => LocalAuthorityDataService.kt} (62%) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt index 35601d851..36f197e04 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt @@ -2,27 +2,38 @@ package uk.gov.communities.prsdb.webapp.controllers import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.springframework.security.access.prepost.PreAuthorize import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import uk.gov.communities.prsdb.webapp.constants.SERVICE_NAME -import uk.gov.communities.prsdb.webapp.services.ManageLocalAuthorityUserService +import uk.gov.communities.prsdb.webapp.services.LocalAuthorityDataService +import java.security.Principal -// @PreAuthorize("hasRole('LA_ADMIN')") +@PreAuthorize("hasRole('LA_ADMIN')") @Controller @RequestMapping("/manage-users") class ManageLocalAuthorityUsersController( - val manageLocalAuthorityUserService: ManageLocalAuthorityUserService, + val localAuthorityDataService: LocalAuthorityDataService, ) { @GetMapping - fun index(model: Model): String { - val users = manageLocalAuthorityUserService.getLocalAuthorityUsersForLocalAuthority(1) - val usersJson = Json.encodeToString(users) + fun index( + model: Model, + principal: Principal, + ): String { + val currentUserLocalAuthority = localAuthorityDataService.getLocalAuthorityForUser(principal.name) + if (currentUserLocalAuthority?.id != null) { + // We should always get to here as only LA_ADMINs can access this page + val users = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(currentUserLocalAuthority.id) + val usersJson = Json.encodeToString(users) + model.addAttribute("usersJson", usersJson) + } + model.addAttribute("contentHeader", "Manage Local Authority Users") model.addAttribute("title", "Manage Local Authority Users") model.addAttribute("serviceName", SERVICE_NAME) - model.addAttribute("usersJson", usersJson) + return "manageLAUsers" } } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt index 6c6453c21..b44912233 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt @@ -10,7 +10,7 @@ import jakarta.persistence.Id class LocalAuthority : AuditableEntity() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private val id: Int? = null + val id: Int? = null @Column(nullable = false) lateinit var name: String diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt index a30fcd90b..b4846e0eb 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt @@ -4,6 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthorityUser interface LocalAuthorityUserRepository : JpaRepository { + // The underscore tells JPA to access fields relating to the referenced table @Suppress("ktlint:standard:function-naming") fun findByLocalAuthority_Id(localAuthorityId: Int): List + + @Suppress("ktlint:standard:function-naming") + fun findByBaseUser_Id(userName: String): LocalAuthorityUser? } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt similarity index 62% rename from src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt rename to src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt index 75bbf050e..7492332cf 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/ManageLocalAuthorityUserService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt @@ -1,15 +1,25 @@ package uk.gov.communities.prsdb.webapp.services import org.springframework.stereotype.Service +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthority import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository import uk.gov.communities.prsdb.webapp.models.LocalAuthorityUserDataModel @Service -class ManageLocalAuthorityUserService( +class LocalAuthorityDataService( val localAuthorityUserRepository: LocalAuthorityUserRepository, ) { fun getLocalAuthorityUsersForLocalAuthority(localAuthorityId: Int): List { val usersInThisLocalAuthority = localAuthorityUserRepository.findByLocalAuthority_Id(localAuthorityId) return usersInThisLocalAuthority.map { LocalAuthorityUserDataModel(it.baseUser.name, it.isManager) } } + + fun getLocalAuthorityForUser(subjectId: String): LocalAuthority? { + val localAuthorityUser = localAuthorityUserRepository.findByBaseUser_Id(subjectId) + if (localAuthorityUser == null) { + return null + } + + return localAuthorityUser.localAuthority + } } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt index a4fb75442..5ba71b2b0 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt @@ -2,17 +2,30 @@ package uk.gov.communities.prsdb.webapp.services import org.springframework.stereotype.Service import uk.gov.communities.prsdb.webapp.database.repository.LandlordUserRepository +import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository @Service class UserRolesService( val landlordRepository: LandlordUserRepository, + val localAuthorityUserRepository: LocalAuthorityUserRepository, ) { fun getRolesforSubjectId(subjectId: String): List { val roles = mutableListOf() + val matchingLandlordUser = landlordRepository.findByBaseUser_Id(subjectId) if (matchingLandlordUser.isNotEmpty()) { roles.add("ROLE_LANDLORD") } + + val matchingLocalAuthorityUser = localAuthorityUserRepository.findByBaseUser_Id(subjectId) + if (matchingLocalAuthorityUser != null) { + if (matchingLocalAuthorityUser.isManager) { + roles.add("ROLE_LA_ADMIN") + } else { + roles.add("ROLE_LA_USER") + } + } + return roles } } diff --git a/src/main/resources/data-local.sql b/src/main/resources/data-local.sql index 30eb78b5a..8cef7fca9 100644 --- a/src/main/resources/data-local.sql +++ b/src/main/resources/data-local.sql @@ -2,15 +2,18 @@ INSERT INTO one_login_user (id, name, email, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:ABCDE', 'Bob T Builder', 'bobthebuilder@gmail.com', '09/13/24', '09/13/24'), ('urn:fdc:gov.uk:2022:FGHIJ', 'Anne Other', 'Anne.Other@hotmail.com', '09/13/24', '09/13/24'), ('urn:fdc:gov.uk:2022:KLMNO', 'Ford Prefect', 'Ford.Prefect@hotmail.com', '10/07/24', '10/07/24'), - ('urn:fdc:gov.uk:2022:PQRST', 'Arthur Dent', 'Arthur.Dent@hotmail.com', '10/09/24', '10/09/24'); + ('urn:fdc:gov.uk:2022:PQRST', 'Arthur Dent', 'Arthur.Dent@hotmail.com', '10/09/24', '10/09/24'), + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', 'Jasmin Conterio', 'jasmin.conterio@softwire.com', '10/07/24', '10/07/24'); INSERT INTO landlord_user (subject_identifier, phone_number, date_of_birth, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:ABCDE', '07712345678', '01/01/00', '09/13/24', '09/13/24'), - ('urn:fdc:gov.uk:2022:FGHIJ', '07811111111', '11/23/98', '09/13/24', '09/13/24'); + ('urn:fdc:gov.uk:2022:FGHIJ', '07811111111', '11/23/98', '09/13/24', '09/13/24'), + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', '01223456789','02/01/00','10/09/24', '10/09/24'); INSERT INTO local_authority (name, created_date, last_modified_date) VALUES ('Betelgeuse','09/13/24', '09/13/24'); INSERT INTO local_authority_user (subject_identifier, is_manager, local_authority_id, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:KLMNO',true, 1,'10/07/24', '10/07/24'), - ('urn:fdc:gov.uk:2022:PQRST',false, 1,'10/09/24', '10/09/24') \ No newline at end of file + ('urn:fdc:gov.uk:2022:PQRST',false, 1,'10/09/24', '10/09/24'), + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI',true,1,'10/09/24', '10/09/24'); \ No newline at end of file diff --git a/src/main/resources/db/migrations/V1_0_0__initial_user_tables.sql b/src/main/resources/db/migrations/V1_0_0__initial_user_tables.sql index 19ab771f9..d0ebeec41 100644 --- a/src/main/resources/db/migrations/V1_0_0__initial_user_tables.sql +++ b/src/main/resources/db/migrations/V1_0_0__initial_user_tables.sql @@ -23,8 +23,8 @@ CREATE TABLE local_authority_user created_date TIMESTAMPTZ(6), last_modified_date TIMESTAMPTZ(6), subject_identifier VARCHAR(255) NOT NULL UNIQUE, - is_manager BOOLEAN, - local_authority_id INT, + is_manager BOOLEAN NOT NULL, + local_authority_id INT NOT NULL, PRIMARY KEY (id) ); CREATE TABLE local_authority @@ -32,7 +32,7 @@ CREATE TABLE local_authority id INT GENERATED BY DEFAULT AS IDENTITY, created_date TIMESTAMPTZ(6), last_modified_date TIMESTAMPTZ(6), - name VARCHAR(255), + name VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); ALTER TABLE IF EXISTS landlord_user From ecbdd2c2fb5397e1f7f2dd641ac2579d86ce9fb1 Mon Sep 17 00:00:00 2001 From: JasCon Date: Thu, 10 Oct 2024 15:53:24 +0100 Subject: [PATCH 04/12] PRSD-358: Add auth tests for the ManagerLocalAuthorityUsersController --- .../webapp/controllers/ControllerTest.kt | 4 ++ ...anageLocalAuthorityUsersControllerTests.kt | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ControllerTest.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ControllerTest.kt index b74326e5a..7c0d294f7 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ControllerTest.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ControllerTest.kt @@ -11,6 +11,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.web.context.WebApplicationContext import uk.gov.communities.prsdb.webapp.config.CustomSecurityConfig import uk.gov.communities.prsdb.webapp.config.EnableMethodSecurityConfig +import uk.gov.communities.prsdb.webapp.services.LocalAuthorityDataService import uk.gov.communities.prsdb.webapp.services.UserRolesService @Import(CustomSecurityConfig::class, EnableMethodSecurityConfig::class) @@ -33,4 +34,7 @@ abstract class ControllerTest( @MockBean lateinit var userRolesService: UserRolesService + + @MockBean + lateinit var localAuthorityDataService: LocalAuthorityDataService } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt new file mode 100644 index 000000000..74ed33e68 --- /dev/null +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt @@ -0,0 +1,40 @@ +package uk.gov.communities.prsdb.webapp.controllers + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.web.servlet.get +import org.springframework.web.context.WebApplicationContext +import kotlin.test.Test + +@WebMvcTest(ManageLocalAuthorityUsersController::class) +class ManageLocalAuthorityUsersControllerTests( + @Autowired val webContext: WebApplicationContext, +) : ControllerTest(webContext) { + @Test + fun `ManageLocalAuthorityUsersController returns a redirect for unauthenticated user`() { + mvc.get("/manage-users").andExpect { + status { is3xxRedirection() } + } + } + + @Test + @WithMockUser + fun `ManageLocalAuthorityUsersController returns 403 for unauthorized user`() { + mvc + .get("/manage-users") + .andExpect { + status { isForbidden() } + } + } + + @Test + @WithMockUser(roles = ["LA_ADMIN"]) + fun `ManageLocalAuthorityUsersController returns 200 for authorized user`() { + mvc + .get("/manage-users") + .andExpect { + status { isOk() } + } + } +} From b308c02b7c328fbf8941f56bc06131b2e0889bae Mon Sep 17 00:00:00 2001 From: JasCon Date: Mon, 14 Oct 2024 10:36:44 +0100 Subject: [PATCH 05/12] PRSD-358: Added first service test --- .../LocalAuthorityDataServiceTests.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt new file mode 100644 index 000000000..aed7f9ad4 --- /dev/null +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt @@ -0,0 +1,42 @@ +package uk.gov.communities.prsdb.webapp.services + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.springframework.test.util.ReflectionTestUtils +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthority +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthorityUser +import uk.gov.communities.prsdb.webapp.database.entity.OneLoginUser +import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository + +class LocalAuthorityDataServiceTests { + private lateinit var localAuthorityUsersRepository: LocalAuthorityUserRepository + private lateinit var localAuthorityDataService: LocalAuthorityDataService + + @BeforeEach + fun setup() { + localAuthorityUsersRepository = Mockito.mock(LocalAuthorityUserRepository::class.java) + localAuthorityDataService = LocalAuthorityDataService(localAuthorityUsersRepository) + } + + @Test + fun `getLocalAuthorityUsersForLocalAuthority returns a populated list of LocalAuthorityUserDataModel`() { + // Arrange + val baseUser1 = OneLoginUser() + val localAuthorityTest = LocalAuthority() + val localAuthorityUser1 = LocalAuthorityUser() + ReflectionTestUtils.setField(localAuthorityTest, "id", 123) + ReflectionTestUtils.setField(baseUser1, "name", "Test user 1") + ReflectionTestUtils.setField(localAuthorityUser1, "isManager", true) + ReflectionTestUtils.setField(localAuthorityUser1, "baseUser", baseUser1) + ReflectionTestUtils.setField(localAuthorityUser1, "localAuthority", localAuthorityTest) + Mockito.`when`(localAuthorityUsersRepository.findByLocalAuthority_Id(123)).thenReturn(listOf(localAuthorityUser1)) + + // Act + val laUserList = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(123) + + // Assert + Assertions.assertEquals(1, laUserList.size) + } +} From 1a875694772c1ca7c9f47abe4a4eda88b7248db3 Mon Sep 17 00:00:00 2001 From: JasCon Date: Mon, 14 Oct 2024 13:56:41 +0100 Subject: [PATCH 06/12] PRSD-358: Added LocalAuthorityDataServiceTests.kt --- .../LocalAuthorityDataServiceTests.kt | 81 ++++++++++++++++--- 1 file changed, 70 insertions(+), 11 deletions(-) diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt index aed7f9ad4..d15918957 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt @@ -20,23 +20,82 @@ class LocalAuthorityDataServiceTests { localAuthorityDataService = LocalAuthorityDataService(localAuthorityUsersRepository) } + fun createOneLoginUser(username: String): OneLoginUser { + val user = OneLoginUser() + ReflectionTestUtils.setField(user, "name", username) + ReflectionTestUtils.setField(user, "id", username.lowercase().replace(" ", "-")) + return user + } + + fun createLocalAuthority(id: Int): LocalAuthority { + val localAuthority = LocalAuthority() + ReflectionTestUtils.setField(localAuthority, "id", id) + + return localAuthority + } + + fun createLocalAuthorityUser( + baseUser: OneLoginUser, + isManager: Boolean, + localAuthority: LocalAuthority, + ): LocalAuthorityUser { + val user = LocalAuthorityUser() + ReflectionTestUtils.setField(user, "baseUser", baseUser) + ReflectionTestUtils.setField(user, "isManager", isManager) + ReflectionTestUtils.setField(user, "localAuthority", localAuthority) + + return user + } + @Test fun `getLocalAuthorityUsersForLocalAuthority returns a populated list of LocalAuthorityUserDataModel`() { // Arrange - val baseUser1 = OneLoginUser() - val localAuthorityTest = LocalAuthority() - val localAuthorityUser1 = LocalAuthorityUser() - ReflectionTestUtils.setField(localAuthorityTest, "id", 123) - ReflectionTestUtils.setField(baseUser1, "name", "Test user 1") - ReflectionTestUtils.setField(localAuthorityUser1, "isManager", true) - ReflectionTestUtils.setField(localAuthorityUser1, "baseUser", baseUser1) - ReflectionTestUtils.setField(localAuthorityUser1, "localAuthority", localAuthorityTest) - Mockito.`when`(localAuthorityUsersRepository.findByLocalAuthority_Id(123)).thenReturn(listOf(localAuthorityUser1)) + val localAuthorityId = 123 + val localAuthorityTest = createLocalAuthority(localAuthorityId) + val baseUser1 = createOneLoginUser("Test user 1") + val baseUser2 = createOneLoginUser("Test user 2") + val localAuthorityUser1 = createLocalAuthorityUser(baseUser1, true, localAuthorityTest) + val localAuthorityUser2 = createLocalAuthorityUser(baseUser2, false, localAuthorityTest) + Mockito + .`when`(localAuthorityUsersRepository.findByLocalAuthority_Id(localAuthorityId)) + .thenReturn(listOf(localAuthorityUser1, localAuthorityUser2)) // Act - val laUserList = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(123) + val laUserList = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(localAuthorityId) // Assert - Assertions.assertEquals(1, laUserList.size) + Assertions.assertEquals(2, laUserList.size) + Assertions.assertEquals("Test user 1", laUserList[0].userName) + Assertions.assertEquals("Test user 2", laUserList[1].userName) + Assertions.assertEquals(true, laUserList[0].isManager) + Assertions.assertEquals(false, laUserList[1].isManager) + } + + @Test + fun `getLocalAuthorityForUser returns local authority if it exists for the user`() { + // Arrange + val localAuthority = createLocalAuthority(123) + val baseUser = createOneLoginUser("Test user 1") + val localAuthorityUser = createLocalAuthorityUser(baseUser, false, localAuthority) + Mockito + .`when`(localAuthorityUsersRepository.findByBaseUser_Id("test-user-1")) + .thenReturn(localAuthorityUser) + + // Act + val returnedLocalAuthority = localAuthorityDataService.getLocalAuthorityForUser("test-user-1") + + // Assert + Assertions.assertEquals(localAuthority, returnedLocalAuthority) + } + + @Test + fun `getLocalAuthorityForUser returns null if user is not in a local authority`() { + // Arrange + Mockito + .`when`(localAuthorityUsersRepository.findByBaseUser_Id("test-user-1")) + .thenReturn(null) + + // Act, Assert + Assertions.assertNull(localAuthorityDataService.getLocalAuthorityForUser("test-user-1")) } } From db6bb018aaaa2ffaab445aafb823fcea5c96586d Mon Sep 17 00:00:00 2001 From: JasCon Date: Mon, 14 Oct 2024 14:34:06 +0100 Subject: [PATCH 07/12] PRSD-358: Added UserRolesServiceTests and updated the landlord repository's findByBaseUser_Id to return a single user --- .../webapp/config/CustomSecurityConfig.kt | 2 +- .../repository/LandlordUserRepository.kt | 2 +- .../prsdb/webapp/services/UserRolesService.kt | 4 +- .../webapp/services/UserRolesServiceTests.kt | 88 +++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/config/CustomSecurityConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/config/CustomSecurityConfig.kt index b74a1280b..bb2dc6440 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/config/CustomSecurityConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/config/CustomSecurityConfig.kt @@ -48,7 +48,7 @@ class CustomSecurityConfig { val subjectId = oidcUser.subject val mappedAuthorities = HashSet() if (subjectId != null) { - val userRoles = userRolesService.getRolesforSubjectId(subjectId) + val userRoles = userRolesService.getRolesForSubjectId(subjectId) mappedAuthorities.addAll( userRoles.map { role -> SimpleGrantedAuthority(role) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LandlordUserRepository.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LandlordUserRepository.kt index 30f03b50e..287490b59 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LandlordUserRepository.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LandlordUserRepository.kt @@ -6,5 +6,5 @@ import uk.gov.communities.prsdb.webapp.database.entity.LandlordUser interface LandlordUserRepository : JpaRepository { // The underscore tells JPA to access fields relating to the referenced table @Suppress("ktlint:standard:function-naming") - fun findByBaseUser_Id(userName: String): List + fun findByBaseUser_Id(userName: String): LandlordUser? } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt index 5ba71b2b0..232ce4925 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt @@ -9,11 +9,11 @@ class UserRolesService( val landlordRepository: LandlordUserRepository, val localAuthorityUserRepository: LocalAuthorityUserRepository, ) { - fun getRolesforSubjectId(subjectId: String): List { + fun getRolesForSubjectId(subjectId: String): List { val roles = mutableListOf() val matchingLandlordUser = landlordRepository.findByBaseUser_Id(subjectId) - if (matchingLandlordUser.isNotEmpty()) { + if (matchingLandlordUser != null) { roles.add("ROLE_LANDLORD") } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt new file mode 100644 index 000000000..4914b45d3 --- /dev/null +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt @@ -0,0 +1,88 @@ +package uk.gov.communities.prsdb.webapp.services + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.springframework.test.util.ReflectionTestUtils +import uk.gov.communities.prsdb.webapp.database.entity.LandlordUser +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthorityUser +import uk.gov.communities.prsdb.webapp.database.entity.OneLoginUser +import uk.gov.communities.prsdb.webapp.database.repository.LandlordUserRepository +import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository + +class UserRolesServiceTests { + private lateinit var landlordRepository: LandlordUserRepository + private lateinit var localAuthorityUserRepository: LocalAuthorityUserRepository + private lateinit var userRolesService: UserRolesService + + @BeforeEach + fun setup() { + landlordRepository = Mockito.mock(LandlordUserRepository::class.java) + localAuthorityUserRepository = Mockito.mock(LocalAuthorityUserRepository::class.java) + userRolesService = UserRolesService(landlordRepository, localAuthorityUserRepository) + } + + fun createOneLoginUser(username: String): OneLoginUser { + val user = OneLoginUser() + ReflectionTestUtils.setField(user, "name", username) + ReflectionTestUtils.setField(user, "id", username.lowercase().replace(" ", "-")) + return user + } + + @Test + fun `getRolesForSubjectId returns ROLE_LANDLORD for a landlord user`() { + // Arrange + val baseUser = createOneLoginUser("Test User 1") + val user = LandlordUser() + ReflectionTestUtils.setField(user, "baseUser", baseUser) + Mockito + .`when`(landlordRepository.findByBaseUser_Id("test-user-1")) + .thenReturn(user) + + // Act + val roles = userRolesService.getRolesForSubjectId("test-user-1") + + // Assert + Assertions.assertEquals(1, roles.size) + Assertions.assertEquals("ROLE_LANDLORD", roles[0]) + } + + @Test + fun `getRolesForSubjectId returns ROLE_LA_ADMIN for a local authority manager`() { + // Arrange + val baseUser = createOneLoginUser("Test User 1") + val user = LocalAuthorityUser() + ReflectionTestUtils.setField(user, "baseUser", baseUser) + ReflectionTestUtils.setField(user, "isManager", true) + Mockito + .`when`(localAuthorityUserRepository.findByBaseUser_Id("test-user-1")) + .thenReturn(user) + + // Act + val roles = userRolesService.getRolesForSubjectId("test-user-1") + + // Assert + Assertions.assertEquals(1, roles.size) + Assertions.assertEquals("ROLE_LA_ADMIN", roles[0]) + } + + @Test + fun `getRolesForSubjectId returns ROLE_LA_USER for a standard local authority user`() { + // Arrange + val baseUser = createOneLoginUser("Test User 1") + val user = LocalAuthorityUser() + ReflectionTestUtils.setField(user, "baseUser", baseUser) + ReflectionTestUtils.setField(user, "isManager", false) + Mockito + .`when`(localAuthorityUserRepository.findByBaseUser_Id("test-user-1")) + .thenReturn(user) + + // Act + val roles = userRolesService.getRolesForSubjectId("test-user-1") + + // Assert + Assertions.assertEquals(1, roles.size) + Assertions.assertEquals("ROLE_LA_USER", roles[0]) + } +} From 3bcb7dfd403a2c13d979c7684b52674bf51ec790 Mon Sep 17 00:00:00 2001 From: JasCon Date: Mon, 14 Oct 2024 15:23:19 +0100 Subject: [PATCH 08/12] PRSD-358: Updated the readme with instructions on getting a one login user id --- ReadMe.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index fe55eefb0..6c640d6fe 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -39,6 +39,8 @@ postgres database. This takes extra time to spin up, and spins up a clean contai for integration tests that need to interact with a real database - for other tests the relevant repository beans should be mocked instead. +You can run the unit tests by running the `verification\test` task from the Gradle tab in Intellij. + ### Code structure #### Backend @@ -80,4 +82,35 @@ Database migrations run at deployment time for all non-local depl the `flywayMigrate` Gradle task. When developing locally using the `local` profile the migrations will run at application start up. If you are using the `local` launch profile in IntelliJ, this will also run the `flywayClean` task before running the migrations. After the migrations have run Spring Boot will then run the SQL in `data-local.sql` to -populate the database with seed data. \ No newline at end of file +populate the database with seed data. + +### One Login accounts +When you run the app and try to view pages, you will be prompted to sign in or create a One Login account. + +To view most pages, your account will need to have been added to the relevant database (e.g. LandlordUser, +LocalAuthorityUser) for you to be able to see the page. + +For local dev, you can add your account by modifying the `data-local.sql` file. Insert an entry into the +`one_login_user` database with a subject_identifier matching your real one login id (see below). +Then you can add entries to any other user database that you need access to (e.g. landlord_user, local_authority_user +with is_manager set to true to see local authority admin pages). + +#### Finding your One Login id +One way to find your id is: +* Inject the principle into somewhere like the start page (ExampleStartPageController.kt) +```kotlin +class ExampleStartPageController { + @GetMapping + fun index( + model: Model, + principal: Principal, + ): String { + // No need to change the contents + } +} +``` +* Run the app in debug mode, add a break point in your index function and load the page +* When you hit the debug point, your one login id should be available in `principal.name` + (it should look like `urn:fdc:gov.uk:2022:string-of-characters`) + +If anyone knows a better way to do this please add it here! \ No newline at end of file From b0ebfb5b68aa818bcb7315fed428c6e2e425c359 Mon Sep 17 00:00:00 2001 From: JasCon Date: Tue, 15 Oct 2024 10:48:29 +0100 Subject: [PATCH 09/12] PRSD-358: Added Team-PRSDB accounts and updated ReadMe.md --- ReadMe.md | 27 +++++++++++---------------- src/main/resources/data-local.sql | 12 +++++++++--- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 6c640d6fe..7373494a9 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -88,7 +88,10 @@ populate the database with seed data. When you run the app and try to view pages, you will be prompted to sign in or create a One Login account. To view most pages, your account will need to have been added to the relevant database (e.g. LandlordUser, -LocalAuthorityUser) for you to be able to see the page. +LocalAuthorityUser) for you to be able to see the page. It checks the database on login (you can step through +`getRolesforSubjectId` in `UserRolesService` to test it), so you will need to log in again to see the change in +permissions (if logging out is not yet implemented, try running in an incognito tab so you are prompted to log in +again). For local dev, you can add your account by modifying the `data-local.sql` file. Insert an entry into the `one_login_user` database with a subject_identifier matching your real one login id (see below). @@ -96,21 +99,13 @@ Then you can add entries to any other user database that you need access to (e.g with is_manager set to true to see local authority admin pages). #### Finding your One Login id -One way to find your id is: -* Inject the principle into somewhere like the start page (ExampleStartPageController.kt) -```kotlin -class ExampleStartPageController { - @GetMapping - fun index( - model: Model, - principal: Principal, - ): String { - // No need to change the contents - } -} -``` -* Run the app in debug mode, add a break point in your index function and load the page -* When you hit the debug point, your one login id should be available in `principal.name` +One way to find your id is to check the `subjectId` in `getRolesForSubjectId` in the `UserRolesService` while you are +logging in. + +* Run the app in debug mode, add a break point in `getRolesForSubjectId` +* If you are already logged in it won't hit the breakpoint. Load the app in an incognito tab so that you are prompted + to log in again. +* When you hit the debug point, your one login id should be available in `subjectId` (it should look like `urn:fdc:gov.uk:2022:string-of-characters`) If anyone knows a better way to do this please add it here! \ No newline at end of file diff --git a/src/main/resources/data-local.sql b/src/main/resources/data-local.sql index 8cef7fca9..edaff343b 100644 --- a/src/main/resources/data-local.sql +++ b/src/main/resources/data-local.sql @@ -3,12 +3,16 @@ VALUES ('urn:fdc:gov.uk:2022:ABCDE', 'Bob T Builder', 'bobthebuilder@gmail.com', ('urn:fdc:gov.uk:2022:FGHIJ', 'Anne Other', 'Anne.Other@hotmail.com', '09/13/24', '09/13/24'), ('urn:fdc:gov.uk:2022:KLMNO', 'Ford Prefect', 'Ford.Prefect@hotmail.com', '10/07/24', '10/07/24'), ('urn:fdc:gov.uk:2022:PQRST', 'Arthur Dent', 'Arthur.Dent@hotmail.com', '10/09/24', '10/09/24'), - ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', 'Jasmin Conterio', 'jasmin.conterio@softwire.com', '10/07/24', '10/07/24'); + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', 'Jasmin Conterio', 'jasmin.conterio@softwire.com', '10/07/24', '10/07/24'), + ('urn:fdc:gov.uk:2022:mGHDySEVfCsvfvc6lVWf6Qt9Dv0ZxPQWKoEzcjnBlUo','PRSDB Landlord', 'Team-PRSDB+landlord@softwire.com','10/15/24','10/15/24'), + ('urn:fdc:gov.uk:2022:n93slCXHsxJ9rU6-AFM0jFIctYQjYf0KN9YVuJT-cao','PRSDB LA Admin', 'Team-PRSDB+laadmin@softwire.com','10/15/24','10/15/24'), + ('urn:fdc:gov.uk:2022:cgVX2oJWKHMwzm8Gzx25CSoVXixVS0rw32Sar4Om8vQ','PRSDB La User', 'Team-PRSDB+lauser@softwire.com', '10/15/24', '10/15/24'); INSERT INTO landlord_user (subject_identifier, phone_number, date_of_birth, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:ABCDE', '07712345678', '01/01/00', '09/13/24', '09/13/24'), ('urn:fdc:gov.uk:2022:FGHIJ', '07811111111', '11/23/98', '09/13/24', '09/13/24'), - ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', '01223456789','02/01/00','10/09/24', '10/09/24'); + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI', '01223456789','02/01/00','10/09/24', '10/09/24'), + ('urn:fdc:gov.uk:2022:mGHDySEVfCsvfvc6lVWf6Qt9Dv0ZxPQWKoEzcjnBlUo','01223456789','03/05/00','10/15/24', '10/09/24'); INSERT INTO local_authority (name, created_date, last_modified_date) VALUES ('Betelgeuse','09/13/24', '09/13/24'); @@ -16,4 +20,6 @@ VALUES ('Betelgeuse','09/13/24', '09/13/24'); INSERT INTO local_authority_user (subject_identifier, is_manager, local_authority_id, created_date, last_modified_date) VALUES ('urn:fdc:gov.uk:2022:KLMNO',true, 1,'10/07/24', '10/07/24'), ('urn:fdc:gov.uk:2022:PQRST',false, 1,'10/09/24', '10/09/24'), - ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI',true,1,'10/09/24', '10/09/24'); \ No newline at end of file + ('urn:fdc:gov.uk:2022:07lXHJeQwE0k5PZO7w_PQF425vT8T7e63MrvyPYNSoI',true,1,'10/09/24', '10/09/24'), + ('urn:fdc:gov.uk:2022:n93slCXHsxJ9rU6-AFM0jFIctYQjYf0KN9YVuJT-cao',true,1,'10/15/24','10/15/24'), + ('urn:fdc:gov.uk:2022:cgVX2oJWKHMwzm8Gzx25CSoVXixVS0rw32Sar4Om8vQ',false,1,'10/15/24','10/15/24'); \ No newline at end of file From 1dadf9e03dc209314ff091bef631cb2964597b07 Mon Sep 17 00:00:00 2001 From: JasCon Date: Tue, 15 Oct 2024 14:31:41 +0100 Subject: [PATCH 10/12] PRSD-358: Review markups --- .../ManageLocalAuthorityUsersController.kt | 13 ++++++------- .../webapp/services/LocalAuthorityDataService.kt | 6 +----- .../prsdb/webapp/services/UserRolesService.kt | 3 +-- .../ManageLocalAuthorityUsersControllerTests.kt | 9 +++++++++ .../prsdb/webapp/services/UserRolesServiceTests.kt | 3 ++- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt index 36f197e04..5a294e65c 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt @@ -22,13 +22,12 @@ class ManageLocalAuthorityUsersController( model: Model, principal: Principal, ): String { - val currentUserLocalAuthority = localAuthorityDataService.getLocalAuthorityForUser(principal.name) - if (currentUserLocalAuthority?.id != null) { - // We should always get to here as only LA_ADMINs can access this page - val users = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(currentUserLocalAuthority.id) - val usersJson = Json.encodeToString(users) - model.addAttribute("usersJson", usersJson) - } + val currentUserLocalAuthority = localAuthorityDataService.getLocalAuthorityForUser(principal.name)!! + currentUserLocalAuthority.id!! + + val users = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(currentUserLocalAuthority.id) + val usersJson = Json.encodeToString(users) + model.addAttribute("usersJson", usersJson) model.addAttribute("contentHeader", "Manage Local Authority Users") model.addAttribute("title", "Manage Local Authority Users") diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt index 7492332cf..6c696adb1 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt @@ -16,10 +16,6 @@ class LocalAuthorityDataService( fun getLocalAuthorityForUser(subjectId: String): LocalAuthority? { val localAuthorityUser = localAuthorityUserRepository.findByBaseUser_Id(subjectId) - if (localAuthorityUser == null) { - return null - } - - return localAuthorityUser.localAuthority + return localAuthorityUser?.localAuthority } } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt index 232ce4925..0fc5befdf 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesService.kt @@ -21,9 +21,8 @@ class UserRolesService( if (matchingLocalAuthorityUser != null) { if (matchingLocalAuthorityUser.isManager) { roles.add("ROLE_LA_ADMIN") - } else { - roles.add("ROLE_LA_USER") } + roles.add("ROLE_LA_USER") } return roles diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt index 74ed33e68..a1f555950 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersControllerTests.kt @@ -1,10 +1,13 @@ package uk.gov.communities.prsdb.webapp.controllers +import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.get import org.springframework.web.context.WebApplicationContext +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthority import kotlin.test.Test @WebMvcTest(ManageLocalAuthorityUsersController::class) @@ -31,6 +34,12 @@ class ManageLocalAuthorityUsersControllerTests( @Test @WithMockUser(roles = ["LA_ADMIN"]) fun `ManageLocalAuthorityUsersController returns 200 for authorized user`() { + val localAuthority = LocalAuthority() + ReflectionTestUtils.setField(localAuthority, "id", 123) + Mockito + .`when`(localAuthorityDataService.getLocalAuthorityForUser("user")) + .thenReturn(localAuthority) + mvc .get("/manage-users") .andExpect { diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt index 4914b45d3..31d850653 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserRolesServiceTests.kt @@ -63,8 +63,9 @@ class UserRolesServiceTests { val roles = userRolesService.getRolesForSubjectId("test-user-1") // Assert - Assertions.assertEquals(1, roles.size) + Assertions.assertEquals(2, roles.size) Assertions.assertEquals("ROLE_LA_ADMIN", roles[0]) + Assertions.assertEquals("ROLE_LA_USER", roles[1]) } @Test From 504f19cf231b6e1a55309d79859127cc69483cc2 Mon Sep 17 00:00:00 2001 From: JasCon Date: Tue, 15 Oct 2024 15:45:00 +0100 Subject: [PATCH 11/12] PRSD-358: Moved data model to new folder --- .../models/{ => dataModels}/LocalAuthorityUserDataModel.kt | 2 +- .../prsdb/webapp/services/LocalAuthorityDataService.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/kotlin/uk/gov/communities/prsdb/webapp/models/{ => dataModels}/LocalAuthorityUserDataModel.kt (72%) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/LocalAuthorityUserDataModel.kt similarity index 72% rename from src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt rename to src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/LocalAuthorityUserDataModel.kt index 7606977dd..a04b9cea0 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/LocalAuthorityUserDataModel.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/LocalAuthorityUserDataModel.kt @@ -1,4 +1,4 @@ -package uk.gov.communities.prsdb.webapp.models +package uk.gov.communities.prsdb.webapp.models.dataModels import kotlinx.serialization.Serializable diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt index 6c696adb1..7a70697c8 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt @@ -3,7 +3,7 @@ package uk.gov.communities.prsdb.webapp.services import org.springframework.stereotype.Service import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthority import uk.gov.communities.prsdb.webapp.database.repository.LocalAuthorityUserRepository -import uk.gov.communities.prsdb.webapp.models.LocalAuthorityUserDataModel +import uk.gov.communities.prsdb.webapp.models.dataModels.LocalAuthorityUserDataModel @Service class LocalAuthorityDataService( From 728b9a3107a91f56433acf62cd1f6ca925416cba Mon Sep 17 00:00:00 2001 From: JasCon Date: Tue, 15 Oct 2024 17:11:05 +0100 Subject: [PATCH 12/12] PRSD-358: Made the Local Authority id private --- .../webapp/controllers/ManageLocalAuthorityUsersController.kt | 3 +-- .../prsdb/webapp/database/entity/LocalAuthority.kt | 2 +- .../database/repository/LocalAuthorityUserRepository.kt | 3 ++- .../prsdb/webapp/services/LocalAuthorityDataService.kt | 4 ++-- .../prsdb/webapp/services/LocalAuthorityDataServiceTests.kt | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt index 5a294e65c..b66c4928f 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/controllers/ManageLocalAuthorityUsersController.kt @@ -23,9 +23,8 @@ class ManageLocalAuthorityUsersController( principal: Principal, ): String { val currentUserLocalAuthority = localAuthorityDataService.getLocalAuthorityForUser(principal.name)!! - currentUserLocalAuthority.id!! - val users = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(currentUserLocalAuthority.id) + val users = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(currentUserLocalAuthority) val usersJson = Json.encodeToString(users) model.addAttribute("usersJson", usersJson) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt index b44912233..6c6453c21 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/LocalAuthority.kt @@ -10,7 +10,7 @@ import jakarta.persistence.Id class LocalAuthority : AuditableEntity() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Int? = null + private val id: Int? = null @Column(nullable = false) lateinit var name: String diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt index b4846e0eb..eb1c7d264 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/repository/LocalAuthorityUserRepository.kt @@ -1,12 +1,13 @@ package uk.gov.communities.prsdb.webapp.database.repository import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthority import uk.gov.communities.prsdb.webapp.database.entity.LocalAuthorityUser interface LocalAuthorityUserRepository : JpaRepository { // The underscore tells JPA to access fields relating to the referenced table @Suppress("ktlint:standard:function-naming") - fun findByLocalAuthority_Id(localAuthorityId: Int): List + fun findByLocalAuthority(localAuthority: LocalAuthority): List @Suppress("ktlint:standard:function-naming") fun findByBaseUser_Id(userName: String): LocalAuthorityUser? diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt index 7a70697c8..5f64acddf 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataService.kt @@ -9,8 +9,8 @@ import uk.gov.communities.prsdb.webapp.models.dataModels.LocalAuthorityUserDataM class LocalAuthorityDataService( val localAuthorityUserRepository: LocalAuthorityUserRepository, ) { - fun getLocalAuthorityUsersForLocalAuthority(localAuthorityId: Int): List { - val usersInThisLocalAuthority = localAuthorityUserRepository.findByLocalAuthority_Id(localAuthorityId) + fun getLocalAuthorityUsersForLocalAuthority(localAuthority: LocalAuthority): List { + val usersInThisLocalAuthority = localAuthorityUserRepository.findByLocalAuthority(localAuthority) return usersInThisLocalAuthority.map { LocalAuthorityUserDataModel(it.baseUser.name, it.isManager) } } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt index d15918957..4b3542da5 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LocalAuthorityDataServiceTests.kt @@ -57,11 +57,11 @@ class LocalAuthorityDataServiceTests { val localAuthorityUser1 = createLocalAuthorityUser(baseUser1, true, localAuthorityTest) val localAuthorityUser2 = createLocalAuthorityUser(baseUser2, false, localAuthorityTest) Mockito - .`when`(localAuthorityUsersRepository.findByLocalAuthority_Id(localAuthorityId)) + .`when`(localAuthorityUsersRepository.findByLocalAuthority(localAuthorityTest)) .thenReturn(listOf(localAuthorityUser1, localAuthorityUser2)) // Act - val laUserList = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(localAuthorityId) + val laUserList = localAuthorityDataService.getLocalAuthorityUsersForLocalAuthority(localAuthorityTest) // Assert Assertions.assertEquals(2, laUserList.size)