diff --git a/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt b/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt index f3776b4..51326da 100644 --- a/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt +++ b/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping @@ -71,4 +72,16 @@ class PublicServiceController(private val publicServiceService: PublicServiceSer } else { ResponseEntity(HttpStatus.FORBIDDEN) } + + @PostMapping(value = ["/{id}/publish"], produces = [MediaType.APPLICATION_JSON_VALUE]) + fun publishPublicService( + @AuthenticationPrincipal jwt: Jwt, + @PathVariable catalogId: String, + @PathVariable id: String, + ): ResponseEntity = + if (endpointPermissions.hasOrgWritePermission(jwt, catalogId)) { + ResponseEntity(publicServiceService.publishPublicService(id, catalogId), HttpStatus.OK) + } else { + ResponseEntity(HttpStatus.FORBIDDEN) + } } diff --git a/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt b/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt index b155f46..9bf2206 100644 --- a/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt +++ b/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt @@ -14,5 +14,6 @@ data class PublicService ( val id: String, val catalogId: String, val title: LocalizedStrings?, - val description: LocalizedStrings? + val description: LocalizedStrings?, + val isPublished: Boolean = false ) diff --git a/src/main/kotlin/no/digdir/service_catalog/service/JsonPatchUtils.kt b/src/main/kotlin/no/digdir/service_catalog/service/JsonPatchUtils.kt index 37289c0..33606b2 100644 --- a/src/main/kotlin/no/digdir/service_catalog/service/JsonPatchUtils.kt +++ b/src/main/kotlin/no/digdir/service_catalog/service/JsonPatchUtils.kt @@ -39,7 +39,7 @@ inline fun applyPatch(originalObject: T, operations: List) { - val invalidPaths = listOf("/id", "/catalogId") + val invalidPaths = listOf("/id", "/catalogId", "/isPublished") if (operations.any { it.path in invalidPaths }) { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Patch of paths $invalidPaths is not permitted") } diff --git a/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt b/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt index 423624e..a4ba136 100644 --- a/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt +++ b/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt @@ -1,6 +1,7 @@ package no.digdir.service_catalog.service import no.digdir.service_catalog.model.JsonPatchOperation +import no.digdir.service_catalog.model.OpEnum import no.digdir.service_catalog.model.PublicService import no.digdir.service_catalog.mongodb.PublicServiceRepository import org.slf4j.LoggerFactory @@ -40,4 +41,14 @@ class PublicServiceService(private val publicServiceRepository: PublicServiceRep logger.error("Failed to delete public service with id $id in catalog $catalogId", ex) throw ex } + + fun publishPublicService(id: String, catalogId: String): PublicService? = + try { + findPublicServiceById(id, catalogId) + ?.let { publicServiceRepository.save(it.copy(isPublished = true)) } + ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + } catch (ex: Exception) { + logger.error("Failed to publish public service with id $id in catalog $catalogId", ex) + throw ex + } } diff --git a/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt b/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt index 128475c..d6fa4a6 100644 --- a/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt +++ b/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt @@ -335,4 +335,85 @@ class PublicServices: ApiTestContext() { Assertions.assertEquals(HttpStatus.NOT_FOUND.value(), notFoundResponse["status"]) } } + + @Nested + internal inner class PublishPublicService { + val pathService1 = "/catalogs/910244132/public-services/1/publish" + @Test + fun `unauthorized when missing token` () { + val response = apiAuthorizedRequest( + pathService1, + port, + null, + null, + HttpMethod.POST) + + Assertions.assertEquals(HttpStatus.UNAUTHORIZED.value(), response["status"]) + } + + @Test + fun `forbidden when authenticated as read user` () { + val response = apiAuthorizedRequest( + pathService1, + port, + null, + JwtToken(Access.ORG_READ).toString(), + HttpMethod.POST) + + Assertions.assertEquals(HttpStatus.FORBIDDEN.value(), response["status"]) + } + + @Test + fun `not found when public service in different catalog`() { + val response = apiAuthorizedRequest( + "/catalogs/123456789/public-services/1/publish", + port, + null, + JwtToken(Access.WRONG_ORG_WRITE).toString(), + HttpMethod.POST) + Assertions.assertEquals(HttpStatus.NOT_FOUND.value(), response["status"]) + } + + @Test + fun `not found when public service not in database`() { + val response = apiAuthorizedRequest( + "/catalogs/910244132/public-services/1000/publish", + port, + null, + JwtToken(Access.ORG_WRITE).toString(), + HttpMethod.POST) + Assertions.assertEquals(HttpStatus.NOT_FOUND.value(), response["status"]) + } + + @Test + fun `able to publish public service when authenticated as a write user`() { + val response = apiAuthorizedRequest( + pathService1, + port, + null, + JwtToken(Access.ORG_WRITE).toString(), + HttpMethod.POST) + Assertions.assertEquals(HttpStatus.OK.value(), response["status"]) + + val result: PublicService = mapper.readValue(response["body"] as String) + val expected = PUBLIC_SERVICE_1.copy(isPublished = true) + Assertions.assertEquals(expected, result) + } + + @Test + fun `bad request when updating isPublished with normal patch updates`() { + val operations = listOf(JsonPatchOperation( + op = OpEnum.REPLACE, + path = "/isPublished", + value = true)) + val response = apiAuthorizedRequest( + "/catalogs/910244132/public-services/1", + port, + mapper.writeValueAsString(operations), + JwtToken(Access.ORG_WRITE).toString(), + HttpMethod.PATCH) + + Assertions.assertEquals(HttpStatus.BAD_REQUEST.value(), response["status"]) + } + } } diff --git a/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt b/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt index 165aa86..f1789f1 100644 --- a/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt +++ b/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt @@ -28,7 +28,8 @@ val PUBLIC_SERVICE_0 = val PUBLIC_SERVICE_1 = PublicService("1", "910244132", title = LocalizedStrings("NB Tittel 1", "NN Tittel 1", "EN Tittel 1"), - description = LocalizedStrings("Beskrivelse 1", "Beskriving 1", "Description 1")) + description = LocalizedStrings("Beskrivelse 1", "Beskriving 1", "Description 1"), + ) val PUBLIC_SERVICE_2 = PublicService("2", "910244132", title = LocalizedStrings("NB Tittel 2", "NN Tittel 2", "EN Tittel 2"), null)