Skip to content

Commit

Permalink
New endpoints for narmesteleder
Browse files Browse the repository at this point in the history
  • Loading branch information
AudunSorheim committed Jan 24, 2024
1 parent 31afb79 commit 70f64d2
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 2 deletions.
7 changes: 7 additions & 0 deletions nais/nais-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ spec:
- application: syfobrukertilgang
namespace: team-esyfo
cluster: dev-gcp
- application: isnarmesteleder
namespace: teamsykefravr
cluster: dev-gcp
azure:
application:
allowAllUsers: true
Expand Down Expand Up @@ -92,6 +95,10 @@ spec:
value: dev-gcp:team-esyfo:syfobrukertilgang
- name: OPPFOLGINGSPLAN_FRONTEND_CLIENT_ID
value: dev-gcp:team-esyfo:oppfolgingsplan-frontend
- name: NARMESTELEDER_URL
value: http://isnarmesteleder.teamsykefravr
- name: NARMESTELEDER_CLIENT_ID
value: dev-gcp:teamsykefravr:isnarmesteleder
redis:
- instance: oppfolgingsplan
access: readwrite
7 changes: 7 additions & 0 deletions nais/nais-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ spec:
- application: syfobrukertilgang
namespace: team-esyfo
cluster: prod-gcp
- application: isnarmesteleder
namespace: teamsykefravr
cluster: prod-gcp
azure:
application:
allowAllUsers: true
Expand Down Expand Up @@ -92,6 +95,10 @@ spec:
value: prod-gcp:team-esyfo:syfobrukertilgang
- name: OPPFOLGINGSPLAN_FRONTEND_CLIENT_ID
value: prod-gcp:team-esyfo:oppfolgingsplan-frontend
- name: NARMESTELEDER_URL
value: http://isnarmesteleder.teamsykefravr
- name: NARMESTELEDER_CLIENT_ID
value: prod-gcp:teamsykefravr:isnarmesteleder
redis:
- instance: oppfolgingsplan
access: readwrite
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class BrukertilgangClient(

private fun getResponse(httpEntity: HttpEntity<*>, ansattFnr: String): ResponseEntity<Boolean> {
return RestTemplate().exchange(
"$baseUrl/api/v2/tilgang/ansatt/{ansattFnr}",
"$baseUrl/api/v2/tilgang/ansatt/$ansattFnr",
HttpMethod.GET,
httpEntity,
Boolean::class.java,
Expand Down
108 changes: 108 additions & 0 deletions src/main/kotlin/no/nav/syfo/narmesteleder/NarmesteLederClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package no.nav.syfo.narmesteleder

import no.nav.security.token.support.core.context.TokenValidationContextHolder
import no.nav.syfo.auth.oidc.TokenUtil
import no.nav.syfo.auth.tokenx.TokenXUtil
import no.nav.syfo.auth.tokenx.tokendings.TokenDingsConsumer
import no.nav.syfo.util.*
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClientResponseException
import org.springframework.web.client.RestTemplate
import java.util.*

@Service
class NarmesteLederClient(
@Value("\${narmesteleder.url}") private val baseUrl: String,
@Value("\${narmesteleder.client.id}") private var targetApp: String,
private val tokenDingsConsumer: TokenDingsConsumer,
private val contextHolder: TokenValidationContextHolder,
) {
@Cacheable(value = ["aktive_ledere"], key = "#ansattFnr", condition = "#ansattFnr != null")
fun alleAktiveLedereForSykmeldt(
ansattFnr: String,
): List<NarmesteLederRelasjonDTO> {

val issuerToken = TokenUtil.getIssuerToken(contextHolder, TokenXUtil.TokenXIssuer.TOKENX)
val exchangedToken = tokenDingsConsumer.exchangeToken(issuerToken, targetApp)

try {
val response = getResponse(
fnr = ansattFnr,
accessToken = exchangedToken
)

val relasjoner = response.body ?: emptyArray()

return relasjoner
.filter { it.status == NarmesteLederRelasjonStatus.INNMELDT_AKTIV.name }
.filter { it.arbeidstakerPersonIdentNumber == ansattFnr }
.distinctBy { it.narmesteLederPersonIdentNumber }
} catch (e: RestClientResponseException) {
log.error(
"Error while requesting all NarmesteLeder of sykmeldt. Stacktrace: {}",
e.stackTraceToString()
)
return emptyList()
}
}

@Cacheable(value = ["aktive_ansatte"], key = "#narmesteLederIdent", condition = "#narmesteLederIdent != null")
fun aktivNarmesteLederIVirksomhet(
ansattFnr: String,
narmesteLederIdent: String,
virksomhetsnummer: String,
): NarmesteLederRelasjonDTO? {
try {
val narmesteLederRelasjoner = alleAktiveLedereForSykmeldt(ansattFnr)

return narmesteLederRelasjoner
.filter { it.narmesteLederPersonIdentNumber == narmesteLederIdent }
.firstOrNull { it.virksomhetsnummer == virksomhetsnummer }
} catch (e: RestClientResponseException) {
log.error(
"Error while requesting aktive ansatte of leder. Stacktrace: {}",
e.stackTraceToString()
)
return null
}
}

private fun headers(fnr: String, accessToken: String): HttpEntity<String> {
val headers = HttpHeaders()
headers.contentType = MediaType.APPLICATION_JSON
headers[HttpHeaders.AUTHORIZATION] = bearerHeader(accessToken)
headers[NAV_PERSONIDENT_HEADER] = fnr
headers[NAV_CALL_ID_HEADER] = createCallId()
return HttpEntity(headers)
}

private fun getResponse(
fnr: String,
accessToken: String
): ResponseEntity<Array<NarmesteLederRelasjonDTO>> {
return RestTemplate().exchange(
"$baseUrl/api/selvbetjening/v1/narmestelederrelasjoner",
HttpMethod.GET,
headers(fnr, accessToken),
Array<NarmesteLederRelasjonDTO>::class.java,
)
}

companion object {
private val log = LoggerFactory.getLogger(NarmesteLederClient::class.java)

private fun createCallId(): String {
val randomUUID = UUID.randomUUID().toString()
return "oppfolgingsplan-backend-$randomUUID"
}
}

}
105 changes: 105 additions & 0 deletions src/main/kotlin/no/nav/syfo/narmesteleder/NarmesteLederController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package no.nav.syfo.narmesteleder

import no.nav.security.token.support.core.api.ProtectedWithClaims
import no.nav.security.token.support.core.context.TokenValidationContextHolder
import no.nav.syfo.auth.tokenx.TokenXUtil
import no.nav.syfo.auth.tokenx.TokenXUtil.TokenXIssuer.TOKENX
import no.nav.syfo.auth.tokenx.TokenXUtil.fnrFromIdportenTokenX
import no.nav.syfo.brukertilgang.BrukertilgangService
import no.nav.syfo.metric.Metrikk
import no.nav.syfo.util.NAV_PERSONIDENT_HEADER
import no.nav.syfo.util.ORGNUMMER_HEADER
import no.nav.syfo.util.fodselsnummerInvalid
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController

@RestController
@ProtectedWithClaims(issuer = TOKENX, claimMap = ["acr=Level4", "acr=idporten-loa-high"], combineWithOr = true)
@RequestMapping(value = ["/api/v1/narmesteleder"])
class NarmesteLederController @Autowired constructor(
private val contextHolder: TokenValidationContextHolder,
private val metrikk: Metrikk,
private val narmesteLederClient: NarmesteLederClient,
@Value("\${oppfolgingsplan.frontend.client.id}")
private val oppfolgingsplanClientId: String,
private val brukertilgangService: BrukertilgangService,
) {

@ResponseBody
@GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE], path = ["/virksomhet"])
fun getAktivNarmesteLederIVirksomhet(
@RequestHeader(NAV_PERSONIDENT_HEADER) fnr: String,
@RequestHeader(ORGNUMMER_HEADER) virksomhetsnummer: String,
): ResponseEntity<NarmesteLederRelasjonDTO?> {
metrikk.tellHendelse("get_narmesteledere")

val innloggetIdent = TokenXUtil.validateTokenXClaims(contextHolder, oppfolgingsplanClientId)
.fnrFromIdportenTokenX()
.value

return if (fodselsnummerInvalid(fnr)) {
LOG.error("Ugyldig fnr ved henting av nærmeste ledere")
ResponseEntity
.status(HttpStatus.FORBIDDEN)
.build()
} else {
if (!brukertilgangService.tilgangTilOppslattIdent(innloggetIdent, fnr)) {
LOG.error("Ikke tilgang til nærmeste ledere: Bruker spør om noen andre enn seg selv eller egne ansatte")
ResponseEntity
.status(HttpStatus.FORBIDDEN)
.build()
} else {
val narmesteLedere = narmesteLederClient.aktivNarmesteLederIVirksomhet(
ansattFnr = fnr,
narmesteLederIdent = innloggetIdent,
virksomhetsnummer = virksomhetsnummer
)
if (narmesteLedere != null) {
return ResponseEntity
.status(HttpStatus.OK)
.body(narmesteLedere)
} else {
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build()
}
}
}
}

@ResponseBody
@GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE], path = ["/alle"])
fun getNarmesteLedere(): ResponseEntity<List<NarmesteLederRelasjonDTO>> {
metrikk.tellHendelse("get_narmesteledere")

val innloggetIdent = TokenXUtil.validateTokenXClaims(contextHolder, oppfolgingsplanClientId)
.fnrFromIdportenTokenX()
.value

val narmesteLedere = narmesteLederClient.alleAktiveLedereForSykmeldt(ansattFnr = innloggetIdent)

return if (narmesteLedere.isNotEmpty()) {
ResponseEntity
.status(HttpStatus.OK)
.body(narmesteLedere)
} else {
ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build()
}
}


