Skip to content

Commit

Permalink
api for varslingstatus
Browse files Browse the repository at this point in the history
  • Loading branch information
kenglxn committed Oct 11, 2023
1 parent 2bf689d commit 7f0ef95
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package no.nav.arbeidsgiver.min_side.varslingstatus

import no.nav.arbeidsgiver.min_side.controller.AuthenticatedUserHolder
import no.nav.arbeidsgiver.min_side.services.altinn.AltinnService
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime

@RestController
class VarslingStatusController(
private val authenticatedUserHolder: AuthenticatedUserHolder,
private val altinnService: AltinnService,
private val repository: VarslingStatusRepository,
) {

@PostMapping("/api/varslingStatus/v1")
fun getVarslingStatus(@RequestBody requestBody: VarslingStatusRequest): VarslingStatus {
val virksomhetsnummer = requestBody.virksomhetsnummer
val harTilgang = altinnService.hentOrganisasjoner(authenticatedUserHolder.fnr)
.any { it.organizationNumber == virksomhetsnummer }

if (!harTilgang) {
return VarslingStatus(
status = Status.OK,
varselTimestamp = LocalDateTime.now(),
eventTimestamp = LocalDateTime.now(),
)
}

return repository.varslingStatus(virksomhetsnummer = virksomhetsnummer)
}

data class VarslingStatusRequest(
val virksomhetsnummer: String,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package no.nav.arbeidsgiver.min_side.varslingstatus

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.springframework.context.annotation.Profile
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.kafka.annotation.KafkaListener
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
import java.sql.PreparedStatement
import java.time.LocalDateTime

data class VarslingStatus(
val status: Status,
val varselTimestamp: LocalDateTime,
val eventTimestamp: LocalDateTime,
)

@Repository
class VarslingStatusRepository(
private val jdbcTemplate: JdbcTemplate,
private val namedParameterJdbcTemplate: NamedParameterJdbcTemplate,
) {
fun varslingStatus(virksomhetsnummer: String): VarslingStatus {
return namedParameterJdbcTemplate.queryForList(
"""
select status, varslet_tidspunkt, status_tidspunkt
from varsling_status
where virksomhetsnummer = :virksomhetsnummer
order by status_tidspunkt desc
""".trimIndent(),
mapOf("virksomhetsnummer" to virksomhetsnummer)
).firstOrNull()?.let {
VarslingStatus(
status = Status.valueOf(it["status"] as String),
varselTimestamp = LocalDateTime.parse(it["varslet_tidspunkt"] as String),
eventTimestamp = LocalDateTime.parse(it["status_tidspunkt"] as String),
)
} ?: VarslingStatus(
status = Status.OK,
varselTimestamp = LocalDateTime.now(),
eventTimestamp = LocalDateTime.now(),
)
}

fun processVarslingStatus(varslingStatus: VarslingStatusDto) {
jdbcTemplate.update(
"""
insert into varsling_status(
varsel_id, virksomhetsnummer, status, status_tidspunkt, varslet_tidspunkt
) values(?, ?, ?, ?, ?)
on conflict (varsel_id)
-- upserter bare for sikkerhetsskyld, vil antakelig ikke skje
do update set
status = EXCLUDED.status,
status_tidspunkt = EXCLUDED.status_tidspunkt,
varslet_tidspunkt = EXCLUDED.varslet_tidspunkt;
""".trimIndent()
) { ps: PreparedStatement ->
ps.setString(1, varslingStatus.varselId)
ps.setString(2, varslingStatus.virksomhetsnummer)
ps.setString(3, varslingStatus.status.toString())
ps.setString(4, varslingStatus.eventTimestamp.toString())
ps.setString(5, varslingStatus.varselTimestamp.toString())
}
}
}

@Profile("dev-gcp", "prod-gcp")
@Service
class VarslingStatusKafkaListener(
private val varslingStatusRepository: VarslingStatusRepository,
private val objectMapper: ObjectMapper,
) {
@Profile("dev-gcp", "prod-gcp")
@KafkaListener(
id = "min-side-arbeidsgiver-varsling-status-1",
topics = ["fager.ekstern-varsling-status"],
containerFactory = "errorLoggingKafkaListenerContainerFactory"
)
fun processVarslingStatus(record: ConsumerRecord<String?, String?>) =
varslingStatusRepository.processVarslingStatus(
objectMapper.readValue(record.value(), VarslingStatusDto::class.java)
)
}

@JsonIgnoreProperties(ignoreUnknown = true)
data class VarslingStatusDto @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) constructor(
@param:JsonProperty("virksomhetsnummer") val virksomhetsnummer: String,
@param:JsonProperty("varselId") val varselId: String,
@param:JsonProperty("varselTimestamp") val varselTimestamp: LocalDateTime,
@param:JsonProperty("eventTimestamp") val eventTimestamp: LocalDateTime,
@param:JsonProperty("status") val status: Status,
@param:JsonProperty("version") val version: String,
)

enum class Status {
OK,
MANGLER_KOFUVI,
ANNEN_FEIL,
}


12 changes: 12 additions & 0 deletions src/main/resources/db/migration/V10__varsling_status.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
create table varsling_status
(
varsel_id text not null primary key,
virksomhetsnummer text not null,
status text not null,
status_tidspunkt text not null,
varslet_tidspunkt text not null
);
create index varsling_status_virksomhetsnummer_idx on varsling_status (virksomhetsnummer);



Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package no.nav.arbeidsgiver.min_side.varslingstatus

import com.fasterxml.jackson.databind.ObjectMapper
import no.nav.arbeidsgiver.min_side.controller.SecurityMockMvcUtil.Companion.jwtWithPid
import no.nav.arbeidsgiver.min_side.models.Organisasjon
import no.nav.arbeidsgiver.min_side.services.altinn.AltinnService
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.flywaydb.core.Flyway
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when`
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.post

@SpringBootTest(
properties = [
"server.servlet.context-path=/",
"spring.flyway.cleanDisabled=false",
]
)
@AutoConfigureMockMvc
class VarslingStatusIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

@Autowired
lateinit var varslingStatusRepository: VarslingStatusRepository

@Autowired
lateinit var objectMapper: ObjectMapper

lateinit var varslingStatusKafkaListener: VarslingStatusKafkaListener

@MockBean // the real jwt decoder is bypassed by SecurityMockMvcRequestPostProcessors.jwt
lateinit var jwtDecoder: JwtDecoder

@MockBean
lateinit var altinnService: AltinnService

@Autowired
lateinit var flyway: Flyway

@BeforeEach
fun setup() {
flyway.clean()
flyway.migrate()
varslingStatusKafkaListener = VarslingStatusKafkaListener(
varslingStatusRepository,
objectMapper,
)
}

@Test
fun `bruker som ikke har tilgang får status ok som default`() {
`when`(
altinnService.hentOrganisasjoner("42")
).thenReturn(emptyList())

processVarslingStatus(
"""
{
"virksomhetsnummer": "314",
"varselId": "vid1",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "2021-01-01T00:00:00",
"status": "MANGLER_KOFUVI",
"version": "1"
}
"""
)

mockMvc.post("/api/varslingStatus/v1") {
content = """{"virksomhetsnummer": "314"}"""
contentType = APPLICATION_JSON
accept = APPLICATION_JSON
with(jwtWithPid("42"))
}.andExpect {
status { isOk() }
content { json("""{"status": "OK"}""") }
}
}

@Test
fun `bruker med tilgang men ingen status i databasen får OK som default`() {
`when`(
altinnService.hentOrganisasjoner("42")
).thenReturn(listOf(Organisasjon(organizationNumber = "314", name = "Foo & Co")))

processVarslingStatus(
"""
{
"virksomhetsnummer": "86",
"varselId": "vid1",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "2021-01-01T00:00:00",
"status": "MANGLER_KOFUVI",
"version": "1"
}
"""
)

mockMvc.post("/api/varslingStatus/v1") {
content = """{"virksomhetsnummer": "314"}"""
contentType = APPLICATION_JSON
accept = APPLICATION_JSON
with(jwtWithPid("42"))
}.andExpect {
status { isOk() }
content { json("""{"status": "OK"}""") }
}
}

@Test
fun `returnerer siste status for virksomhet`() {
`when`(
altinnService.hentOrganisasjoner("42")
).thenReturn(listOf(Organisasjon(organizationNumber = "314", name = "Foo & Co")))

listOf(
"MANGLER_KOFUVI" to "2021-01-02T00:00:00",
"OK" to "2021-01-01T00:00:00",
"MANGLER_KOFUVI" to "2021-01-04T00:00:00",
"ANNEN_FEIL" to "2021-01-03T00:00:00",
).forEachIndexed { index, (status, timestamp) ->
processVarslingStatus(
"""
{
"virksomhetsnummer": "314",
"varselId": "vid$index",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "$timestamp",
"status": "$status",
"version": "1"
}
"""
)
}

mockMvc.post("/api/varslingStatus/v1") {
content = """{"virksomhetsnummer": "314"}"""
contentType = APPLICATION_JSON
accept = APPLICATION_JSON
with(jwtWithPid("42"))
}.andExpect {
status { isOk() }
content {
json(
"""{
"status": "MANGLER_KOFUVI",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "2021-01-04T00:00:00"
}""",
true
)
}
}
}

@Test
fun `returnerer siste status for virksomhet OK`() {
`when`(
altinnService.hentOrganisasjoner("42")
).thenReturn(listOf(Organisasjon(organizationNumber = "314", name = "Foo & Co")))

listOf(
"MANGLER_KOFUVI" to "2021-01-01T00:00:00",
"OK" to "2021-01-07T00:00:00",
"ANNEN_FEIL" to "2021-01-02T00:00:00",
"MANGLER_KOFUVI" to "2021-01-03T00:00:00",
).forEachIndexed { index, (status, timestamp) ->
processVarslingStatus(
"""
{
"virksomhetsnummer": "314",
"varselId": "vid$index",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "$timestamp",
"status": "$status",
"version": "1"
}
"""
)
}

mockMvc.post("/api/varslingStatus/v1") {
content = """{"virksomhetsnummer": "314"}"""
contentType = APPLICATION_JSON
accept = APPLICATION_JSON
with(jwtWithPid("42"))
}.andExpect {
status { isOk() }
content {
json(
"""{
"status": "OK",
"varselTimestamp": "2021-01-01T00:00:00",
"eventTimestamp": "2021-01-07T00:00:00"
}""",
true
)
}
}
}

private fun processVarslingStatus(value: String) {
varslingStatusKafkaListener.processVarslingStatus(
ConsumerRecord(
"", 0, 0, "", value
)
)
}
}

0 comments on commit 7f0ef95

Please sign in to comment.