Skip to content

Commit

Permalink
feat: add create method for public service (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
hegeaal authored Nov 13, 2023
1 parent b2fc532 commit f24086c
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package no.digdir.service_catalog.controller

import no.digdir.service_catalog.model.JsonPatchOperation
import no.digdir.service_catalog.model.PublicService
import no.digdir.service_catalog.model.*
import no.digdir.service_catalog.security.EndpointPermissions
import no.digdir.service_catalog.service.PublicServiceService
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
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.*
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
Expand Down Expand Up @@ -73,6 +74,20 @@ class PublicServiceController(private val publicServiceService: PublicServiceSer
ResponseEntity(HttpStatus.FORBIDDEN)
}

@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
fun createPublicService(
@AuthenticationPrincipal jwt: Jwt,
@PathVariable catalogId: String,
@RequestBody publicServiceToBeCreated: PublicServiceToBeCreated
): ResponseEntity<HttpStatus> =
if (endpointPermissions.hasOrgWritePermission(jwt, catalogId)) {
val created = publicServiceService.createPublicService(catalogId, publicServiceToBeCreated)
ResponseEntity(
locationHeaderForCreated(newId = created.id, catalogId),
HttpStatus.CREATED
)
} else ResponseEntity<HttpStatus>(HttpStatus.FORBIDDEN)

@PostMapping(value = ["/{id}/publish"], produces = [MediaType.APPLICATION_JSON_VALUE])
fun publishPublicService(
@AuthenticationPrincipal jwt: Jwt,
Expand All @@ -85,3 +100,9 @@ class PublicServiceController(private val publicServiceService: PublicServiceSer
ResponseEntity(HttpStatus.FORBIDDEN)
}
}

private fun locationHeaderForCreated(newId: String, catalogId: String): HttpHeaders =
HttpHeaders().apply {
add(HttpHeaders.LOCATION, "/$catalogId/catalogs/{catalogId}/public-services/$newId")
add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.LOCATION)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ data class PublicService (
val description: LocalizedStrings?,
val isPublished: Boolean = false
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class PublicServiceToBeCreated(
val title: LocalizedStrings?,
val description: LocalizedStrings?
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ 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.model.PublicServiceToBeCreated
import no.digdir.service_catalog.mongodb.PublicServiceRepository
import org.slf4j.LoggerFactory
import org.springframework.data.repository.findByIdOrNull
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
import java.util.*

@Service
class PublicServiceService(private val publicServiceRepository: PublicServiceRepository) {
Expand Down Expand Up @@ -42,6 +44,19 @@ class PublicServiceService(private val publicServiceRepository: PublicServiceRep
throw ex
}

fun createPublicService(catalogId: String, publicServiceToBeCreated: PublicServiceToBeCreated): PublicService =
try {
PublicService(
id = UUID.randomUUID().toString(),
catalogId = catalogId,
title = publicServiceToBeCreated.title,
description = publicServiceToBeCreated.description
).let { publicServiceRepository.insert(it) }
} catch (ex: Exception) {
logger.error("Failed to create public service for $catalogId", ex)
throw ex
}

fun publishPublicService(id: String, catalogId: String): PublicService? =
try {
findPublicServiceById(id, catalogId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import no.digdir.service_catalog.model.JsonPatchOperation
import no.digdir.service_catalog.model.LocalizedStrings
import no.digdir.service_catalog.model.OpEnum
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.PUBLIC_SERVICE_1
import no.digdir.service_catalog.utils.PUBLIC_SERVICE_2
import no.digdir.service_catalog.utils.apiAuthorizedRequest
import no.digdir.service_catalog.utils.*
import no.digdir.service_catalog.utils.jwt.Access
import no.digdir.service_catalog.utils.jwt.JwtToken
import org.junit.jupiter.api.Assertions
Expand All @@ -22,6 +18,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.test.context.ContextConfiguration
import kotlin.test.assertEquals

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(
Expand Down Expand Up @@ -336,6 +333,82 @@ class PublicServices: ApiTestContext() {
}
}

@Nested
internal inner class CreatePublicService {
private val path = "/catalogs/910244132/public-services"

@Test
fun `create PublicService as OrgWrite`() {
val before = apiAuthorizedRequest(
path,
port,
null,
JwtToken(Access.ORG_ADMIN).toString(),
HttpMethod.GET
)
assertEquals(HttpStatus.OK.value(), before["status"])

val createResponse = apiAuthorizedRequest(
path,
port,
mapper.writeValueAsString(PUBLIC_SERVICE_TO_BE_CREATED),
JwtToken(Access.ORG_WRITE).toString(),
HttpMethod.POST
)
assertEquals(HttpStatus.CREATED.value(), createResponse["status"])

val after = apiAuthorizedRequest(
path,
port,
null,
JwtToken(Access.ORG_ADMIN).toString(),
HttpMethod.GET
)
assertEquals(HttpStatus.OK.value(), after["status"])

val allPublicServicesBefore: List<PublicService> = mapper.readValue(before["body"] as String)
val allPublicServicesAfter: List<PublicService> = mapper.readValue(after["body"] as String)
assertEquals(allPublicServicesBefore.size + 1, allPublicServicesAfter.size)
}

@Test
fun `create PublicService as OrgAdmin`() {
val createResponse = apiAuthorizedRequest(
path,
port,
mapper.writeValueAsString(PUBLIC_SERVICE_TO_BE_CREATED),
JwtToken(Access.ORG_ADMIN).toString(),
HttpMethod.POST
)
assertEquals(HttpStatus.CREATED.value(), createResponse["status"])
}

@Test
fun `create PublicService as OrgRead forbidden`() {
val createResponse = apiAuthorizedRequest(
path,
port,
mapper.writeValueAsString(PUBLIC_SERVICE_TO_BE_CREATED),
JwtToken(Access.ORG_READ).toString(),
HttpMethod.POST
)
assertEquals(HttpStatus.FORBIDDEN.value(), createResponse["status"])
}

@Test
fun `create PublicService as WrongOrg forbidden`() {
val createResponse = apiAuthorizedRequest(
path,
port,
mapper.writeValueAsString(PUBLIC_SERVICE_TO_BE_CREATED),
JwtToken(Access.WRONG_ORG_WRITE).toString(),
HttpMethod.POST
)
assertEquals(HttpStatus.FORBIDDEN.value(), createResponse["status"])
}
}


@Nested
internal inner class PublishPublicService {
val pathService1 = "/catalogs/910244132/public-services/1/publish"
Expand Down
3 changes: 3 additions & 0 deletions src/test/kotlin/no/digdir/service_catalog/utils/TestData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,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.PublicServiceToBeCreated
import no.digdir.service_catalog.model.Service
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap

Expand Down Expand Up @@ -34,4 +35,6 @@ val PUBLIC_SERVICE_2 =
PublicService("2", "910244132",
title = LocalizedStrings("NB Tittel 2", "NN Tittel 2", "EN Tittel 2"), null)

val PUBLIC_SERVICE_TO_BE_CREATED = PublicServiceToBeCreated(title = LocalizedStrings("NB Tittel 2", "NN Tittel 2", "EN Tittel 2"), null)

val PUBLIC_SERVICES = listOf(PUBLIC_SERVICE_0, PUBLIC_SERVICE_1, PUBLIC_SERVICE_2)

0 comments on commit f24086c

Please sign in to comment.