Skip to content

Commit

Permalink
Merge pull request #380 from navikt/flytt_tjenesteid_til_frontend
Browse files Browse the repository at this point in the history
userinfo/v2
  • Loading branch information
kenglxn authored Oct 16, 2024
2 parents 01cfac5 + 8ce6749 commit b543700
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package no.nav.arbeidsgiver.min_side.services.altinn

import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
Expand All @@ -26,7 +27,7 @@ class AltinnService(
@Value("\${nais.cluster.name}") private val naisCluster: String,
) {

private val cache: Cache<String, AltinnTilgangerResponse> = Caffeine.newBuilder()
private val cache: Cache<String, AltinnTilganger> = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()
Expand All @@ -43,26 +44,20 @@ class AltinnService(
)
).build()

fun hentOrganisasjoner(): List<Organisasjon> {
val altinnTilganger = hentAltinnTilganger()
val organisasjoner = altinnTilganger.hierarki.flatMap { flattenUnderOrganisasjoner(it) }
return organisasjoner
}

fun hentAltinnTilganger(): AltinnTilgangerResponse =
fun hentAltinnTilganger() =
cache.getIfPresent(authenticatedUserHolder.token) ?: run {
hentAltinnTilgangerFraProxy().also {
cache.put(authenticatedUserHolder.token, it)
}
}

fun harTilgang(orgnr: String, tjeneste: String) =
hentAltinnTilganger().orgNrTilTilganger[orgnr]?.contains(tjeneste) ?: false
fun hentOrganisasjoner() = hentAltinnTilganger().organisasjonerFlattened

fun harOrganisasjon(orgnr: String) =
hentOrganisasjoner().any { it.organizationNumber == orgnr }
fun harTilgang(orgnr: String, tjeneste: String) = hentAltinnTilganger().harTilgang(orgnr, tjeneste)

