diff --git a/pom.xml b/pom.xml
index 160dea2..e0edad8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.1.3
+ 3.1.5
@@ -27,7 +27,7 @@
false
1.9.10
- 1.19.0
+ 1.19.1
@@ -176,7 +176,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.10
+ 0.8.11
before-unit-test-execution
@@ -234,7 +234,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.1.2
+ 3.2.1
false
${surefire.jacoco.args}
@@ -248,7 +248,7 @@
org.apache.maven.plugins
maven-failsafe-plugin
- 3.1.2
+ 3.2.1
${failsafe.jacoco.args}
integration
diff --git a/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt b/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt
new file mode 100644
index 0000000..39fda5e
--- /dev/null
+++ b/src/main/kotlin/no/digdir/service_catalog/controller/PublicServiceController.kt
@@ -0,0 +1,28 @@
+package no.digdir.service_catalog.controller
+
+import no.digdir.service_catalog.model.PublicService
+import no.digdir.service_catalog.security.EndpointPermissions
+import no.digdir.service_catalog.service.PublicServiceService
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import org.springframework.security.oauth2.jwt.Jwt
+import org.springframework.stereotype.Controller
+import org.springframework.web.bind.annotation.CrossOrigin
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.RequestMapping
+
+@Controller
+@CrossOrigin
+@RequestMapping(value = ["/catalogs/{catalogId}/public-services"])
+class PublicServiceController(private val publicServiceService: PublicServiceService, private val endpointPermissions: EndpointPermissions) {
+
+ @GetMapping
+ fun getAllPublicServices(@AuthenticationPrincipal jwt: Jwt, @PathVariable catalogId: String): ResponseEntity> =
+ if (endpointPermissions.hasOrgReadPermission(jwt, catalogId)) {
+ ResponseEntity(publicServiceService.findPublicServicesByCatalogId(catalogId), HttpStatus.OK)
+ } else {
+ ResponseEntity(HttpStatus.FORBIDDEN)
+ }
+}
diff --git a/src/main/kotlin/no/digdir/service_catalog/model/LocalizedStrings.kt b/src/main/kotlin/no/digdir/service_catalog/model/LocalizedStrings.kt
new file mode 100644
index 0000000..11b1659
--- /dev/null
+++ b/src/main/kotlin/no/digdir/service_catalog/model/LocalizedStrings.kt
@@ -0,0 +1,12 @@
+package no.digdir.service_catalog.model
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class LocalizedStrings(
+ val nb: String?,
+ val nn: String?,
+ val en: String?
+)
diff --git a/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt b/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt
new file mode 100644
index 0000000..b155f46
--- /dev/null
+++ b/src/main/kotlin/no/digdir/service_catalog/model/PublicService.kt
@@ -0,0 +1,18 @@
+package no.digdir.service_catalog.model
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+import org.springframework.data.mongodb.core.index.CompoundIndex
+import org.springframework.data.mongodb.core.index.CompoundIndexes
+import org.springframework.data.mongodb.core.mapping.Document
+
+@Document(collection = "publicServices")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+@CompoundIndexes(value = [CompoundIndex(name = "catalog_id", def = "{'catalogId' : 1}")])
+data class PublicService (
+ val id: String,
+ val catalogId: String,
+ val title: LocalizedStrings?,
+ val description: LocalizedStrings?
+)
diff --git a/src/main/kotlin/no/digdir/service_catalog/mongodb/PublicServiceRepository.kt b/src/main/kotlin/no/digdir/service_catalog/mongodb/PublicServiceRepository.kt
new file mode 100644
index 0000000..195e676
--- /dev/null
+++ b/src/main/kotlin/no/digdir/service_catalog/mongodb/PublicServiceRepository.kt
@@ -0,0 +1,10 @@
+package no.digdir.service_catalog.mongodb
+
+import no.digdir.service_catalog.model.PublicService
+import org.springframework.data.mongodb.repository.MongoRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface PublicServiceRepository : MongoRepository {
+ fun getByCatalogId(catalogId: String): List
+}
diff --git a/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt b/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt
new file mode 100644
index 0000000..1d6537c
--- /dev/null
+++ b/src/main/kotlin/no/digdir/service_catalog/service/PublicServiceService.kt
@@ -0,0 +1,10 @@
+package no.digdir.service_catalog.service
+
+import no.digdir.service_catalog.mongodb.PublicServiceRepository
+import org.springframework.stereotype.Service
+
+@Service
+class PublicServiceService(private val publicServiceRepository: PublicServiceRepository) {
+ fun findPublicServicesByCatalogId(catalogId: String) =
+ publicServiceRepository.getByCatalogId(catalogId)
+}
diff --git a/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt b/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt
new file mode 100644
index 0000000..ae17e30
--- /dev/null
+++ b/src/test/kotlin/no/digdir/service_catalog/integration/PublicServices.kt
@@ -0,0 +1,48 @@
+package no.digdir.service_catalog.integration
+
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import com.fasterxml.jackson.module.kotlin.readValue
+import no.digdir.service_catalog.model.PublicService
+import no.digdir.service_catalog.utils.ApiTestContext
+import no.digdir.service_catalog.utils.PUBLIC_SERVICES
+import no.digdir.service_catalog.utils.apiAuthorizedRequest
+import no.digdir.service_catalog.utils.jwt.Access
+import no.digdir.service_catalog.utils.jwt.JwtToken
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestInstance
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.HttpStatus
+import org.springframework.test.context.ContextConfiguration
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@SpringBootTest(
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.profiles.active=test"])
+@ContextConfiguration(initializers = [ApiTestContext.Initializer::class])
+@Tag("integration")
+class PublicServices: ApiTestContext() {
+ private val mapper = jacksonObjectMapper()
+
+ @Test
+ fun `able to get all public services`() {
+ val response = apiAuthorizedRequest("/catalogs/910244132/public-services", port, null, JwtToken(Access.ORG_READ).toString(), "GET")
+ Assertions.assertEquals(HttpStatus.OK.value(), response["status"])
+
+ val result: List = mapper.readValue(response["body"] as String)
+ Assertions.assertEquals(PUBLIC_SERVICES, result)
+ }
+
+ @Test
+ fun `unauthorized when missing token`() {
+ val response = apiAuthorizedRequest("/catalogs/910244132/public-services", port, null, null, "GET")
+ Assertions.assertEquals(HttpStatus.UNAUTHORIZED.value(), response["status"])
+ }
+
+ @Test
+ fun `forbidden when authorized for other catalog`() {
+ val response = apiAuthorizedRequest("/catalogs/910244132/public-services", port, null, JwtToken(Access.WRONG_ORG_READ).toString(), "GET")
+ Assertions.assertEquals(HttpStatus.FORBIDDEN.value(), response["status"])
+ }
+}
diff --git a/src/test/kotlin/no/digdir/service_catalog/utils/ApiTestContext.kt b/src/test/kotlin/no/digdir/service_catalog/utils/ApiTestContext.kt
index 4278025..85aef06 100644
--- a/src/test/kotlin/no/digdir/service_catalog/utils/ApiTestContext.kt
+++ b/src/test/kotlin/no/digdir/service_catalog/utils/ApiTestContext.kt
@@ -1,5 +1,6 @@
package no.digdir.service_catalog.utils
+import no.digdir.service_catalog.mongodb.PublicServiceRepository
import no.digdir.service_catalog.mongodb.ServiceRepository
import org.junit.jupiter.api.BeforeEach
import org.springframework.beans.factory.annotation.Autowired
@@ -18,10 +19,17 @@ abstract class ApiTestContext {
@Autowired
private lateinit var serviceRepository: ServiceRepository
+
+ @Autowired
+ private lateinit var publicServiceRepository: PublicServiceRepository
+
@BeforeEach
fun resetDatabase() {
serviceRepository.deleteAll()
serviceRepository.saveAll(SERVICES)
+
+ publicServiceRepository.deleteAll()
+ publicServiceRepository.saveAll(PUBLIC_SERVICES)
}
internal class Initializer : ApplicationContextInitializer {
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 1faa7d6..f0446e8 100644
--- a/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt
+++ b/src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt
@@ -1,5 +1,7 @@
package no.digdir.service_catalog.utils
+import no.digdir.service_catalog.model.LocalizedStrings
+import no.digdir.service_catalog.model.PublicService
import no.digdir.service_catalog.model.Service
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap
@@ -17,3 +19,14 @@ val SERVICE_0 = Service("0", "title 0")
val SERVICE_1 = Service("1", "title 1")
val SERVICES = listOf(SERVICE_0, SERVICE_1)
+
+val PUBLIC_SERVICE_0 =
+ PublicService("0", "910244132",
+ title = LocalizedStrings("Tittel 0", "Tittel 0", "Tittel 0"),
+ description = LocalizedStrings("Beskrivelse 0", "Beskriving 0", "Description 0"))
+val PUBLIC_SERVICE_1 =
+ PublicService("1", "910244132",
+ title = LocalizedStrings("Tittel 1", "Tittel 1", "Tittel 1"),
+ description = LocalizedStrings("Beskrivelse 1", "Beskriving 1", "Description 1"))
+
+val PUBLIC_SERVICES = listOf(PUBLIC_SERVICE_0, PUBLIC_SERVICE_1)