Skip to content

Commit

Permalink
Koblet på tilgangskontroll + omskriving av plukk oppgave.
Browse files Browse the repository at this point in the history
  • Loading branch information
frodeli committed Sep 18, 2024
1 parent cf40b45 commit 648165b
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .nais/app-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ spec:
outbound:
rules:
- application: tilgang
env:
- name: INTEGRASJON_TILGANG_URL
value: http://tilgang
- name: INTEGRASJON_TILGANG_SCOPE
value: api://dev-gcp.aap.tilgang/.default
gcp:
sqlInstances:
- type: POSTGRES_16
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ data class NesteOppgaveDto(
val oppgaveId: OppgaveId,
val saksnummer: String?,
val behandlingRef: UUID?,
val journalpostId: Long?
val journalpostId: Long?,
val avklaringsbehovKode: String
)
5 changes: 4 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

val ktorVersion = "2.3.12"
val komponenterVersjon = "0.0.53"
val komponenterVersjon = "0.0.56"
val tilgangVersjon = "0.0.6"

plugins {
id("oppgave.conventions")
Expand All @@ -17,7 +18,9 @@ dependencies {
implementation("no.nav.aap.kelvin:dbconnect:$komponenterVersjon")
implementation("no.nav.aap.kelvin:dbmigrering:$komponenterVersjon")
implementation("no.nav.aap.kelvin:dbtest:$komponenterVersjon")
implementation("no.nav.aap.kelvin:infrastructure:$komponenterVersjon")
implementation("no.nav:ktor-openapi-generator:1.0.31")
implementation("no.nav.aap.tilgang:api-kontrakt:$tilgangVersjon")

implementation("io.ktor:ktor-server-auth:$ktorVersion")
implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion")
Expand Down
51 changes: 25 additions & 26 deletions app/src/main/kotlin/no/nav/aap/oppgave/OppgaveRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ class OppgaveRepository(private val connection: DBConnection) {
}
}

fun reserverNesteOppgave(filterDto: FilterDto, ident: String): NesteOppgaveDto? {
fun finnNesteOppgave(filterDto: FilterDto): NesteOppgaveDto? {
val hentNesteOppgaveQuery = """
SELECT
ID, SAKSNUMMER, BEHANDLING_REF, JOURNALPOST_ID
ID, SAKSNUMMER, BEHANDLING_REF, JOURNALPOST_ID, AVKLARINGSBEHOV_TYPE
FROM
OPPGAVE
WHERE
Expand All @@ -74,16 +74,36 @@ class OppgaveRepository(private val connection: DBConnection) {
saksnummer = it.getStringOrNull("SAKSNUMMER"),
behandlingRef = it.getUUIDOrNull("BEHANDLING_REF"),
journalpostId = it.getLongOrNull("JOURNALPOST_ID"),
avklaringsbehovKode = it.getString("AVKLARINGSBEHOV_TYPE")
)
}
}
return nesteOppgave
}

if (nesteOppgave != null) {
reserverOppgave(connection, nesteOppgave.oppgaveId, ident)
fun reserverOppgave(oppgaveId: OppgaveId, ident: String) {
val updaterOppgaveReservasjonQuery = """
UPDATE
OPPGAVE
SET
RESERVERT_AV = ?,
RESERVERT_TIDSPUNKT = CURRENT_TIMESTAMP,
ENDRET_AV = ?,
ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP
WHERE ID = ?
""".trimIndent()

connection.execute(updaterOppgaveReservasjonQuery) {
setParams {
setString(1, ident)
setString(2, ident)
setLong(3, oppgaveId.id)
}
}
return nesteOppgave
}



fun hentMineOppgaver(ident: String): List<OppgaveDto> {
val query = """
SELECT
Expand Down Expand Up @@ -163,27 +183,6 @@ class OppgaveRepository(private val connection: DBConnection) {
}
}

private fun reserverOppgave(connection: DBConnection, oppgaveId: OppgaveId, ident: String) {
val updaterOppgaveReservasjonQuery = """
UPDATE
OPPGAVE
SET
RESERVERT_AV = ?,
RESERVERT_TIDSPUNKT = CURRENT_TIMESTAMP,
ENDRET_AV = ?,
ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP
WHERE ID = ?
""".trimIndent()

connection.execute(updaterOppgaveReservasjonQuery) {
setParams {
setString(1, ident)
setString(2, ident)
setLong(3, oppgaveId.id)
}
}
}

private fun FilterDto.whereClause(): String {
if (avklaringsbehovKoder.isNotEmpty()) {
return "AVKLARINGSBEHOV_TYPE IN ${avklaringsbehovKoder.tilStringListe()} AND "
Expand Down
10 changes: 2 additions & 8 deletions app/src/main/kotlin/no/nav/aap/oppgave/plukk/PlukkAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import com.papsign.ktor.openapigen.route.route
import io.ktor.http.HttpStatusCode
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry
import no.nav.aap.komponenter.dbconnect.transaction
import no.nav.aap.oppgave.OppgaveRepository
import no.nav.aap.oppgave.filter.FilterRepository
import no.nav.aap.komponenter.httpklient.auth.token
import no.nav.aap.oppgave.metriker.httpCallCounter
import no.nav.aap.oppgave.server.authenticate.ident
import javax.sql.DataSource
Expand All @@ -19,12 +18,7 @@ fun NormalOpenAPIRoute.plukkApi(dataSource: DataSource, prometheus: PrometheusMe
route("/neste-oppgave").post<Unit, NesteOppgaveDto, FinnNesteOppgaveDto> { _, request ->
prometheus.httpCallCounter("/neste-oppgave").increment()
val nesteOppgave = dataSource.transaction { connection ->
val filter = FilterRepository(connection).hentFilter(request.filterId)
if (filter != null) {
OppgaveRepository(connection).reserverNesteOppgave(filter, ident())
} else {
null
}
PlukkOppgaveService(connection).plukkNesteOppgave(request.filterId, ident(), token())
}
if (nesteOppgave != null) {
respond(nesteOppgave)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package no.nav.aap.oppgave.plukk

import no.nav.aap.komponenter.dbconnect.DBConnection
import no.nav.aap.komponenter.httpklient.httpclient.tokenprovider.OidcToken
import no.nav.aap.oppgave.OppgaveRepository
import no.nav.aap.oppgave.filter.FilterRepository
import tilgang.Operasjon
import tilgang.TilgangRequest

class PlukkOppgaveService(val connection: DBConnection) {

fun plukkNesteOppgave(filterId: Long, ident: String, token: OidcToken): NesteOppgaveDto? {
val oppgaveRepo = OppgaveRepository(connection)
val filterRepo = FilterRepository(connection)
val filter = filterRepo.hentFilter(filterId)
if (filter == null) {
throw IllegalArgumentException("Finner ikke filter med id: $filterId")
}
val nesteOppgave = oppgaveRepo.finnNesteOppgave(filter)
if (nesteOppgave != null) {
val tilgangRequest = TilgangRequest(
saksnummer = nesteOppgave.saksnummer!!,
behandlingsreferanse = nesteOppgave.behandlingRef!!.toString(),
avklaringsbehovKode = nesteOppgave.avklaringsbehovKode,
operasjon = Operasjon.SAKSBEHANDLE
)
if (TilgangGateway.harTilgang(tilgangRequest, token)) {

oppgaveRepo.reserverOppgave(nesteOppgave.oppgaveId, ident)
}
}
return nesteOppgave
}

}
43 changes: 43 additions & 0 deletions app/src/main/kotlin/no/nav/aap/oppgave/plukk/TilgangGateway.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package no.nav.aap.oppgave.plukk

import tilgang.TilgangRequest
import tilgang.TilgangResponse
import no.nav.aap.komponenter.httpklient.httpclient.ClientConfig
import no.nav.aap.komponenter.httpklient.httpclient.RestClient
import no.nav.aap.komponenter.httpklient.httpclient.post
import no.nav.aap.komponenter.httpklient.httpclient.request.PostRequest
import no.nav.aap.komponenter.httpklient.httpclient.tokenprovider.OidcToken
import no.nav.aap.komponenter.httpklient.httpclient.tokenprovider.azurecc.OnBehalfOfTokenProvider
import no.nav.aap.komponenter.config.requiredConfigForKey
import java.net.URI

object TilgangGateway {
private val baseUrl = URI.create(requiredConfigForKey("integrasjon.tilgang.url"))
private val config = ClientConfig(scope = requiredConfigForKey("integrasjon.tilgang.scope"))

private val client = RestClient.withDefaultResponseHandler(
config = config,
tokenProvider = OnBehalfOfTokenProvider,
)

fun harTilgang(body: TilgangRequest, currentToken: OidcToken): Boolean {
val respons = query(
body,
currentToken = currentToken
)
return respons.tilgang
}

private fun query(body: TilgangRequest, currentToken: OidcToken): TilgangResponse {
val httpRequest = PostRequest(
body = body,
currentToken = currentToken
)
return requireNotNull(
client.post<_, TilgangResponse>(
uri = baseUrl.resolve("/tilgang"),
request = httpRequest
)
)
}
}
9 changes: 4 additions & 5 deletions app/src/test/kotlin/no/nav/aap/oppgave/ApiTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ApiTest {
assertThat(oppgaveIder).hasSize(1)
assertThat(oppgaveIder.first()).isEqualTo(oppgaveId)

// Sjekk at det ikkk er flere oppgaver i køen
// Sjekk at det ikke er flere oppgaver i køen
nesteOppgave = hentNesteOppgave()
assertThat(nesteOppgave).isNull()
}
Expand Down Expand Up @@ -134,16 +134,15 @@ class ApiTest {
private val fakes = Fakes(azurePort = 8081)

private val dbConfig = DbConfig(
database = "test",
database = postgres.databaseName,
jdbcUrl = postgres.jdbcUrl,
username = postgres.username,
password = postgres.password
)

private val client = RestClient(
private val client = RestClient.withDefaultResponseHandler(
config = ClientConfig(scope = "oppgave"),
tokenProvider = ClientCredentialsTokenProvider,
responseHandler = DefaultResponseHandler()
tokenProvider = ClientCredentialsTokenProvider
)

// Starter server
Expand Down
39 changes: 19 additions & 20 deletions app/src/test/kotlin/no/nav/aap/oppgave/OppgaveRepositoryTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package no.nav.aap.oppgave
import no.nav.aap.komponenter.dbconnect.transaction
import no.nav.aap.komponenter.dbtest.InitTestDatabase
import no.nav.aap.oppgave.filter.FilterDto
import no.nav.aap.oppgave.plukk.NesteOppgaveDto
import no.nav.aap.oppgave.verdityper.AvklaringsbehovKode
import no.nav.aap.oppgave.verdityper.OppgaveId
import no.nav.aap.oppgave.verdityper.Status
Expand Down Expand Up @@ -37,45 +36,45 @@ class OppgaveRepositoryTest {
}

@Test
fun `Reserver neste oppgave finner ingen oppgave fordi opprettet oppgave ikke matcher filter`() {
fun `Finn neste oppgave finner ingen oppgave fordi opprettet oppgave ikke matcher filter`() {
opprettOppgave(avklaringsbehovKode = AvklaringsbehovKode("1000"))
InitTestDatabase.dataSource.transaction { connection ->
val oppgaveId = OppgaveRepository(connection).reserverNesteOppgave(filter("2000"), "test")
val oppgaveId = OppgaveRepository(connection).finnNesteOppgave(filter("2000"))
assertThat(oppgaveId).isNull()
}
}

@Test
fun `Reserver neste oppgave finner en oppgave fordi en av oppgavene matcher filter`() {
fun `Finn neste oppgave finner en oppgave fordi en av oppgavene matcher filter`() {
opprettOppgave(avklaringsbehovKode = AvklaringsbehovKode("2000"))
opprettOppgave(avklaringsbehovKode = AvklaringsbehovKode("3000"))
InitTestDatabase.dataSource.transaction { connection ->
val oppgaveId = OppgaveRepository(connection).reserverNesteOppgave(filter("3000"), "test")
val oppgaveId = OppgaveRepository(connection).finnNesteOppgave(filter("3000"))
assertThat(oppgaveId).isNotNull()
}
}

@Test
fun `Reserver neste oppgave finner ikke en oppgave fordi den er avsluttet`() {
fun `Finn neste oppgave finner ikke en oppgave fordi den er avsluttet`() {
opprettOppgave(status = Status.AVSLUTTET)
InitTestDatabase.dataSource.transaction { connection ->
val oppgaveId = OppgaveRepository(connection).reserverNesteOppgave(filter(), "test")
val oppgaveId = OppgaveRepository(connection).finnNesteOppgave(filter())
assertThat(oppgaveId).isNull()
}
}

@Test
fun `Hent mine åpne oppgaver`() {
opprettOppgave()
opprettOppgave()
opprettOppgave()
opprettOppgave()

reserverOppgave("bruker1")
reserverOppgave("bruker2")
reserverOppgave("bruker1")
val nesteOppgave = reserverOppgave("bruker1")
avsluttOppgave(nesteOppgave.oppgaveId)
fun `Hent mine reserverte oppgaver som ikke er avsluttet`() {
val oppgaveId1 = opprettOppgave()
val oppgaveId2 = opprettOppgave()
val oppgaveId3 = opprettOppgave()
val oppgaveId4 = opprettOppgave()

reserverOppgave(oppgaveId1, "bruker1")
reserverOppgave(oppgaveId2, "bruker2")
reserverOppgave(oppgaveId3, "bruker1")
reserverOppgave(oppgaveId4, "bruker1")
avsluttOppgave(oppgaveId4)

InitTestDatabase.dataSource.transaction { connection ->
val oppgaver = OppgaveRepository(connection).hentMineOppgaver("bruker1")
Expand All @@ -93,9 +92,9 @@ class OppgaveRepositoryTest {
}
}

private fun reserverOppgave(ident: String): NesteOppgaveDto {
private fun reserverOppgave(oppgaveId: OppgaveId, ident: String) {
return InitTestDatabase.dataSource.transaction { connection ->
OppgaveRepository(connection).reserverNesteOppgave(filter(), ident)!!
OppgaveRepository(connection).reserverOppgave(oppgaveId, ident)
}
}

Expand Down
Loading

0 comments on commit 648165b

Please sign in to comment.