private fun hentAltinnTilgangerFraProxy(): AltinnTilgangerResponse {
fun harOrganisasjon(orgnr: String) = hentAltinnTilganger().harOrganisasjon(orgnr)

private fun hentAltinnTilgangerFraProxy(): AltinnTilganger {
val token = tokenExchangeClient.exchange(
authenticatedUserHolder.token,
"$naisCluster:fager:arbeidsgiver-altinn-tilganger"
Expand All @@ -75,30 +70,16 @@ class AltinnService(
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer $token")
.build(),
AltinnTilgangerResponse::class.java
AltinnTilganger::class.java
)

return response.body!! // response != 200 => throws
}

private fun flattenUnderOrganisasjoner(
altinnTilgang: AltinnTilgangerResponse.AltinnTilgang,
parentOrgNr: String? = null
): List<Organisasjon> {
val parent = Organisasjon(
name = altinnTilgang.name,
parentOrganizationNumber = parentOrgNr,
organizationForm = altinnTilgang.organizationForm,
organizationNumber = altinnTilgang.orgNr
)
val children = altinnTilgang.underenheter.flatMap { flattenUnderOrganisasjoner(it, parent.organizationNumber) }
return listOf(parent) + children
}
}


@JsonIgnoreProperties(ignoreUnknown = true)
data class AltinnTilgangerResponse(
data class AltinnTilganger(
val isError: Boolean,
val hierarki: List<AltinnTilgang>,
val orgNrTilTilganger: Map<String, Set<String>>,
Expand All @@ -112,5 +93,28 @@ data class AltinnTilgangerResponse(
val name: String,
val organizationForm: String,
)

@get:JsonIgnore
val organisasjonerFlattened : List<Organisasjon>
get() = hierarki.flatMap { flattenUnderOrganisasjoner(it) }

fun harOrganisasjon(orgnr: String) =
organisasjonerFlattened.any { it.organizationNumber == orgnr }

fun harTilgang(orgnr: String, tjeneste: String) = orgNrTilTilganger[orgnr]?.contains(tjeneste) ?: false

private fun flattenUnderOrganisasjoner(
altinnTilgang: AltinnTilgang,
parentOrgNr: String? = null
): List<Organisasjon> {
val parent = Organisasjon(
name = altinnTilgang.name,
parentOrganizationNumber = parentOrgNr,
organizationForm = altinnTilgang.organizationForm,
organizationNumber = altinnTilgang.orgNr
)
val children = altinnTilgang.underenheter.flatMap { flattenUnderOrganisasjoner(it, parent.organizationNumber) }
return listOf(parent) + children
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlinx.coroutines.supervisorScope
import no.nav.arbeidsgiver.min_side.controller.AuthenticatedUserHolder
import no.nav.arbeidsgiver.min_side.models.Organisasjon
import no.nav.arbeidsgiver.min_side.services.altinn.AltinnService
import no.nav.arbeidsgiver.min_side.services.altinn.AltinnTilganger
import no.nav.arbeidsgiver.min_side.services.digisyfo.DigisyfoService
import no.nav.arbeidsgiver.min_side.services.digisyfo.DigisyfoService.VirksomhetOgAntallSykmeldte
import no.nav.arbeidsgiver.min_side.services.tiltak.RefusjonStatusService
Expand All @@ -20,75 +21,49 @@ class UserInfoController(
private val authenticatedUserHolder: AuthenticatedUserHolder,
) {

/**
* konseptet tjeneste id er noe som finnes i frontend.
* på sikt bør oversetting/oppslag flyttes dit og denne koden slettes
*/
val idLookup = mapOf(
"5384:1" to "ekspertbistand",
"4936:1" to "inntektsmelding",
"4826:1" to "utsendtArbeidstakerEØS",
"2896:87" to "endreBankkontonummerForRefusjoner",
"5332:1" to "arbeidstrening",
"5332:2" to "arbeidstrening",
"5441:1" to "arbeidsforhold",
"5516:1" to "midlertidigLønnstilskudd",
"5516:2" to "varigLønnstilskudd",
"5516:3" to "sommerjobb",
"5516:4" to "mentortilskudd",
"5516:5" to "inkluderingstilskudd",
"3403:1" to "sykefravarstatistikk",
"3403:2" to "sykefravarstatistikk",
"5934:1" to "forebyggefravar",
"5078:1" to "rekruttering",
"5278:1" to "tilskuddsbrev",
"5902:1" to "yrkesskade",
)


@GetMapping("/api/userInfo/v1")
suspend fun getUserInfo(): UserInfoRespons {
val (tilganger, organisasjoner, syfoVirksomheter, refusjoner) = supervisorScope {
val tilganger = async {
altinnService.hentAltinnTilganger().let {
it.tilgangTilOrgNr.map { (tilgang, value) ->
if (tilgang.contains(":")) {
/**
* I frontend mappes tilganger til en record fra tjeneste "id" til et set med orgnr
* dette blir dobbeltarbeid. Endre frontend til å motta map direkte på form:
* {
* "tjenestekode:tjenesteversjon": ["orgnr1", "orgnr2"]
* }
*/
val (tjenestekode, tjenesteversjon) = tilgang.split(":")
UserInfoRespons.Tilgang(
id = idLookup[tilgang] ?: tilgang,
tjenestekode = tjenestekode,
tjenesteversjon = tjenesteversjon,
organisasjoner = value.toList(),
altinnError = it.isError,
)
} else {
/**
* altinn3 ressurser har ingen tjenesteversjon
* her burde vi på sikt ha en bedre måte å skille på
* altinn2 tjeneste tilgang vs altinn3 ressurs tilgang
*/
UserInfoRespons.Tilgang(
id = tilgang,
tjenestekode = tilgang,
tjenesteversjon = "",
organisasjoner = value.toList(),
altinnError = it.isError,
)
runCatching {
altinnService.hentAltinnTilganger().let {
it.tilgangTilOrgNr.map { (tilgang, value) ->
if (tilgang.contains(":")) {
/**
* I frontend mappes tilganger til en record fra tjeneste "id" til et set med orgnr
* dette blir dobbeltarbeid. Endre frontend til å motta map direkte på form:
* {
* "tjenestekode:tjenesteversjon": ["orgnr1", "orgnr2"]
* }
*/
val (tjenestekode, tjenesteversjon) = tilgang.split(":")
UserInfoRespons.Tilgang(
tjenestekode = tjenestekode,
tjenesteversjon = tjenesteversjon,
organisasjoner = value.toList(),
altinnError = it.isError,
)
} else {
/**
* altinn3 ressurser har ingen tjenesteversjon
* her burde vi på sikt ha en bedre måte å skille på
* altinn2 tjeneste tilgang vs altinn3 ressurs tilgang
*/
UserInfoRespons.Tilgang(
tjenestekode = tilgang,
tjenesteversjon = "",
organisasjoner = value.toList(),
altinnError = it.isError,
)
}
}
}
}
}

val organisasjoner = async {
runCatching {
altinnService.hentOrganisasjoner()
altinnService.hentAltinnTilganger().organisasjonerFlattened
}
}

Expand All @@ -109,17 +84,17 @@ class UserInfoController(
}

return UserInfoRespons(
altinnError = organisasjoner.isFailure || tilganger.any { it.altinnError } || refusjoner.isFailure,
altinnError = organisasjoner.isFailure || (tilganger.isFailure || tilganger.getOrDefault(emptyList()).any { it.altinnError }) || refusjoner.isFailure,
digisyfoError = syfoVirksomheter.isFailure,
organisasjoner = organisasjoner.getOrDefault(emptyList()),
digisyfoOrganisasjoner = syfoVirksomheter.getOrDefault(emptyList()),
refusjoner = refusjoner.getOrDefault(emptyList()),
tilganger = tilganger,
tilganger = tilganger.getOrDefault(emptyList()),
)
}

data class UserInfoData(
val tilganger: List<UserInfoRespons.Tilgang>,
val tilganger: Result<List<UserInfoRespons.Tilgang>>,
val organisasjoner: Result<List<Organisasjon>>,
val digisyfoOrganisasjoner: Result<Collection<VirksomhetOgAntallSykmeldte>>,
val refusjoner: Result<List<RefusjonStatusService.Statusoversikt>>,
Expand All @@ -134,14 +109,58 @@ class UserInfoController(
val refusjoner: List<RefusjonStatusService.Statusoversikt>,
) {
data class Tilgang(
val id: String,
val tjenestekode: String,
val tjenesteversjon: String,
val organisasjoner: List<String>,
@get:JsonIgnore val altinnError: Boolean,
)
}


@GetMapping("/api/userInfo/v2")
suspend fun getUserInfoV2(): UserInfoV2Respons {
val (tilganger, syfoVirksomheter, refusjoner) = supervisorScope {
val tilganger = async {
runCatching {
altinnService.hentAltinnTilganger()
}
}

val syfoVirksomheter = async {
runCatching {
digisyfoService.hentVirksomheterOgSykmeldte(authenticatedUserHolder.fnr)
}
}

val refusjoner = async {
runCatching {
refusjonStatusService.statusoversikt(authenticatedUserHolder.fnr)
}
}

Triple(tilganger.await(), syfoVirksomheter.await(), refusjoner.await())
}


return UserInfoV2Respons(
altinnError = tilganger.isFailure || tilganger.getOrNull()?.isError ?: false || refusjoner.isFailure,
digisyfoError = syfoVirksomheter.isFailure,
organisasjoner = tilganger.getOrNull()?.hierarki ?: emptyList(),
digisyfoOrganisasjoner = syfoVirksomheter.getOrDefault(emptyList()),
refusjoner = refusjoner.getOrDefault(emptyList()),
tilganger = tilganger.getOrNull()?.tilgangTilOrgNr ?: emptyMap<String, Set<String>>(),
)
}

data class UserInfoV2Respons(
val altinnError: Boolean,
val digisyfoError: Boolean,
val organisasjoner: List<AltinnTilganger.AltinnTilgang>,
val tilganger: Map<String, Collection<String>>,
val digisyfoOrganisasjoner: Collection<VirksomhetOgAntallSykmeldte>,
val refusjoner: List<RefusjonStatusService.Statusoversikt>,
)

sealed interface Tjeneste {
val sort: Sort
val tjenestekode: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package no.nav.arbeidsgiver.min_side.tiltak

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 no.nav.arbeidsgiver.min_side.services.altinn.AltinnTilgangerResponse
import no.nav.arbeidsgiver.min_side.services.altinn.AltinnTilganger
import no.nav.arbeidsgiver.min_side.services.tiltak.RefusjonStatusKafkaListener
import no.nav.arbeidsgiver.min_side.services.tiltak.RefusjonStatusRepository
import no.nav.arbeidsgiver.min_side.services.tiltak.RefusjonStatusService.Companion.TJENESTEKODE
Expand Down Expand Up @@ -67,23 +66,23 @@ class RefusjonStatusIntegrationTest {
`when`(
altinnService.hentAltinnTilganger()
).thenReturn(
AltinnTilgangerResponse(
AltinnTilganger(
isError = false,
hierarki = listOf(
AltinnTilgangerResponse.AltinnTilgang(
AltinnTilganger.AltinnTilgang(
orgNr = "1",
altinn3Tilganger = setOf(),
altinn2Tilganger = setOf(),
underenheter = listOf(
AltinnTilgangerResponse.AltinnTilgang(
AltinnTilganger.AltinnTilgang(
orgNr = "314",
altinn3Tilganger = setOf(),
altinn2Tilganger = setOf("$TJENESTEKODE:$TJENESTEVERSJON"),
underenheter = listOf(),
name = "Foo & Co",
organizationForm = "BEDR"
),
AltinnTilgangerResponse.AltinnTilgang(
AltinnTilganger.AltinnTilgang(
orgNr = "315",
altinn3Tilganger = setOf(),
altinn2Tilganger = setOf("$TJENESTEKODE:$TJENESTEVERSJON"),
Expand Down
Loading

0 comments on commit b543700

Please sign in to comment.