Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add create method for public service #26

Merged
merged 2 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)