companion object {
private val LOG = LoggerFactory.getLogger(NarmesteLederController::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package no.nav.syfo.narmesteleder

import java.time.*

data class NarmesteLederRelasjonDTO(
val uuid: String,
val arbeidstakerPersonIdentNumber: String,
val virksomhetsnavn: String?,
val virksomhetsnummer: String,
val narmesteLederPersonIdentNumber: String,
val narmesteLederTelefonnummer: String,
val narmesteLederEpost: String,
val narmesteLederNavn: String?,
val aktivFom: LocalDate,
val aktivTom: LocalDate?,
val arbeidsgiverForskutterer: Boolean?,
val timestamp: LocalDateTime,
val status: String,
)

enum class NarmesteLederRelasjonStatus {
INNMELDT_AKTIV,
DEAKTIVERT,
DEAKTIVERT_ARBEIDSTAKER,
DEAKTIVERT_ARBEIDSTAKER_INNSENDT_SYKMELDING,
DEAKTIVERT_LEDER,
DEAKTIVERT_ARBEIDSFORHOLD,
DEAKTIVERT_NY_LEDER,
}
2 changes: 1 addition & 1 deletion src/main/kotlin/no/nav/syfo/util/RequestUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.util.*
const val NAV_CONSUMER_ID_HEADER = "Nav-Consumer-Id"
const val APP_CONSUMER_ID = "srvoppfolgingsplanbackend"
const val NAV_CALL_ID_HEADER = "Nav-Call-Id"

const val ORGNUMMER_HEADER = "orgnummer"
const val NAV_PERSONIDENT_HEADER = "nav-personident"

fun createCallId(): String = UUID.randomUUID().toString()
Expand Down

0 comments on commit 70f64d2

Please sign in to comment.