From 8e4ece4577bb49ea0b2876192838df591a75a0e8 Mon Sep 17 00:00:00 2001 From: Niko Pitkonen <78962935+pitkni@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:28:35 +0300 Subject: [PATCH] HAI-1844: Create hankekayttaja instance for Hanke perustaja (#390) Add functionality to include Hanke perustaja in hanke kayttaja listing. A hanke generated from a cable report is a special case. In these cases perustaja is generated from the ordered person in application contacts. Additional: permission for hanke creator is now set in the service layer as the permission entity is required for token creation. --- .../haitaton/hanke/HankeControllerITests.kt | 52 ++----------- .../hel/haitaton/hanke/HankeServiceITests.kt | 30 +++++--- .../permissions/HankeKayttajaServiceITest.kt | 53 +++++++++++-- .../permissions/PermissionServiceITest.kt | 2 + .../expectedHankeWithPoints.json.mustache | 9 --- .../expectedHankeWithPolygon.json.mustache | 9 --- .../fi/hel/haitaton/hanke/HankeController.kt | 28 ++----- .../fi/hel/haitaton/hanke/HankeServiceImpl.kt | 50 +++++++++---- .../fi/hel/haitaton/hanke/PerustajaEntity.kt | 6 +- .../hanke/application/ApplicationData.kt | 3 + .../hanke/application/CustomerWithContacts.kt | 15 ++++ .../fi/hel/haitaton/hanke/domain/Hanke.kt | 4 - .../fi/hel/haitaton/hanke/domain/Perustaja.kt | 6 +- .../hanke/permissions/HankeKayttajaService.kt | 36 ++++++--- .../hanke/permissions/KayttajaTunniste.kt | 4 +- .../hanke/permissions/PermissionService.kt | 4 +- .../hel/haitaton/hanke/HankeControllerTest.kt | 52 +++++-------- .../haitaton/hanke/application/ContactTest.kt | 74 +++++++++++++++++++ .../haitaton/hanke/factory/HankeFactory.kt | 11 ++- 19 files changed, 271 insertions(+), 177 deletions(-) diff --git a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeControllerITests.kt b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeControllerITests.kt index 201e86ab2..d736170d6 100644 --- a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeControllerITests.kt +++ b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeControllerITests.kt @@ -1,6 +1,5 @@ package fi.hel.haitaton.hanke -import com.fasterxml.jackson.databind.node.ObjectNode import fi.hel.haitaton.hanke.application.ApplicationsResponse import fi.hel.haitaton.hanke.domain.HankeWithApplications import fi.hel.haitaton.hanke.domain.Hankealue @@ -8,12 +7,10 @@ import fi.hel.haitaton.hanke.factory.AlluDataFactory import fi.hel.haitaton.hanke.factory.DateFactory import fi.hel.haitaton.hanke.factory.HankeFactory import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withGeneratedOmistaja -import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withPerustaja import fi.hel.haitaton.hanke.geometria.Geometriat import fi.hel.haitaton.hanke.logging.DisclosureLogService import fi.hel.haitaton.hanke.permissions.PermissionCode import fi.hel.haitaton.hanke.permissions.PermissionService -import fi.hel.haitaton.hanke.permissions.Role import io.mockk.checkUnnecessaryStub import io.mockk.clearAllMocks import io.mockk.confirmVerified @@ -322,7 +319,6 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll createdAt = getCurrentTimeUTC(), ) every { hankeService.createHanke(any()) }.returns(createdHanke) - justRun { permissionService.setPermission(hankeId, USERNAME, Role.KAIKKI_OIKEUDET) } post(url, hankeToBeCreated) .andExpect(status().isOk) @@ -332,56 +328,24 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll verifySequence { hankeService.createHanke(any()) - permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) disclosureLogService.saveDisclosureLogsForHanke(createdHanke, USERNAME) } } - @Test - fun `When perustaja is provided return provided information`() { - val hanke = HankeFactory.create().withPerustaja() - every { hankeService.createHanke(any()) } returns hanke - justRun { permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) } - - post(url, hanke) - .andExpect(status().isOk) - .andExpect(jsonPath("$.perustaja.nimi").value("Pertti Perustaja")) - .andExpect(jsonPath("$.perustaja.email").value("foo@bar.com")) - - verifySequence { - hankeService.createHanke(any()) - permissionService.setPermission(any(), any(), any()) - disclosureLogService.saveDisclosureLogsForHanke(any(), any()) - } - } - @Test fun `Sanitize hanke input and return 200`() { val hanke = HankeFactory.create().apply { generated = true } every { hankeService.createHanke(hanke.copy(id = null, generated = false)) } returns hanke.copy(generated = false) - justRun { permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) } post(url, hanke).andExpect(status().isOk) verifySequence { hankeService.createHanke(any()) - permissionService.setPermission(any(), any(), any()) disclosureLogService.saveDisclosureLogsForHanke(any(), any()) } } - @Test - fun `With perustaja without sahkoposti returns 400`() { - val hakemus = HankeFactory.create().withPerustaja() - val content: ObjectNode = OBJECT_MAPPER.valueToTree(hakemus) - (content.get("perustaja") as ObjectNode).remove("email") - - postRaw(url, content.toJsonString()) - .andExpect(status().isBadRequest) - .andExpect(hankeError(HankeError.HAI0003)) - } - @Test fun `Add Hanke and HankeYhteystiedot and return it with newly created hankeTunnus (POST)`() { val hankeToBeMocked = @@ -393,7 +357,6 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll id = 12 omistajat[0].id = 3 } - justRun { permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) } every { hankeService.createHanke(any()) }.returns(expectedHanke) val expectedContent = expectedHanke.toJsonString() @@ -405,7 +368,6 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll verifySequence { hankeService.createHanke(any()) - permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) disclosureLogService.saveDisclosureLogsForHanke(expectedHanke, USERNAME) } } @@ -457,7 +419,6 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll expectedDateLoppu.toJsonString().substringAfter('"').substringBeforeLast('"') // faking the service call every { hankeService.createHanke(any()) }.returns(expectedHanke) - justRun { permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) } // Call it and check results post(url, hankeToBeMocked) @@ -472,7 +433,6 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll verifySequence { hankeService.createHanke(any()) - permissionService.setPermission(any(), any(), Role.KAIKKI_OIKEUDET) disclosureLogService.saveDisclosureLogsForHanke(expectedHanke, USERNAME) } } @@ -495,14 +455,14 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll @Test fun `Without permission returns 404`() { val hanke = HankeFactory.create(version = null) - every { hankeService.loadHanke(HANKE_TUNNUS) } returns hanke + every { hankeService.findHankeOrThrow(HANKE_TUNNUS) } returns hanke every { permissionService.hasPermission(hankeId, USERNAME, PermissionCode.EDIT) } .returns(false) put(url, hanke).andExpect(status().isNotFound).andExpect(hankeError(HankeError.HAI1001)) verifySequence { - hankeService.loadHanke(HANKE_TUNNUS) + hankeService.findHankeOrThrow(HANKE_TUNNUS) permissionService.hasPermission(hankeId, USERNAME, PermissionCode.EDIT) } } @@ -516,7 +476,7 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll modifiedBy = USERNAME status = HankeStatus.PUBLIC } - every { hankeService.loadHanke(HANKE_TUNNUS) } returns HankeFactory.create() + every { hankeService.findHankeOrThrow(HANKE_TUNNUS) } returns HankeFactory.create() every { permissionService.hasPermission(hankeId, USERNAME, PermissionCode.EDIT) } .returns(true) every { hankeService.updateHanke(any()) }.returns(updatedHanke) @@ -528,7 +488,7 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll .andExpect(jsonPath("$.status").value(HankeStatus.PUBLIC.name)) verifySequence { - hankeService.loadHanke(HANKE_TUNNUS) + hankeService.findHankeOrThrow(HANKE_TUNNUS) permissionService.hasPermission(hankeId, USERNAME, PermissionCode.EDIT) hankeService.updateHanke(any()) disclosureLogService.saveDisclosureLogsForHanke(updatedHanke, USERNAME) @@ -565,7 +525,7 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll expectedHanke.alueet[0].haittaAlkuPvm = expectedDateAlku expectedHanke.alueet[0].haittaLoppuPvm = expectedDateLoppu val expectedContent = expectedHanke.toJsonString() - every { hankeService.loadHanke(HANKE_TUNNUS) } returns hankeToBeUpdated + every { hankeService.findHankeOrThrow(HANKE_TUNNUS) } returns hankeToBeUpdated every { permissionService.hasPermission(expectedHanke.id!!, USERNAME, PermissionCode.EDIT) } returns true @@ -583,7 +543,7 @@ class HankeControllerITests(@Autowired override val mockMvc: MockMvc) : Controll ) // Note, here as string, not the enum. verifySequence { - hankeService.loadHanke(HANKE_TUNNUS) + hankeService.findHankeOrThrow(HANKE_TUNNUS) permissionService.hasPermission(expectedHanke.id!!, USERNAME, PermissionCode.EDIT) hankeService.updateHanke(any()) disclosureLogService.saveDisclosureLogsForHanke(expectedHanke, USERNAME) diff --git a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeServiceITests.kt b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeServiceITests.kt index 66dd6d7ba..736c3aebd 100644 --- a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeServiceITests.kt +++ b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/HankeServiceITests.kt @@ -19,7 +19,6 @@ import fi.hel.haitaton.hanke.application.CableReportWithoutHanke import fi.hel.haitaton.hanke.domain.Hanke import fi.hel.haitaton.hanke.domain.HankeYhteystieto import fi.hel.haitaton.hanke.domain.Hankealue -import fi.hel.haitaton.hanke.domain.Perustaja import fi.hel.haitaton.hanke.domain.YhteystietoTyyppi.YHTEISO import fi.hel.haitaton.hanke.domain.YhteystietoTyyppi.YKSITYISHENKILO import fi.hel.haitaton.hanke.domain.YhteystietoTyyppi.YRITYS @@ -29,7 +28,6 @@ import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withGeneratedOmistaj import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withGeneratedOmistajat import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withGeneratedRakennuttaja import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withHankealue -import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withPerustaja import fi.hel.haitaton.hanke.factory.HankeFactory.Companion.withYhteystiedot import fi.hel.haitaton.hanke.factory.HankealueFactory import fi.hel.haitaton.hanke.geometria.Geometriat @@ -41,6 +39,8 @@ import fi.hel.haitaton.hanke.logging.Status import fi.hel.haitaton.hanke.logging.UserRole import fi.hel.haitaton.hanke.permissions.HankeKayttajaRepository import fi.hel.haitaton.hanke.permissions.KayttajaTunnisteRepository +import fi.hel.haitaton.hanke.permissions.PermissionCode +import fi.hel.haitaton.hanke.permissions.PermissionService import fi.hel.haitaton.hanke.test.Asserts.isRecent import fi.hel.haitaton.hanke.test.TestUtils import fi.hel.haitaton.hanke.test.TestUtils.nextYear @@ -94,6 +94,7 @@ class HankeServiceITests : DatabaseTest() { @MockkBean private lateinit var cableReportService: CableReportService @Autowired private lateinit var hankeService: HankeService + @Autowired private lateinit var permissionService: PermissionService @Autowired private lateinit var auditLogRepository: AuditLogRepository @Autowired private lateinit var applicationRepository: ApplicationRepository @Autowired private lateinit var hankeRepository: HankeRepository @@ -114,8 +115,7 @@ class HankeServiceITests : DatabaseTest() { @Test fun `create Hanke with full data set succeeds and returns a new domain object with the correct values`() { - val hanke: Hanke = - getATestHanke().withYhteystiedot { it.id = null }.withPerustaja().withHankealue() + val hanke: Hanke = getATestHanke().withYhteystiedot { it.id = null }.withHankealue() val datetimeAlku = hanke.alueet[0].haittaAlkuPvm // nextyear.2.20 23:45:56Z val datetimeLoppu = hanke.alueet[0].haittaLoppuPvm // nextyear.2.21 0:12:34Z @@ -125,6 +125,10 @@ class HankeServiceITests : DatabaseTest() { // Call create and get the return object: val returnedHanke = hankeService.createHanke(hanke) + // Verify privileges + PermissionCode.values().forEach { + assertThat(permissionService.hasPermission(returnedHanke.id!!, USER_NAME, it)).isTrue() + } // Check the return object in general: assertThat(returnedHanke).isNotNull assertThat(returnedHanke).isNotSameAs(hanke) @@ -142,7 +146,6 @@ class HankeServiceITests : DatabaseTest() { assertThat(returnedHanke.loppuPvm).isEqualTo(expectedDateLoppu) assertThat(returnedHanke.vaihe).isEqualTo(Vaihe.SUUNNITTELU) assertThat(returnedHanke.suunnitteluVaihe).isEqualTo(SuunnitteluVaihe.RAKENNUS_TAI_TOTEUTUS) - assertThat(returnedHanke.perustaja).isEqualTo(Perustaja("Pertti Perustaja", "foo@bar.com")) assertThat(returnedHanke.tyomaaKatuosoite).isEqualTo("Testikatu 1") assertThat(returnedHanke.tyomaaTyyppi).contains(TyomaaTyyppi.VESI, TyomaaTyyppi.MUU) assertThat(returnedHanke.alueet[0].kaistaHaitta) @@ -207,6 +210,16 @@ class HankeServiceITests : DatabaseTest() { assertThat(kayttajaTunnisteRepository.findAll()).hasSize(4) } + @Test + fun `create Hanke with without perustaja and contacts does not create hanke users`() { + val hanke = hankeService.createHanke(getATestHanke()) + + val hankeEntity = hankeRepository.findByHankeTunnus(hanke.hankeTunnus!!)!! + assertThat(hankeEntity.perustaja).isNull() + assertThat(hankeKayttajaRepository.findAll()).isEmpty() + assertThat(kayttajaTunnisteRepository.findAll()).isEmpty() + } + @Test fun `create Hanke with partial data set and update with full data set give correct status`() { // Setup Hanke (without any yhteystieto): @@ -935,11 +948,13 @@ class HankeServiceITests : DatabaseTest() { with(result) { val application = applications.first() - assertThat(hanke.hankeTunnus).isEqualTo(application.hankeTunnus) assertThat(hanke.nimi).isEqualTo(application.applicationData.name) assertThat(application.applicationData.name) .isEqualTo(inputApplication.applicationData.name) + val hankePerustaja = hankeRepository.findByHankeTunnus(hanke.hankeTunnus!!)?.perustaja + assertThat(hankePerustaja?.nimi).isEqualTo("Teppo Testihenkilö") + assertThat(hankePerustaja?.email).isEqualTo("teppo@example.test") } } @@ -1378,7 +1393,6 @@ class HankeServiceITests : DatabaseTest() { TemplateData( updatedHanke.id!!, updatedHanke.hankeTunnus!!, - updatedHanke.perustaja != null, updatedHanke.alueet[0].id, updatedHanke.alueet[0].geometriat?.id, hankeVersion = 1, @@ -1504,7 +1518,6 @@ class HankeServiceITests : DatabaseTest() { data class TemplateData( val hankeId: Int, val hankeTunnus: String, - val hankePerustaja: Boolean = false, val alueId: Int? = null, val geometriaId: Int? = null, val geometriaVersion: Int = 0, @@ -1534,7 +1547,6 @@ class HankeServiceITests : DatabaseTest() { TemplateData( hanke.id!!, hanke.hankeTunnus!!, - hanke.perustaja != null, alue?.id, alue?.geometriat?.id, geometriaVersion, diff --git a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaServiceITest.kt b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaServiceITest.kt index 40909fdb1..a2bcb354b 100644 --- a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaServiceITest.kt +++ b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaServiceITest.kt @@ -47,6 +47,8 @@ class HankeKayttajaServiceITest : DatabaseTest() { @Autowired private lateinit var permissionRepository: PermissionRepository @Autowired private lateinit var roleRepository: RoleRepository + private val perustaja = HankeFactory.defaultPerustaja + @Test fun `getKayttajatByHankeId should return users from correct hanke only`() { val hankeToFind = hankeFactory.save(HankeFactory.create().withYhteystiedot()) @@ -76,6 +78,25 @@ class HankeKayttajaServiceITest : DatabaseTest() { } } + @Test + fun `addHankeFounder saves kayttaja with correct permission and other data`() { + val hankeEntity = hankeFactory.saveEntity() + val savedHankeId = hankeEntity.id!! + val savedPermission = savePermission(savedHankeId, USERNAME, Role.KAIKKI_OIKEUDET) + + hankeKayttajaService.addHankeFounder(savedHankeId, perustaja, savedPermission) + + val kayttajaEntity = + hankeKayttajaRepository.findAll().also { assertThat(it).hasSize(1) }.first() + with(kayttajaEntity) { + assertThat(id).isNotNull() + assertThat(hankeId).isEqualTo(savedHankeId) + assertThat(permission!!).isOfEqualDataTo(savedPermission) + assertThat(sahkoposti).isEqualTo(perustaja.email) + assertThat(nimi).isEqualTo(perustaja.nimi) + } + } + @Test fun `saveNewTokensFromApplication does nothing if application has no contacts`() { val hanke = hankeFactory.saveEntity() @@ -339,6 +360,20 @@ class HankeKayttajaServiceITest : DatabaseTest() { k.transform { it.kayttajaTunniste }.isNotNull() } + private fun Assert.isOfEqualDataTo(other: PermissionEntity) = + given { actual -> + assertThat(actual.id).isEqualTo(other.id) + assertThat(actual.hankeId).isEqualTo(other.hankeId) + assertThat(actual.userId).isEqualTo(other.userId) + assertThat(actual.role).isOfEqualDataTo(other.role) + } + + private fun Assert.isOfEqualDataTo(other: RoleEntity) = given { actual -> + assertThat(actual.id).isEqualTo(other.id) + assertThat(actual.role).isEqualTo(other.role) + assertThat(actual.permissionCode).isEqualTo(other.permissionCode) + } + private val expectedNames = arrayOf( "yhteys-etu1 yhteys-suku1", @@ -386,14 +421,7 @@ class HankeKayttajaServiceITest : DatabaseTest() { nimi: String, sahkoposti: String ): HankeKayttajaEntity { - val permissionEntity = - permissionRepository.save( - PermissionEntity( - userId = "fake id", - hankeId = hankeId, - role = roleRepository.findOneByRole(Role.KATSELUOIKEUS), - ) - ) + val permissionEntity = savePermission(hankeId, "fake id", Role.KATSELUOIKEUS) return hankeKayttajaRepository.save( HankeKayttajaEntity( @@ -405,4 +433,13 @@ class HankeKayttajaServiceITest : DatabaseTest() { ) ) } + + private fun savePermission(hankeId: Int, userId: String, role: Role) = + permissionRepository.save( + PermissionEntity( + userId = userId, + hankeId = hankeId, + role = roleRepository.findOneByRole(role) + ) + ) } diff --git a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/PermissionServiceITest.kt b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/PermissionServiceITest.kt index f97d62b1e..e5070ff5e 100644 --- a/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/PermissionServiceITest.kt +++ b/services/hanke-service/src/integrationTest/kotlin/fi/hel/haitaton/hanke/permissions/PermissionServiceITest.kt @@ -166,6 +166,7 @@ class PermissionServiceITest : DatabaseTest() { @Test fun `setPermission creates a new permission`() { val hankeId = saveSeveralHanke(1)[0].id!! + permissionRepository.deleteAll() // remove permission created in hanke creation permissionService.setPermission(hankeId, username, Role.KATSELUOIKEUS) @@ -178,6 +179,7 @@ class PermissionServiceITest : DatabaseTest() { @Test fun `setPermission updates an existing permission`() { val hankeId = saveSeveralHanke(1)[0].id!! + permissionRepository.deleteAll() // remove permission created in hanke creation val role = roleRepository.findOneByRole(Role.KATSELUOIKEUS) permissionRepository.save( PermissionEntity(userId = username, hankeId = hankeId, role = role) diff --git a/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPoints.json.mustache b/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPoints.json.mustache index 631805893..eeb5e304a 100644 --- a/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPoints.json.mustache +++ b/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPoints.json.mustache @@ -22,15 +22,6 @@ "version": {{hankeVersion}}, "generated": false, "tyomaaKatuosoite": "Testikatu 1", - {{#hankkeenPerustaja}} - "perustaja": { - "nimi": "Pertti Perustaja", - "sahkoposti": "foo@bar.com" - }, - {{/hankkeenPerustaja}} - {{^hankkeenPerustaja}} - "perustaja": null, - {{/hankkeenPerustaja}} "tyomaaTyyppi": [ "MUU", "VESI" diff --git a/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPolygon.json.mustache b/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPolygon.json.mustache index 452f886fa..e44c3a772 100644 --- a/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPolygon.json.mustache +++ b/services/hanke-service/src/integrationTest/resources/fi/hel/haitaton/hanke/logging/expectedHankeWithPolygon.json.mustache @@ -22,15 +22,6 @@ "version": {{hankeVersion}}, "generated": false, "tyomaaKatuosoite": "Testikatu 1", - {{#hankkeenPerustaja}} - "perustaja": { - "nimi": "Pertti Perustaja", - "sahkoposti": "foo@bar.com" - }, - {{/hankkeenPerustaja}} - {{^hankkeenPerustaja}} - "perustaja": null, - {{/hankkeenPerustaja}} "tyomaaTyyppi": [ "MUU", "VESI" diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeController.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeController.kt index 581859622..804786851 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeController.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeController.kt @@ -7,7 +7,6 @@ import fi.hel.haitaton.hanke.domain.Hanke import fi.hel.haitaton.hanke.logging.DisclosureLogService import fi.hel.haitaton.hanke.permissions.PermissionCode import fi.hel.haitaton.hanke.permissions.PermissionService -import fi.hel.haitaton.hanke.permissions.Role import fi.hel.haitaton.hanke.validation.ValidHanke import io.swagger.v3.oas.annotations.Hidden import io.swagger.v3.oas.annotations.Operation @@ -188,11 +187,6 @@ class HankeController( val createdHanke = hankeService.createHanke(sanitizedHanke) - permissionService.setPermission( - createdHanke.id!!, - currentUserId(), - Role.KAIKKI_OIKEUDET, - ) disclosureLogService.saveDisclosureLogsForHanke(createdHanke, userId) return createdHanke } @@ -240,14 +234,9 @@ class HankeController( featureFlags.ensureEnabled(Feature.HANKE_EDITING) logger.info { "Updating Hanke: ${hanke.toLogString()}" } - - val existingHanke = - hankeService.loadHanke(hankeTunnus)?.also { - it.verifyUserAuthorization(currentUserId(), PermissionCode.EDIT) - } - ?: throw HankeNotFoundException(hankeTunnus) - - existingHanke.validateUpdatable(hanke, hankeTunnus) + val existingHanke = hankeService.findHankeOrThrow(hankeTunnus) + existingHanke.verifyUserAuthorization(currentUserId(), PermissionCode.EDIT) + validateUpdatable(hanke, hankeTunnus) val updatedHanke = hankeService.updateHanke(hanke) logger.info { "Updated hanke ${updatedHanke.hankeTunnus}." } @@ -315,12 +304,11 @@ class HankeController( } } - private fun Hanke.validateUpdatable(updatedHanke: Hanke, hankeTunnusFromPath: String) { - if (hankeTunnusFromPath != updatedHanke.hankeTunnus) { - throw HankeArgumentException("Hanketunnus not given or doesn't match the hanke data") - } - if (perustaja != null && perustaja != updatedHanke.perustaja) { - throw HankeArgumentException("Updating perustaja not allowed.") + private fun validateUpdatable(hankeUpdate: Hanke, hankeTunnusFromPath: String) { + if (hankeUpdate.hankeTunnus != hankeTunnusFromPath) { + throw HankeArgumentException( + "Hanketunnus mismatch. (In payload=${hankeUpdate.hankeTunnus}, In path=$hankeTunnusFromPath)" + ) } } } diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeServiceImpl.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeServiceImpl.kt index dd1dcca77..0304d2208 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeServiceImpl.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/HankeServiceImpl.kt @@ -6,13 +6,15 @@ import fi.hel.haitaton.hanke.ContactType.RAKENNUTTAJA import fi.hel.haitaton.hanke.ContactType.TOTEUTTAJA import fi.hel.haitaton.hanke.application.Application import fi.hel.haitaton.hanke.application.ApplicationService +import fi.hel.haitaton.hanke.application.CableReportApplicationData import fi.hel.haitaton.hanke.application.CableReportWithoutHanke +import fi.hel.haitaton.hanke.application.Contact import fi.hel.haitaton.hanke.domain.Hanke import fi.hel.haitaton.hanke.domain.HankeWithApplications import fi.hel.haitaton.hanke.domain.HankeYhteystieto import fi.hel.haitaton.hanke.domain.Hankealue import fi.hel.haitaton.hanke.domain.HasId -import fi.hel.haitaton.hanke.domain.toEntity +import fi.hel.haitaton.hanke.domain.Perustaja import fi.hel.haitaton.hanke.geometria.GeometriatService import fi.hel.haitaton.hanke.logging.AuditLogService import fi.hel.haitaton.hanke.logging.HankeLoggingService @@ -111,11 +113,11 @@ open class HankeServiceImpl( override fun loadHankkeetByIds(ids: List) = hankeRepository.findAllById(ids).map { createHankeDomainObjectFromEntity(it) } - /** @return a new Hanke instance with the added and possibly modified values. */ @Transactional - override fun createHanke(hanke: Hanke): Hanke { - // TODO: Only create that hanke-tunnus if a specific set of fields are non-empty/set. + override fun createHanke(hanke: Hanke): Hanke = + createHankeInternal(hanke = hanke, perustaja = null) + private fun createHankeInternal(hanke: Hanke, perustaja: Perustaja?): Hanke { val userId = currentUserId() val entity = HankeEntity() @@ -126,6 +128,8 @@ open class HankeServiceImpl( entity.hankeTunnus = hanketunnus hanke.hankeTunnus = hanketunnus + entity.perustaja = perustaja?.toEntity() + // Copy values from the incoming domain object, and set some internal fields: copyNonNullHankeFieldsToEntity(hanke, entity) @@ -151,8 +155,8 @@ open class HankeServiceImpl( postProcessAndSaveLogging(loggingEntryHolder, savedHankeEntity, userId) - return createHankeDomainObjectFromEntity(entity).also { - hankeKayttajaService.saveNewTokensFromHanke(it) + return createHankeDomainObjectFromEntity(savedHankeEntity).also { + initAccessForCreatedHanke(it, perustaja, userId) hankeLoggingService.logCreate(it, userId) } } @@ -169,7 +173,6 @@ open class HankeServiceImpl( val tunnus = hanke.hankeTunnus ?: throw HankeArgumentException("Hanke must have tunnus") val createdApplication = applicationService.create(cableReport.toNewApplication(tunnus), userId) - permissionService.setPermission(hanke.id!!, userId, Role.KAIKKI_OIKEUDET) return HankeWithApplications(hanke, listOf(createdApplication)) } @@ -241,6 +244,13 @@ open class HankeServiceImpl( !applicationService.isStillPending(it) } + private fun initAccessForCreatedHanke(hanke: Hanke, perustaja: Perustaja?, userId: String) { + val hankeId = hanke.id!! + val permissionAll = permissionService.setPermission(hankeId, userId, Role.KAIKKI_OIKEUDET) + perustaja?.let { hankeKayttajaService.addHankeFounder(hankeId, it, permissionAll) } + hankeKayttajaService.saveNewTokensFromHanke(hanke) + } + // TODO: functions to remove and invalidate Hanke's tormaystarkastelu-data // At least invalidation can be done purely working on the particular // tormaystarkasteluTulosEntity and -Repository. @@ -335,7 +345,6 @@ open class HankeServiceImpl( if (hankeEntity.modifiedAt != null) ZonedDateTime.of(hankeEntity.modifiedAt, TZ_UTC) else null, hankeEntity.status, - hankeEntity.perustaja?.toDomainObject(), hankeEntity.generated, ) @@ -561,8 +570,6 @@ open class HankeServiceImpl( hanke.onYKTHanke?.let { entity.onYKTHanke = hanke.onYKTHanke } hanke.nimi?.let { entity.nimi = hanke.nimi } hanke.kuvaus?.let { entity.kuvaus = hanke.kuvaus } - - hanke.perustaja?.let { entity.perustaja = it.toEntity() } entity.generated = hanke.generated hanke.vaihe?.let { entity.vaihe = hanke.vaihe } hanke.suunnitteluVaihe?.let { entity.suunnitteluVaihe = hanke.suunnitteluVaihe } @@ -927,9 +934,14 @@ open class HankeServiceImpl( loggingEntryHolder.saveLogEntries(auditLogService) } - /** Autogenerated hanke based on application data. Generated flag true. */ + /** + * Autogenerated hanke based on application data. + * - Generated flag true. + * - Hanke name is same as application name. + * - Perustaja generated from application data orderer. + */ private fun generateHankeFrom(cableReport: CableReportWithoutHanke): Hanke = - createHanke( + createHankeInternal( Hanke( id = null, hankeTunnus = null, @@ -943,9 +955,17 @@ open class HankeServiceImpl( createdAt = null, modifiedBy = null, modifiedAt = null, - HankeStatus.DRAFT, - perustaja = null, + status = HankeStatus.DRAFT, generated = true, - ) + ), + perustaja = generatePerustajaFrom(cableReport.applicationData), ) + + private fun generatePerustajaFrom(cableReport: CableReportApplicationData): Perustaja { + val orderer: Contact = + cableReport.findOrderer() + ?: throw HankeArgumentException("Orderer not found for Hanke perustaja") + + return orderer.toHankePerustaja() + } } diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/PerustajaEntity.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/PerustajaEntity.kt index daf45d301..fe41bf274 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/PerustajaEntity.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/PerustajaEntity.kt @@ -8,6 +8,6 @@ import jakarta.persistence.Embeddable data class PerustajaEntity( @Column(name = "perustajanimi") var nimi: String?, @Column(name = "perustajaemail") var email: String -) - -fun PerustajaEntity.toDomainObject(): Perustaja = Perustaja(nimi, email) +) { + fun toDomainObject(): Perustaja = Perustaja(nimi, email) +} diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/ApplicationData.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/ApplicationData.kt index 578eb9b71..db72b7506 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/ApplicationData.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/ApplicationData.kt @@ -76,6 +76,9 @@ data class CableReportApplicationData( propertyDeveloperWithContacts, representativeWithContacts ) + + fun findOrderer(): Contact? = + customersWithContacts().flatMap { it.contacts }.find { it.orderer } } class AlluDataException(path: String, error: AlluDataError) : diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/CustomerWithContacts.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/CustomerWithContacts.kt index 1e250815a..98ebf6a43 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/CustomerWithContacts.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/application/CustomerWithContacts.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonView import fi.hel.haitaton.hanke.ChangeLogView +import fi.hel.haitaton.hanke.HankeArgumentException import fi.hel.haitaton.hanke.allu.Contact as AlluContact import fi.hel.haitaton.hanke.allu.Customer as AlluCustomer import fi.hel.haitaton.hanke.allu.CustomerType @@ -11,6 +12,7 @@ import fi.hel.haitaton.hanke.allu.CustomerWithContacts as AlluCustomerWithContac import fi.hel.haitaton.hanke.allu.PostalAddress as AlluPostalAddress import fi.hel.haitaton.hanke.allu.StreetAddress as AlluStreetAddress import fi.hel.haitaton.hanke.domain.BusinessId +import fi.hel.haitaton.hanke.domain.Perustaja @JsonIgnoreProperties(ignoreUnknown = true) data class CustomerWithContacts(val customer: Customer, val contacts: List) { @@ -44,6 +46,19 @@ data class Contact( } return names.filter { !it.isNullOrBlank() }.joinToString(" ") } + + /** + * It is possible to create a cable report without an existing Hanke. In these cases an + * application contact (orderer) is used as Hanke perustaja. + */ + fun toHankePerustaja(): Perustaja { + val name = fullName() + if (name.isNullOrBlank() || email.isNullOrBlank()) { + throw HankeArgumentException("Invalid orderer $this for Hanke perustaja") + } + + return Perustaja(name, email) + } } @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Hanke.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Hanke.kt index b9b78a062..dce4cb99f 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Hanke.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Hanke.kt @@ -79,10 +79,6 @@ data class Hanke( var status: HankeStatus? = HankeStatus.DRAFT, // @JsonView(ChangeLogView::class) - @field:Schema(description = "Hanke founder contact information") - var perustaja: Perustaja? = null, - // - @JsonView(ChangeLogView::class) @field:Schema(description = "Indicates whether the Hanke data is generated, set by the service") var generated: Boolean = false, ) : HasId { diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Perustaja.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Perustaja.kt index f1a47608c..a2c73ef4b 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Perustaja.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/domain/Perustaja.kt @@ -7,6 +7,6 @@ import io.swagger.v3.oas.annotations.media.Schema data class Perustaja( @field:Schema(description = "Name") val nimi: String?, @field:Schema(description = "Email address") val email: String -) - -fun Perustaja.toEntity(): PerustajaEntity = PerustajaEntity(nimi, email) +) { + fun toEntity(): PerustajaEntity = PerustajaEntity(nimi, email) +} diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaService.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaService.kt index 3f4b5f4b6..1576604a3 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaService.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/HankeKayttajaService.kt @@ -3,6 +3,7 @@ package fi.hel.haitaton.hanke.permissions import fi.hel.haitaton.hanke.HankeArgumentException import fi.hel.haitaton.hanke.application.ApplicationEntity import fi.hel.haitaton.hanke.domain.Hanke +import fi.hel.haitaton.hanke.domain.Perustaja import mu.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -48,22 +49,39 @@ class HankeKayttajaService( filterNewContacts(hankeId, contacts).forEach { contact -> createToken(hankeId, contact) } } + @Transactional + fun addHankeFounder(hankeId: Int, founder: Perustaja, permissionEntity: PermissionEntity) { + logger.info { "Saving user for Hanke perustaja." } + saveUser( + HankeKayttajaEntity( + hankeId = hankeId, + nimi = founder.nimi!!, + sahkoposti = founder.email, + permission = permissionEntity, + kayttajaTunniste = null, + ) + ) + } + private fun createToken(hankeId: Int, contact: UserContact) { logger.info { "Creating a new user token, hankeId=$hankeId" } val token = KayttajaTunnisteEntity.create() val kayttajaTunnisteEntity = kayttajaTunnisteRepository.save(token) logger.info { "Saved the new user token, id=${kayttajaTunnisteEntity.id}" } - val user = - hankeKayttajaRepository.save( - HankeKayttajaEntity( - hankeId = hankeId, - nimi = contact.name, - sahkoposti = contact.email, - permission = null, - kayttajaTunniste = kayttajaTunnisteEntity - ) + saveUser( + HankeKayttajaEntity( + hankeId = hankeId, + nimi = contact.name, + sahkoposti = contact.email, + permission = null, + kayttajaTunniste = kayttajaTunnisteEntity ) + ) + } + + private fun saveUser(hankeKayttajaEntity: HankeKayttajaEntity) { + val user = hankeKayttajaRepository.save(hankeKayttajaEntity) logger.info { "Saved the user information, id=${user.id}" } } diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/KayttajaTunniste.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/KayttajaTunniste.kt index c9513d5da..2ffb43d32 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/KayttajaTunniste.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/KayttajaTunniste.kt @@ -31,12 +31,12 @@ class KayttajaTunnisteEntity( private val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') private val secureRandom: SecureRandom = SecureRandom() - fun create() = + fun create(role: Role = Role.KATSELUOIKEUS) = KayttajaTunnisteEntity( tunniste = randomToken(), createdAt = getCurrentTimeUTC().toOffsetDateTime(), sentAt = null, - role = Role.KATSELUOIKEUS, + role = role, hankeKayttaja = null ) diff --git a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/PermissionService.kt b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/PermissionService.kt index 677cef467..1ede300db 100644 --- a/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/PermissionService.kt +++ b/services/hanke-service/src/main/kotlin/fi/hel/haitaton/hanke/permissions/PermissionService.kt @@ -19,14 +19,14 @@ class PermissionService( return hasPermission(role, permission) } - fun setPermission(hankeId: Int, userId: String, role: Role) { + fun setPermission(hankeId: Int, userId: String, role: Role): PermissionEntity { val roleEntity = roleRepository.findOneByRole(role) val entity = permissionRepository.findOneByHankeIdAndUserId(hankeId, userId)?.apply { this.role = roleEntity } ?: PermissionEntity(userId = userId, hankeId = hankeId, role = roleEntity) - permissionRepository.save(entity) + return permissionRepository.save(entity) } fun verifyHankeUserAuthorization(userId: String, hanke: Hanke, permissionCode: PermissionCode) { diff --git a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/HankeControllerTest.kt b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/HankeControllerTest.kt index 63f28020a..3a1051144 100644 --- a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/HankeControllerTest.kt +++ b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/HankeControllerTest.kt @@ -9,7 +9,6 @@ import fi.hel.haitaton.hanke.factory.HankeFactory import fi.hel.haitaton.hanke.logging.DisclosureLogService import fi.hel.haitaton.hanke.permissions.PermissionCode import fi.hel.haitaton.hanke.permissions.PermissionService -import fi.hel.haitaton.hanke.permissions.Role import io.mockk.Called import io.mockk.clearAllMocks import io.mockk.mockk @@ -176,7 +175,7 @@ class HankeControllerTest { // mock HankeService response Mockito.`when`(hankeService.updateHanke(partialHanke)) .thenReturn(partialHanke.copy(modifiedBy = username, modifiedAt = getCurrentTimeUTC())) - Mockito.`when`(hankeService.loadHanke("id123")) + Mockito.`when`(hankeService.findHankeOrThrow("id123")) .thenReturn(HankeFactory.create(hankeTunnus = "id123")) Mockito.`when`(permissionService.hasPermission(123, username, PermissionCode.EDIT)) .thenReturn(true) @@ -189,6 +188,23 @@ class HankeControllerTest { verify { disclosureLogService.saveDisclosureLogsForHanke(any(), eq(username)) } } + @Test + fun `test that the updateHanke will throw if mismatch in hanke tunnus payload vs path`() { + val hankeUpdate = HankeFactory.create() + val existingHanke = HankeFactory.create(hankeTunnus = "wrong") + Mockito.`when`(hankeService.findHankeOrThrow("wrong")).thenReturn(existingHanke) + Mockito.`when`( + permissionService.hasPermission(existingHanke.id!!, username, PermissionCode.EDIT) + ) + .thenReturn(true) + + assertThatExceptionOfType(HankeArgumentException::class.java) + .isThrownBy { hankeController.updateHanke(hankeUpdate, "wrong") } + .withMessageContaining( + "Hanketunnus mismatch. (In payload=${hankeUpdate.hankeTunnus}, In path=wrong)" + ) + } + @Test fun `test that the updateHanke will give validation errors from invalid hanke data for name`() { val partialHanke = @@ -313,36 +329,4 @@ class HankeControllerTest { verify { disclosureLogService wasNot Called } } - - @Test - fun `test that creating a Hanke also adds owner permissions for creating user`() { - val hanke = - Hanke( - id = null, - hankeTunnus = null, - nimi = "hankkeen nimi", - kuvaus = "lorem ipsum dolor sit amet...", - onYKTHanke = false, - vaihe = Vaihe.OHJELMOINTI, - suunnitteluVaihe = null, - version = 1, - createdBy = "Tiina", - createdAt = getCurrentTimeUTC(), - modifiedBy = null, - modifiedAt = null, - status = HankeStatus.DRAFT - ) - - val mockedHanke = hanke.copy() - mockedHanke.id = 12 - mockedHanke.hankeTunnus = "JOKU12" - - Mockito.`when`(hankeService.createHanke(hanke)).thenReturn(mockedHanke) - - val response: Hanke = hankeController.createHanke(hanke) - - assertThat(response).isNotNull - Mockito.verify(permissionService).setPermission(12, username, Role.KAIKKI_OIKEUDET) - verify { disclosureLogService.saveDisclosureLogsForHanke(any(), eq(username)) } - } } diff --git a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/application/ContactTest.kt b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/application/ContactTest.kt index cd1c3dbce..bbdd15076 100644 --- a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/application/ContactTest.kt +++ b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/application/ContactTest.kt @@ -1,11 +1,19 @@ package fi.hel.haitaton.hanke.application import assertk.assertThat +import assertk.assertions.hasSize import assertk.assertions.isEqualTo import assertk.assertions.isNull +import fi.hel.haitaton.hanke.HankeArgumentException +import fi.hel.haitaton.hanke.factory.AlluDataFactory +import fi.hel.haitaton.hanke.factory.AlluDataFactory.Companion.createContact +import fi.hel.haitaton.hanke.factory.AlluDataFactory.Companion.withContacts +import java.util.stream.Stream import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource +import org.junit.jupiter.params.provider.MethodSource private const val DUMMY_EMAIL = "dummymail@mail.com" private const val DUMMY_PHONE = "04012345678" @@ -48,4 +56,70 @@ class ContactTest { Contact(firstName = null, lastName = null, email = DUMMY_EMAIL, phone = DUMMY_PHONE) assertThat(contact.fullName()).isNull() } + + @Test + fun `findOrderer when orderer contact exists should return it`() { + val applicationData = + AlluDataFactory.createCableReportApplicationData( + representativeWithContacts = + AlluDataFactory.createCompanyCustomer().withContacts(createContact()), + propertyDeveloperWithContacts = + AlluDataFactory.createCompanyCustomer().withContacts(createContact()), + ) + + val result = applicationData.findOrderer() + + val allContacts = applicationData.customersWithContacts().flatMap { it.contacts } + assertThat(allContacts).hasSize(4) + val expectedResult = + Contact( + firstName = "Teppo", + lastName = "Testihenkilö", + email = "teppo@example.test", + phone = "04012345678", + orderer = true, + ) + assertThat(result).isEqualTo(expectedResult) + } + + @Test + fun `findOrderer when no orderer contact exists should return null`() { + val applicationData = + AlluDataFactory.createCableReportApplicationData( + customerWithContacts = + AlluDataFactory.createCompanyCustomer().withContacts(createContact()) + ) + + val result = applicationData.findOrderer() + + val allContacts = applicationData.customersWithContacts().flatMap { it.contacts } + assertThat(allContacts).hasSize(2) + assertThat(result).isNull() + } + + @ParameterizedTest + @MethodSource("invalidContacts") + fun `toHankePerustaja when invalid contact input should throw`(contact: Contact) { + assertThrows { contact.toHankePerustaja() } + } + + companion object { + @JvmStatic + fun invalidContacts(): Stream { + val contact = + Contact( + firstName = "Firstname", + lastName = "Lastname", + email = "test@email.com", + phone = "04012345678", + orderer = true + ) + return Stream.of( + contact.copy(firstName = null, lastName = null), + contact.copy(firstName = "", lastName = ""), + contact.copy(email = null), + contact.copy(email = "") + ) + } + } } diff --git a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/factory/HankeFactory.kt b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/factory/HankeFactory.kt index 788499894..606e61e1d 100644 --- a/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/factory/HankeFactory.kt +++ b/services/hanke-service/src/test/kotlin/fi/hel/haitaton/hanke/factory/HankeFactory.kt @@ -62,6 +62,7 @@ class HankeFactory( const val defaultNimi = "Hämeentien perusparannus ja katuvalot" const val defaultId = 123 const val defaultUser = "Risto" + val defaultPerustaja = Perustaja("Pertti Perustaja", "foo@bar.com") /** * Create a simple Hanke with test values. The default values can be overridden with named @@ -99,6 +100,12 @@ class HankeFactory( hankeStatus, ) + /** Create minimal Entity with identifier fields and mandatory fields. */ + fun createMinimalEntity( + id: Int? = defaultId, + hankeTunnus: String? = defaultHankeTunnus, + ) = HankeEntity(id = id, hankeTunnus = hankeTunnus) + /** * Add a hankealue with haitat to a test Hanke. * @@ -176,10 +183,6 @@ class HankeFactory( return this } - fun Hanke.withPerustaja( - newPerustaja: Perustaja? = Perustaja("Pertti Perustaja", "foo@bar.com") - ): Hanke = apply { perustaja = newPerustaja } - /** * Add a number of omistaja to a hanke. Generates the yhteystiedot with * [HankeYhteystietoFactory.createDifferentiated] using the given ints for differentiating