From 50e2073ed5e65dec182554a7d4fe7c57d52f8172 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 16 Feb 2023 13:25:03 +0100 Subject: [PATCH 01/64] Genesis commit --- .gitignore | 31 + paw-pdl-client/.editorconfig | 14 + paw-pdl-client/.github/workflows/main.yml | 25 + paw-pdl-client/.github/workflows/test.yml | 40 + paw-pdl-client/.gitignore | 31 + paw-pdl-client/build.gradle.kts | 75 ++ paw-pdl-client/gradle.properties | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + paw-pdl-client/gradlew | 240 +++++ paw-pdl-client/gradlew.bat | 91 ++ paw-pdl-client/settings.gradle.kts | 13 + .../no/nav/paw/pdl/LocalDateSerializer.kt | 15 + .../no/nav/paw/pdl/LocalDateTimeSerializer.kt | 15 + .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 58 ++ .../main/kotlin/no/nav/paw/pdl/Requests.kt | 14 + .../main/kotlin/no/nav/paw/pdl/Responses.kt | 56 ++ .../src/main/kotlin/no/nav/paw/pdl/Utils.kt | 27 + .../src/main/resources/.graphqlconfig | 4 + .../src/main/resources/hentIdenter.graphql | 8 + .../src/main/resources/pdl-schema.graphql | 865 ++++++++++++++++++ .../test/kotlin/no/nav/paw/pdl/MockUtils.kt | 46 + .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 25 + .../src/test/resources/error-response.json | 14 + .../resources/hentFullPerson-response.json | 97 ++ .../test/resources/hentIdenter-response.json | 16 + 26 files changed, 1837 insertions(+) create mode 100644 .gitignore create mode 100644 paw-pdl-client/.editorconfig create mode 100644 paw-pdl-client/.github/workflows/main.yml create mode 100644 paw-pdl-client/.github/workflows/test.yml create mode 100644 paw-pdl-client/.gitignore create mode 100644 paw-pdl-client/build.gradle.kts create mode 100644 paw-pdl-client/gradle.properties create mode 100644 paw-pdl-client/gradle/wrapper/gradle-wrapper.jar create mode 100644 paw-pdl-client/gradle/wrapper/gradle-wrapper.properties create mode 100755 paw-pdl-client/gradlew create mode 100644 paw-pdl-client/gradlew.bat create mode 100644 paw-pdl-client/settings.gradle.kts create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt create mode 100644 paw-pdl-client/src/main/resources/.graphqlconfig create mode 100644 paw-pdl-client/src/main/resources/hentIdenter.graphql create mode 100644 paw-pdl-client/src/main/resources/pdl-schema.graphql create mode 100644 paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt create mode 100644 paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt create mode 100644 paw-pdl-client/src/test/resources/error-response.json create mode 100644 paw-pdl-client/src/test/resources/hentFullPerson-response.json create mode 100644 paw-pdl-client/src/test/resources/hentIdenter-response.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..241e4dfe --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# IDEA & Gradle +/.gradle +/.idea +/out +/lib +/build +*.iml +*.ipr +*.iws + +# Package Files # +*.jar +!gradle-wrapper.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#mac files +**/.DS_Store diff --git a/paw-pdl-client/.editorconfig b/paw-pdl-client/.editorconfig new file mode 100644 index 00000000..feef31a4 --- /dev/null +++ b/paw-pdl-client/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +# Kotlin +[**.{kt,kts}] +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace=true +insert_final_newline = true +max_line_length = 160 diff --git a/paw-pdl-client/.github/workflows/main.yml b/paw-pdl-client/.github/workflows/main.yml new file mode 100644 index 00000000..291b2cb1 --- /dev/null +++ b/paw-pdl-client/.github/workflows/main.yml @@ -0,0 +1,25 @@ +name: Build and publish + +on: + push: + branches: + - main +jobs: + build: + name: Build and push + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Verify Gradle wrapper checksum + uses: gradle/wrapper-validation-action@v1 + + - name: Build with Gradle and Publish artifact + run: ./gradlew build publish + env: + ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/paw-pdl-client/.github/workflows/test.yml b/paw-pdl-client/.github/workflows/test.yml new file mode 100644 index 00000000..096ff3ce --- /dev/null +++ b/paw-pdl-client/.github/workflows/test.yml @@ -0,0 +1,40 @@ +name: Test + +on: [pull_request] + +jobs: + Test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Cache Gradle wrapper + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle-wrapper- + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-cache-${{ hashFiles('build.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle-cache- + + - name: Build + run: ./gradlew build --info + env: + ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} + + - name: Test + run: ./gradlew test --console=plain + env: + ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/paw-pdl-client/.gitignore b/paw-pdl-client/.gitignore new file mode 100644 index 00000000..241e4dfe --- /dev/null +++ b/paw-pdl-client/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# IDEA & Gradle +/.gradle +/.idea +/out +/lib +/build +*.iml +*.ipr +*.iws + +# Package Files # +*.jar +!gradle-wrapper.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#mac files +**/.DS_Store diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts new file mode 100644 index 00000000..7b294873 --- /dev/null +++ b/paw-pdl-client/build.gradle.kts @@ -0,0 +1,75 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +group = "no.nav.paw" +version = "0.2.2" + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("org.jmailen.kotlinter") + id("maven-publish") +} + +tasks { + withType { + kotlinOptions.jvmTarget = "11" + } + test { + useJUnitPlatform() + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + + withSourcesJar() +} + +repositories { + mavenCentral() + mavenNav("*") +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + } + } + repositories { + mavenNav("paw-${rootProject.name}") + } +} + +dependencies { + val coroutinesVersion: String by project + val junitJupiterVersion: String by project + val kotlinSerializationVersion: String by project + val ktorVersion: String by project + val mockkVersion: String by project + + api("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") + + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-okhttp:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + + testImplementation("io.ktor:ktor-client-mock:$ktorVersion") + testImplementation("io.mockk:mockk:$mockkVersion") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") + testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion") +} + +fun RepositoryHandler.mavenNav(repo: String): MavenArtifactRepository { + val githubPassword: String by project + + return maven { + setUrl("https://maven.pkg.github.com/navikt/$repo") + credentials { + username = "x-access-token" + password = githubPassword + } + } +} diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties new file mode 100644 index 00000000..f3229148 --- /dev/null +++ b/paw-pdl-client/gradle.properties @@ -0,0 +1,12 @@ +kotlin.code.style=official + +# Plugin versions +kotlinVersion=1.7.10 +kotlinterVersion=3.12.0 + +# Dependency versions +coroutinesVersion=1.6.4 +junitJupiterVersion=5.9.0 +kotlinSerializationVersion=1.4.0 +ktorVersion=2.1.1 +mockkVersion=1.12.7 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar b/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/paw-pdl-client/gradlew.bat b/paw-pdl-client/gradlew.bat new file mode 100644 index 00000000..f127cfd4 --- /dev/null +++ b/paw-pdl-client/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/paw-pdl-client/settings.gradle.kts b/paw-pdl-client/settings.gradle.kts new file mode 100644 index 00000000..7a873b6e --- /dev/null +++ b/paw-pdl-client/settings.gradle.kts @@ -0,0 +1,13 @@ +rootProject.name = "pdl-client" + +pluginManagement { + val kotlinVersion: String by settings + val kotlinterVersion: String by settings + + plugins { + kotlin("jvm") version kotlinVersion + kotlin("plugin.serialization") version kotlinVersion + id("org.jmailen.kotlinter") version kotlinterVersion + id("maven-publish") + } +} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt new file mode 100644 index 00000000..cf03f220 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt @@ -0,0 +1,15 @@ +package no.nav.paw.pdl + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDate + +internal object LocalDateSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING) + override fun serialize(encoder: Encoder, value: LocalDate) = encoder.encodeString(value.toString()) + override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString()) +} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt new file mode 100644 index 00000000..cd0a5068 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt @@ -0,0 +1,15 @@ +package no.nav.paw.pdl + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDateTime + +internal object LocalDateTimeSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING) + override fun serialize(encoder: Encoder, value: LocalDateTime) = encoder.encodeString(value.toString()) + override fun deserialize(decoder: Decoder): LocalDateTime = LocalDateTime.parse(decoder.decodeString()) +} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt new file mode 100644 index 00000000..ae418921 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -0,0 +1,58 @@ +package no.nav.paw.pdl + +import io.ktor.client.call.body +import io.ktor.client.request.bearerAuth +import io.ktor.client.request.header +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import io.ktor.http.ContentType +import io.ktor.http.contentType + +/** + * Enkel GraphQL-klient for PDL som kan enten hente navn fra aktør eller fnr (ident) + * eller hente mer fullstendig data om en person via fnr eller aktørid (ident) + * + * Authorisasjon gjøres via den gitte Token prodvideren, og servicebrukeren som er angitt i token provideren må være i + * i AD-gruppen `0000-GA-TEMA_SYK` som dokumentert [her](https://pdldocs-navno.msappproxy.net/intern/index.html#_konsumentroller_basert_p%C3%A5_tema). + * + * Klienten vil alltid gi PDL-Temaet 'SYK', så om du trenger et annet tema må du endre denne klienten. + */ +class PdlClient( + private val url: String, + private val getAccessToken: () -> String +) { + private val httpClient = createHttpClient() + + private val hentIdenterQuery = "hentIdenter.graphql".readQuery() + + suspend fun hentIdenter(ident: String, userLoginToken: String? = null): String? = + PdlQuery(hentIdenterQuery, Variables(ident)) + .execute(userLoginToken) + ?.hentIdenter + ?.trekkUtIdent(PdlIdent.PdlIdentGruppe.AKTORID) + + // Funksjonen må være inline+reified for å kunne deserialisere T + private suspend inline fun PdlQuery.execute(userLoginToken: String?): T? { + val stsToken = getAccessToken() + + val response = httpClient.post(url) { + contentType(ContentType.Application.Json) + bearerAuth(userLoginToken ?: stsToken) + header("Tema", "OPP") + + setBody(this@execute) + } + .body>() + + if (!response.errors.isNullOrEmpty()) { + throw PdlException(response.errors) + } + + return response.data + } +} + +class PdlException(val errors: List?) : RuntimeException() + +private fun String.readQuery(): String = + this.readResource().replace(Regex("[\r\n]"), "") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt new file mode 100644 index 00000000..9100e326 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt @@ -0,0 +1,14 @@ +package no.nav.paw.pdl + +import kotlinx.serialization.Serializable + +@Serializable +internal data class PdlQuery( + val query: String, + val variables: Variables +) + +@Serializable +internal data class Variables( + val ident: String +) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt new file mode 100644 index 00000000..6e06128c --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt @@ -0,0 +1,56 @@ +@file:UseSerializers(LocalDateSerializer::class, LocalDateTimeSerializer::class) + +package no.nav.paw.pdl + +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers + +@Serializable +internal data class PdlResponse( + val errors: List?, + val data: T? +) + +@Serializable +data class PdlHentIdenter( + val hentIdenter: PdlIdentResponse +) + +/** + * Tilsvarer graphql-spørringen hentIdenter.graphql + */ + +@Serializable +data class PdlHentFullPerson( + val hentIdenter: PdlIdentResponse? +) + +@Serializable +data class PdlIdentResponse(val identer: List) { + fun trekkUtIdent(gruppe: PdlIdent.PdlIdentGruppe): String? = identer.firstOrNull { it.gruppe == gruppe }?.ident +} + +@Serializable +data class PdlIdent(val ident: String, val gruppe: PdlIdentGruppe) { + enum class PdlIdentGruppe { AKTORID, FOLKEREGISTERIDENT, NPID } +} + +@Serializable +data class PdlError( + val message: String, + val locations: List, + val path: List?, + val extensions: PdlErrorExtension +) + +@Serializable +data class PdlErrorLocation( + val line: Int?, + val column: Int? +) + +@Serializable +data class PdlErrorExtension( + val code: String?, + val classification: String +) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt new file mode 100644 index 00000000..03e75128 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt @@ -0,0 +1,27 @@ +package no.nav.paw.pdl + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json + +internal fun createHttpClient(): HttpClient = + HttpClient(OkHttp) { configureJsonHandler() } + +@OptIn(ExperimentalSerializationApi::class) +internal fun HttpClientConfig<*>.configureJsonHandler() { + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + explicitNulls = false + } + ) + } +} + +internal fun String.readResource(): String = + ClassLoader.getSystemResource(this).readText() diff --git a/paw-pdl-client/src/main/resources/.graphqlconfig b/paw-pdl-client/src/main/resources/.graphqlconfig new file mode 100644 index 00000000..f44e17f5 --- /dev/null +++ b/paw-pdl-client/src/main/resources/.graphqlconfig @@ -0,0 +1,4 @@ +{ + "name": "PDL GraphQL Schema", + "schemaPath": "pdl-schema.graphql" +} \ No newline at end of file diff --git a/paw-pdl-client/src/main/resources/hentIdenter.graphql b/paw-pdl-client/src/main/resources/hentIdenter.graphql new file mode 100644 index 00000000..1c9a9b3d --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentIdenter.graphql @@ -0,0 +1,8 @@ +query($ident: ID!) { + hentIdenter(ident: $ident) { + identer { + ident + gruppe + } + } +} diff --git a/paw-pdl-client/src/main/resources/pdl-schema.graphql b/paw-pdl-client/src/main/resources/pdl-schema.graphql new file mode 100644 index 00000000..7bf99a43 --- /dev/null +++ b/paw-pdl-client/src/main/resources/pdl-schema.graphql @@ -0,0 +1,865 @@ +#Fra https://github.com/navikt/pdl/blob/master/apps/api/src/main/resources/schemas/pdl.graphqls +# ISO-8601 representasjon for en kalenderdato. YYYY-MM-DD. Eksempel: 2018-01-01. +scalar Date + +# ISO-8601 representasjon for en kalenderdato med tid, trunkert til nærmeste sekund. YYYY-MM-DD'T'hh:mm:ss. Eksempel: 2018-01-01T12:00:00. +scalar DateTime + +# Schema parser kjenner ikke til Typen long men den er støttet av graphql-java, så definerer den her for at schema skal validere. +scalar Long + +schema { + query: Query +} + +type Query { + hentPerson(ident: ID!): Person + hentPersonBolk(identer: [ID!]!): [HentPersonBolkResult!]! + hentIdenter(ident: ID!, grupper: [IdentGruppe!], historikk: Boolean = false): Identliste + hentIdenterBolk(identer: [ID!]!, grupper: [IdentGruppe!], historikk: Boolean = false): [HentIdenterBolkResult!]! + hentGeografiskTilknytning(ident: ID!): GeografiskTilknytning + hentGeografiskTilknytningBolk(identer: [ID!]!): [hentGeografiskTilknytningBolkResult!]! + sokPerson(criteria:[Criterion], paging:Paging): PersonSearchResult + sokAdresse(criteria:[Criterion], paging:Paging): AdresseSearchResult + forslagAdresse(parameters:CompletionParameters): AdresseCompletionResult + hentAdresse(matrikkelId: ID!): KartverketAdresse +} + +type KartverketAdresse { + id: Long! + vegadresse: KartverketVegadresse + matrikkeladresse: KartverketMatrikkeladresse +} + +type KartverketMatrikkeladresse { + undernummer: Int + representasjonspunkt: KartverketRepresentasjonspunkt + adressetilleggsnavn: String + kortnavn: String + postnummeromraade: KartverketPostnummeromraade + grunnkrets: KartverketGrunnkrets + bydel: KartverketBydel + matrikkelnummer: KartverketMatrikkelnummer +} + +type KartverketMatrikkelnummer { + kommunenummer: String + gaardsnummer: Int + bruksnummer: Int + festenummer: Int + seksjonsnummer: Int +} + +type KartverketVegadresse { + nummer: Int + bokstav: String + representasjonspunkt: KartverketRepresentasjonspunkt + adressetilleggsnavn: String + kortnavn: String + postnummeromraade: KartverketPostnummeromraade + grunnkrets: KartverketGrunnkrets + veg: KartverketVeg + bydel: KartverketBydel +} + +type KartverketPostnummeromraade { + poststed: String + postnummer: String +} + +type KartverketGrunnkrets { + grunnkretsnavn: String + grunnkretsnummer: String +} + +type KartverketRepresentasjonspunkt { + posisjonskvalitet: Int + x: Float + y: Float + z: Float +} + +type KartverketBydel { + bydelsnavn: String + bydelsnummer: String +} + +type KartverketVeg { + adressekode: Int + adressenavn: String + kortnavn: String + stedsnummer: String + kommune: KartverketKommune +} + +type KartverketKommune { + nummer: String + navn: String + fylke: KartverketFylke +} + +type KartverketFylke { + nummer: String + navn: String +} + +type Identliste { + identer: [IdentInformasjon!]! +} + +type HentIdenterBolkResult { + ident: String! + identer: [IdentInformasjon!] + code: String! +} + +type IdentInformasjon { + ident: String! + gruppe: IdentGruppe! + historisk: Boolean! +} + +enum IdentGruppe { + AKTORID, + FOLKEREGISTERIDENT, + NPID +} + +type HentPersonBolkResult { + ident: String! + person: Person + code: String! +} + +type Person { + adressebeskyttelse(historikk: Boolean = false): [Adressebeskyttelse!]! + bostedsadresse(historikk: Boolean = false): [Bostedsadresse!]! + deltBosted(historikk: Boolean = false): [DeltBosted!]! + doedfoedtBarn: [DoedfoedtBarn!]! + doedsfall: [Doedsfall!]! + falskIdentitet: FalskIdentitet + foedsel: [Foedsel!]! + folkeregisteridentifikator(historikk: Boolean = false): [Folkeregisteridentifikator!]! + folkeregisterpersonstatus(historikk: Boolean = false): [Folkeregisterpersonstatus!]! + forelderBarnRelasjon: [ForelderBarnRelasjon!]! + foreldreansvar(historikk: Boolean = false): [Foreldreansvar!]! + fullmakt(historikk: Boolean = false): [Fullmakt!]! + identitetsgrunnlag(historikk: Boolean = false): [Identitetsgrunnlag!]! + kjoenn(historikk: Boolean = false): [Kjoenn!]! + kontaktadresse(historikk: Boolean = false): [Kontaktadresse!]! + kontaktinformasjonForDoedsbo(historikk: Boolean = false): [KontaktinformasjonForDoedsbo!]! + navn(historikk: Boolean = false): [Navn!]! + opphold(historikk: Boolean = false):[Opphold!]! + oppholdsadresse(historikk: Boolean = false):[Oppholdsadresse!]! + sikkerhetstiltak:[Sikkerhetstiltak!]! + sivilstand(historikk: Boolean = false):[Sivilstand!]! + statsborgerskap(historikk: Boolean = false): [Statsborgerskap!]! + telefonnummer: [Telefonnummer!]! + tilrettelagtKommunikasjon:[TilrettelagtKommunikasjon!]! + utenlandskIdentifikasjonsnummer(historikk: Boolean = false): [UtenlandskIdentifikasjonsnummer!]! + innflyttingTilNorge: [InnflyttingTilNorge!]! + utflyttingFraNorge: [UtflyttingFraNorge!]! + vergemaalEllerFremtidsfullmakt(historikk: Boolean = false): [VergemaalEllerFremtidsfullmakt!]! +} + +type DeltBosted { + startdatoForKontrakt: Date! + sluttdatoForKontrakt: Date + + coAdressenavn: String + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + utenlandskAdresse: UtenlandskAdresse + ukjentBosted: UkjentBosted + + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +type Bostedsadresse { + angittFlyttedato: Date + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime + + coAdressenavn: String + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + utenlandskAdresse: UtenlandskAdresse + ukjentBosted: UkjentBosted + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Oppholdsadresse { + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime + + coAdressenavn: String + utenlandskAdresse: UtenlandskAdresse + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + oppholdAnnetSted: String + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Kontaktadresse { + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime + type: KontaktadresseType! + + coAdressenavn: String + postboksadresse: Postboksadresse + vegadresse: Vegadresse + postadresseIFrittFormat: PostadresseIFrittFormat + utenlandskAdresse: UtenlandskAdresse + utenlandskAdresseIFrittFormat: UtenlandskAdresseIFrittFormat + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +enum KontaktadresseType { + Innland, + Utland +} + +type Vegadresse { + matrikkelId: Long + husnummer: String + husbokstav: String + bruksenhetsnummer: String + adressenavn: String + kommunenummer: String + bydelsnummer: String + tilleggsnavn: String + postnummer: String + koordinater: Koordinater +} + +type Matrikkeladresse { + matrikkelId: Long + bruksenhetsnummer: String + tilleggsnavn: String + postnummer: String + kommunenummer: String + koordinater: Koordinater +} + +type UkjentBosted { + bostedskommune: String +} + +type UtenlandskAdresse { + adressenavnNummer: String + bygningEtasjeLeilighet: String + postboksNummerNavn: String + postkode: String + bySted: String + regionDistriktOmraade: String + landkode: String! +} + +type UtenlandskAdresseIFrittFormat { + adresselinje1: String + adresselinje2: String + adresselinje3: String + postkode: String + byEllerStedsnavn: String + landkode: String! +} + +type Postboksadresse { + postbokseier: String + postboks: String! + postnummer: String +} + +type PostadresseIFrittFormat { + adresselinje1: String + adresselinje2: String + adresselinje3: String + postnummer: String +} + +type Koordinater { + x: Float + y: Float + z: Float + kvalitet: Int +} + +type FalskIdentitet { + erFalsk: Boolean! + rettIdentitetVedIdentifikasjonsnummer: String + rettIdentitetErUkjent: Boolean + rettIdentitetVedOpplysninger: FalskIdentitetIdentifiserendeInformasjon + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type FalskIdentitetIdentifiserendeInformasjon { + personnavn: Personnavn! + foedselsdato: Date + statsborgerskap: [String!]! + kjoenn: KjoennType +} + +type KontaktinformasjonForDoedsbo { + skifteform: KontaktinformasjonForDoedsboSkifteform! + attestutstedelsesdato: Date! + personSomKontakt: KontaktinformasjonForDoedsboPersonSomKontakt + advokatSomKontakt: KontaktinformasjonForDoedsboAdvokatSomKontakt + organisasjonSomKontakt: KontaktinformasjonForDoedsboOrganisasjonSomKontakt + adresse: KontaktinformasjonForDoedsboAdresse! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +enum KontaktinformasjonForDoedsboSkifteform { + OFFENTLIG + ANNET +} + +type KontaktinformasjonForDoedsboPersonSomKontakt { + foedselsdato: Date + personnavn: Personnavn + identifikasjonsnummer: String +} + +type KontaktinformasjonForDoedsboAdvokatSomKontakt { + personnavn: Personnavn! + organisasjonsnavn: String + organisasjonsnummer: String +} + +type KontaktinformasjonForDoedsboOrganisasjonSomKontakt { + kontaktperson: Personnavn + organisasjonsnavn: String! + organisasjonsnummer: String +} + +type KontaktinformasjonForDoedsboAdresse { + adresselinje1: String! + adresselinje2: String + poststedsnavn: String! + postnummer: String! + landkode: String +} + +type UtenlandskIdentifikasjonsnummer { + identifikasjonsnummer: String! + utstederland: String! + opphoert: Boolean! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Adressebeskyttelse { + gradering: AdressebeskyttelseGradering! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +enum AdressebeskyttelseGradering { + STRENGT_FORTROLIG_UTLAND, + STRENGT_FORTROLIG, + FORTROLIG, + UGRADERT +} + +type Foedsel { + foedselsaar: Int + foedselsdato: Date + foedeland: String + foedested: String + foedekommune: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Kjoenn { + kjoenn: KjoennType + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Doedsfall { + doedsdato: Date + metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata +} + +type ForelderBarnRelasjon { + relatertPersonsIdent: String + relatertPersonsRolle: ForelderBarnRelasjonRolle! + minRolleForPerson: ForelderBarnRelasjonRolle + relatertPersonUtenFolkeregisteridentifikator: RelatertBiPerson + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type DoedfoedtBarn { + dato: Date + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +enum Familierelasjonsrolle { + BARN, + MOR, + FAR, + MEDMOR +} + +enum ForelderBarnRelasjonRolle { + BARN, + MOR, + FAR, + MEDMOR +} + +type Folkeregisterpersonstatus { + status: String! + forenkletStatus: String! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +type GeografiskTilknytning { + gtType: GtType! + gtKommune: String + gtBydel: String + gtLand: String + regel: String! +} + +type hentGeografiskTilknytningBolkResult { + ident: String! + geografiskTilknytning: GeografiskTilknytning + code: String! +} + +enum GtType { + KOMMUNE, + BYDEL, + UTLAND, + UDEFINERT +} + +type Navn { + fornavn: String! + mellomnavn: String + etternavn: String! + forkortetNavn: String + originaltNavn: OriginaltNavn + gyldigFraOgMed: Date + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type OriginaltNavn { + fornavn: String + mellomnavn: String + etternavn: String +} + +type Personnavn { + fornavn: String! + mellomnavn: String + etternavn: String! +} + +enum KjoennType { + MANN, KVINNE, UKJENT +} + +type Identitetsgrunnlag { + status: Identitetsgrunnlagsstatus! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +enum Identitetsgrunnlagsstatus { + IKKE_KONTROLLERT + KONTROLLERT, + INGEN_STATUS +} + +type Folkeregistermetadata { + ajourholdstidspunkt: DateTime + gyldighetstidspunkt: DateTime + opphoerstidspunkt: DateTime + kilde: String + aarsak: String + sekvens: Int +} + +type Telefonnummer { + landskode: String! + nummer: String! + prioritet: Int! + metadata: Metadata! +} + +type TilrettelagtKommunikasjon { + talespraaktolk: Tolk + tegnspraaktolk: Tolk + metadata: Metadata! +} + +type Tolk { + spraak: String +} + +enum FullmaktsRolle { + FULLMAKTSGIVER, + FULLMEKTIG +} + +type Fullmakt { + motpartsPersonident: String! + motpartsRolle: FullmaktsRolle! + omraader: [String!]! + gyldigFraOgMed: Date! + gyldigTilOgMed: Date! + metadata: Metadata! +} + +type Folkeregisteridentifikator { + identifikasjonsnummer: String! + status: String! + type: String! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +type SikkerhetstiltakKontaktperson { + personident: String! + enhet: String! +} + +type Sikkerhetstiltak { + tiltakstype: String! + beskrivelse: String! + kontaktperson: SikkerhetstiltakKontaktperson + gyldigFraOgMed: Date! + gyldigTilOgMed: Date! + metadata: Metadata! +} + +type Statsborgerskap { + land: String! + bekreftelsesdato: Date + gyldigFraOgMed: Date + gyldigTilOgMed: Date + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Opphold { + type: Oppholdstillatelse! + oppholdFra: Date + oppholdTil: Date + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! +} + +enum Oppholdstillatelse { + MIDLERTIDIG + PERMANENT + OPPLYSNING_MANGLER +} + +type Sivilstand { + type: Sivilstandstype! + gyldigFraOgMed: Date + relatertVedSivilstand: String + bekreftelsesdato: Date + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +enum Sivilstandstype { + UOPPGITT + UGIFT + GIFT + ENKE_ELLER_ENKEMANN + SKILT + SEPARERT + REGISTRERT_PARTNER + SEPARERT_PARTNER + SKILT_PARTNER + GJENLEVENDE_PARTNER +} + +type InnflyttingTilNorge { + fraflyttingsland: String + fraflyttingsstedIUtlandet: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type UtflyttingFraNorge { + tilflyttingsland: String + tilflyttingsstedIUtlandet: String + utflyttingsdato: Date + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type VergeEllerFullmektig { + navn: Personnavn + motpartsPersonident: String + omfang: String + omfangetErInnenPersonligOmraade: Boolean! +} + +type VergemaalEllerFremtidsfullmakt { + type: String + embete: String + vergeEllerFullmektig: VergeEllerFullmektig! + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Foreldreansvar { + ansvar: String + ansvarlig: String + ansvarssubjekt: String + ansvarligUtenIdentifikator: RelatertBiPerson + + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type RelatertBiPerson { + navn: Personnavn + foedselsdato: Date + statsborgerskap: String + kjoenn: KjoennType +} + +type Metadata { + # I PDL så får alle forekomster av en opplysning en ID som representerer dens unike forekomst. + # F.eks, så vil en Opprett ha ID X, korriger ID Y (der hvor den spesifiserer at den korrigerer X). + # Dersom en opplysning ikke er lagret i PDL, så vil denne verdien ikke være utfylt. + opplysningsId: String + + # Master refererer til hvem som eier opplysningen, f.eks så har PDL en kopi av Folkeregisteret, da vil master være FREG og eventuelle endringer på dette må gå via Folkeregisteret (API mot dem eller andre rutiner). + master: String! + + # En liste over alle endringer som har blitt utført over tid. + # Vær obs på at denne kan endre seg og man burde takle at det finnes flere korrigeringer i listen, så dersom man ønsker å kun vise den siste, så må man selv filtrere ut dette. + # Det kan også ved svært få tilfeller skje at opprett blir fjernet. F.eks ved splitt tilfeller av identer. Dette skal skje i svært få tilfeller. Dersom man ønsker å presentere opprettet tidspunktet, så blir det tidspunktet på den første endringen. + endringer: [Endring!]! + + # Feltet betegner hvorvidt dette er en funksjonelt historisk opplysning, for eksempel en tidligere fraflyttet adresse eller et foreldreansvar som er utløpt fordi barnet har fylt 18 år. + # I de fleste tilfeller kan dette utledes ved å se på de andre feltene i opplysningen. Dette er imidlertid ikke alltid tilfellet, blant annet for foreldreansvar. + # Feltet bør brukes av konsumenter som henter informasjon fra GraphQL med historikk, men som også trenger å utlede gjeldende informasjon. + historisk: Boolean! +} + +# Endring som har blitt utført på opplysningen. F.eks: Opprett -> Korriger -> Korriger +type Endring { + # Hvilke type endring som har blitt utført. + type: Endringstype! + # Tidspunktet for registrering. + registrert: DateTime! + # Hvem endringen har blitt utført av, ofte saksbehandler (f.eks Z990200), men kan også være system (f.eks srvXXXX). Denne blir satt til "Folkeregisteret" for det vi får fra dem. + registrertAv: String! + # Hvilke system endringen har kommet fra (f.eks srvXXX). Denne blir satt til "FREG" for det vi får fra Folkeregisteret. + systemkilde: String! + # Opphavet til informasjonen. I NAV blir dette satt i forbindelse med registrering (f.eks: Sykehuskassan). + # Fra Folkeregisteret får vi opphaven til dems opplysning, altså NAV, UDI, Politiet, Skatteetaten o.l.. Fra Folkeregisteret kan det også være tekniske navn som: DSF_MIGRERING, m.m.. + kilde: String! +} + +enum Endringstype { + OPPRETT + KORRIGER + OPPHOER +} + +input Criterion { + # Feltnavn ikludert sti til ønsket felt (Eksempel: person.navn.fornavn) + fieldName:String! + + searchRule:SearchRule! + # Søk i historiske data + # true = søker kun i historiske data. + # false = søker kun i gjeldende data. + # null = søke i både historiske og gjeldende data. + searchHistorical:Boolean +} + +input SearchRule { + # Sjekker om feltet finnes / at det ikke har en null verdi. + exists:String + # Filtrerer bort treff hvor felt inneholder input verdi + notEquals:String + # Begrenser treff til kun de hvor felt har input verdi + equals:String + # Gir treff når opgitt felt inneholder en eller flere ord fra input verdien. + contains:String + # Søk som gir treff også for små variasjoner i skrivemåte + fuzzy:String + # Søk som gir tilfeldig poengsum til hvert treff (kun ment til generering av testdata) + random:String + # Bruk "?" som wildcard for enkelt tegn, og "*" som wildcard for 0 eller flere tegn. + wildcard:String + # Gir treff når opgitt feltstarter med opgitt verdi. + startsWith:String + # Regex søk for spesielle situasjoner (Dette er en treg opprasjon og bør ikke brukes) + regex:String + # Brukes til søke etter datoer som kommer etter opgitt dato. + after:String + # Brukes til søke etter datoer som kommer før opgitt dato. + before:String + # Brukes til å søke i tall og finner verdier som er mindre en input verdi. + lessThan:String + # Brukes til å søke i tall og finner verdier som er størren en input verdi. + greaterThan:String + # Søk fra og med (se fromExcluding for bare fra men ikke med) + # kan benyttes på tall og dato + from:String + # Søk til og med (se toExcluding for bare til men ikke med) + # kan benyttes på tall og dato + to:String + # Søk fra men ikke med oppgitt verdi + # kan benyttes på tall og dato + fromExcluding:String, + # Søk til men ikke med oppgitt verdi + # kan benyttes på tall og dato + toExcluding:String + + # [Flag] Kan brukes til å overstyre standard oppførsellen for søk i felter (standard er case insensitive) + caseSensitive:Boolean + # [Flag] Brukes til å deaktivere fonetisk søk feltene som har dette som standard (Navn) + disablePhonetic:Boolean + # Boost brukes til å gi ett søkekriterie høyere eller lavere vektlegging en de andre søke kriteriene. + boost:Float +} + +input Paging { + # Hvilken side i resultatsettet man ønsker vist. + pageNumber:Int = 1 + # antall treff per side (maks 100) + resultsPerPage:Int = 10 + # Liste over felter man ønsker resultatene sortert etter + # Standard er "score". Score er poengsummen Elasticsearch tildeler hvert resultat. + sortBy:[SearchSorting] +} + +input SearchSorting { + # Feltnavn ikludert sti til ønsket felt (eksepmel: person.navn.fornavn) + fieldName:String! + direction:Direction! +} +enum Direction { + ASC, + DESC +} +type PersonSearchResult { + # treff liste + hits : [PersonSearchHit!]! + # Side nummer for siden som vises + pageNumber:Int + # Totalt antall sider + totalPages:Int + # Totalt antall treff (øvre grense er satt til 10 000) + totalHits:Int + +} +type PersonSearchHit { + # forespurte data + person :Person + # forespurte data + identer(historikk: Boolean = false): [IdentInformasjon!]! + # Poengsummen elasticsearch har gitt dette resultatet (brukt til feilsøking, og tuning av søk) + score :Float + # Infromasjon om hva som ga treff i søke resultatet. + highlights:[PersonSearchHighlight] +} +type PersonSearchHighlight { + # Navn/Sti til opplysningen som ga treff. Merk at dette ikke er feltet som ga treff men opplysningen. + # F.eks. hvis du søker på person.navn.fornavn så vil opplysingen være person.navn. + opplysning:String + # Gitt att opplysningen som ga treff har en opplysningsId så vil den returneres her. + # alle søk under person skal ha opplysningsId, men søk i identer vil kunne returnere treff uten opplysningsId. + opplysningsId: String + # Forteller hvorvidt opplysningen som ga treff er markert som historisk. + historisk: Boolean + # liste med feltene og verdiene som ga treff. + # Merk at for fritekst søk så vil disse kunne referere til hjelpe felter som ikke er synelig i resultatene. + matches:[SearchMatch] +} +type SearchMatch { + # feltnavn med sti til feltet so ga treff. + field:String! + type: String + # Verdien som ga treff + fragments: [String] +} +type AdresseSearchResult { + hits : [AdresseSearchHit!]! + pageNumber:Int, + totalPages:Int + totalHits:Int + +} +type AdresseSearchHit { + vegadresse : VegadresseResult + matrikkeladresse : MatrikkeladresseResult + score :Float +} +type VegadresseResult { + matrikkelId:String + husnummer:Int + husbokstav:String + adressenavn:String + adressekode:String + tilleggsnavn:String + fylkesnavn:String + fylkesnummer:String + kommunenavn:String + kommunenummer:String + postnummer:String + poststed:String + bydelsnavn:String + bydelsnummer:String +} +type MatrikkeladresseResult { + matrikkelId:String + tilleggsnavn:String + kommunenummer:String + gaardsnummer:String + bruksnummer:String + postnummer:String + poststed:String +} + +type AdresseCompletionResult { + suggestions: [String!]! + addressFound : CompletionAdresse +} +type CompletionAdresse { + vegadresse : VegadresseResult + matrikkeladresse : MatrikkeladresseResult +} + +input CompletionParameters { + + completionField: String! + maxSuggestions: Int + fieldValues: [CompletionFieldValue]! +} +input CompletionFieldValue { + fieldName: String! + fieldValue: String +} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt new file mode 100644 index 00000000..3a74961a --- /dev/null +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt @@ -0,0 +1,46 @@ +package no.nav.paw.pdl + +import io.ktor.client.HttpClient +import io.ktor.client.engine.mock.MockEngine +import io.ktor.client.engine.mock.respond +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.headersOf +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.unmockkStatic +import kotlin.reflect.KFunction + +const val MOCK_FNR = "test-ident" + +object MockResponse { + val hentIdenter = "hentIdenter-response.json".readResource() + val error = "error-response.json".readResource() +} + +fun mockPdlClient(content: String): PdlClient { + val mockEngine = MockEngine { + respond( + content = content, + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + ) + } + + val mockHttpClient = HttpClient(mockEngine) { configureJsonHandler() } + + return mockFn(::createHttpClient) { + every { createHttpClient() } returns mockHttpClient + PdlClient("url") { "fake token" } + } +} + +private fun mockFn(fn: KFunction<*>, block: () -> T): T { + mockkStatic(fn) + return try { + block() + } finally { + unmockkStatic(fn) + } +} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt new file mode 100644 index 00000000..a42c57bb --- /dev/null +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -0,0 +1,25 @@ +package no.nav.paw.pdl + +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +class PdlClientTest { + @Test + fun `Kaster PdlException ved feilrespons fra PDL`() { + assertThrows { + runBlocking { + mockPdlClient(MockResponse.error).hentIdenter(MOCK_FNR) + } + } + } + + @Test + fun `HentIdenter returnerer en identer`() { + val response = runBlocking { + mockPdlClient(MockResponse.hentIdenter).hentIdenter(MOCK_FNR) + } + assertEquals("2649500819544", response) + } +} diff --git a/paw-pdl-client/src/test/resources/error-response.json b/paw-pdl-client/src/test/resources/error-response.json new file mode 100644 index 00000000..8051f50d --- /dev/null +++ b/paw-pdl-client/src/test/resources/error-response.json @@ -0,0 +1,14 @@ +{ + "data": null, + "errors": [ + { + "message": "error message", + "locations": [{"line": null, "column": null}], + "path": null, + "extensions": { + "code": null, + "classification": "Error" + } + } + ] +} \ No newline at end of file diff --git a/paw-pdl-client/src/test/resources/hentFullPerson-response.json b/paw-pdl-client/src/test/resources/hentFullPerson-response.json new file mode 100644 index 00000000..8dd9be41 --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentFullPerson-response.json @@ -0,0 +1,97 @@ +{ + "data": { + "hentIdenter": { + "identer": [ + { + "ident": "09127821914", + "gruppe": "FOLKEREGISTERIDENT" + }, + { + "ident": "2649500819544", + "gruppe": "AKTORID" + } + ] + }, + + "hentGeografiskTilknytning": { + "gtType": "KOMMUNE", + "gtKommune": "1851", + "gtBydel": null, + "gtLand": null + }, + + "hentPerson": { + "navn": [ + { + "fornavn": "NILS", + "etternavn": "FALSKESEN", + "metadata": { + "master": "Freg" + } + } + ], + "bostedsadresse": [ + { + "gyldigFraOgMed": "2014-07-29T00:00", + "angittFlyttedato": "2014-07-29", + "vegadresse": { + "kommunenummer": "1221" + } + }, + { + "gyldigFraOgMed": "2016-02-05T00:00", + "angittFlyttedato": "2016-01-26", + "gyldigTilOgMed": null, + "vegadresse": { + "kommunenummer": "1106" + } + }, + { + "gyldigFraOgMed": "2014-02-05T00:00", + "angittFlyttedato": "2014-02-02", + "vegadresse": { + "kommunenummer": "1106" + } + }, + { + "gyldigFraOgMed": "2017-05-03T00:00", + "angittFlyttedato": "2017-05-03", + "ukjentBosted": { + "bostedskommune": "1106" + } + }, + { + "gyldigFraOgMed": "2014-05-09T00:00", + "angittFlyttedato": "2014-05-08", + "vegadresse": { + "kommunenummer": "1221" + } + }, + { + "gyldigFraOgMed": "2015-08-13T00:00", + "angittFlyttedato": "2015-08-13", + "vegadresse": { + "kommunenummer": "0626" + } + } + ], + "statsborgerskap": [ + { + "land": "NOR" + } + ], + "foedsel": [ + { + "foedselsdato": "1984-01-31" + } + ], + "doedsfall": [], + "adressebeskyttelse": [], + "kjoenn": [ + { + "kjoenn": "MANN" + } + ] + } + } +} \ No newline at end of file diff --git a/paw-pdl-client/src/test/resources/hentIdenter-response.json b/paw-pdl-client/src/test/resources/hentIdenter-response.json new file mode 100644 index 00000000..7478c75f --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentIdenter-response.json @@ -0,0 +1,16 @@ +{ + "data": { + "hentIdenter": { + "identer": [ + { + "ident": "09127821914", + "gruppe": "FOLKEREGISTERIDENT" + }, + { + "ident": "2649500819544", + "gruppe": "AKTORID" + } + ] + } + } +} \ No newline at end of file From c9a19a72f199bd117050126018bca8a69cc0d751 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Thu, 16 Feb 2023 17:27:56 +0100 Subject: [PATCH 02/64] Workflow for paw-pdl-client --- .../workflows/paw-pdl-client.yml | 7 +++- paw-pdl-client/.github/workflows/test.yml | 40 ------------------- 2 files changed, 5 insertions(+), 42 deletions(-) rename paw-pdl-client/.github/workflows/main.yml => .github/workflows/paw-pdl-client.yml (79%) delete mode 100644 paw-pdl-client/.github/workflows/test.yml diff --git a/paw-pdl-client/.github/workflows/main.yml b/.github/workflows/paw-pdl-client.yml similarity index 79% rename from paw-pdl-client/.github/workflows/main.yml rename to .github/workflows/paw-pdl-client.yml index 291b2cb1..6578c515 100644 --- a/paw-pdl-client/.github/workflows/main.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -1,9 +1,12 @@ -name: Build and publish +name: Build and publish paw-pds-client on: push: branches: - main + paths: + - 'paw-pdl-client/**' + jobs: build: name: Build and push @@ -20,6 +23,6 @@ jobs: uses: gradle/wrapper-validation-action@v1 - name: Build with Gradle and Publish artifact - run: ./gradlew build publish + run: ./paw-pdl-client/gradlew build publish env: ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/paw-pdl-client/.github/workflows/test.yml b/paw-pdl-client/.github/workflows/test.yml deleted file mode 100644 index 096ff3ce..00000000 --- a/paw-pdl-client/.github/workflows/test.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Test - -on: [pull_request] - -jobs: - Test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: temurin - cache: gradle - - - name: Cache Gradle wrapper - uses: actions/cache@v3 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-wrapper- - - - name: Cache Gradle packages - uses: actions/cache@v3 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-cache-${{ hashFiles('build.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle-cache- - - - name: Build - run: ./gradlew build --info - env: - ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} - - - name: Test - run: ./gradlew test --console=plain - env: - ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} From d651579feba7ede8819c7e266d2d3d8254915140 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Fri, 17 Feb 2023 10:22:18 +0100 Subject: [PATCH 03/64] working-directory --- .github/workflows/paw-pdl-client.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index 6578c515..a9233661 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -23,6 +23,7 @@ jobs: uses: gradle/wrapper-validation-action@v1 - name: Build with Gradle and Publish artifact - run: ./paw-pdl-client/gradlew build publish + working-directory: ./paw-pdl-client + run: ./gradlew build publish env: ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} From 45c687c0e7f8079a9c48751eacdfe0d312bfe372 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Fri, 17 Feb 2023 10:25:12 +0100 Subject: [PATCH 04/64] =?UTF-8?q?Temp=20fjern=20paths=20for=20=C3=A5=20tri?= =?UTF-8?q?gge=20kj=C3=B8ring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/paw-pdl-client.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index a9233661..aac9ee17 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -1,11 +1,10 @@ -name: Build and publish paw-pds-client +name: paw-pds-client on: push: branches: - main - paths: - - 'paw-pdl-client/**' + jobs: build: From 352e16fe8a9801797c8af4264d0140c8cf9c0a83 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Fri, 17 Feb 2023 10:36:07 +0100 Subject: [PATCH 05/64] Version & paths --- .github/workflows/paw-pdl-client.yml | 3 ++- paw-pdl-client/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index aac9ee17..e4f0fe0d 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -4,7 +4,8 @@ on: push: branches: - main - + paths: + - 'paw-pdl-client/**' jobs: build: diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 7b294873..cee9ed0a 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.2.2" +version = "0.1.0" plugins { kotlin("jvm") From 8839a3f0dfc5dd731a0c58a10a4d2824c6a32c2b Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 17 Feb 2023 10:36:39 +0100 Subject: [PATCH 06/64] Update build.gradle.kts --- paw-pdl-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index cee9ed0a..1dad8aea 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -38,7 +38,7 @@ publishing { } } repositories { - mavenNav("paw-${rootProject.name}") + mavenNav("paw-kotlin-clients") } } From b553ee9390e4fe9e056e709d314c78aaae7d2c48 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 17 Feb 2023 16:48:53 +0100 Subject: [PATCH 07/64] r: bruker expedia graphql PDL klient --- paw-pdl-client/build.gradle.kts | 22 ++++++- paw-pdl-client/gradle.properties | 2 +- paw-pdl-client/settings.gradle.kts | 2 + .../main/kotlin/no/nav/paw/pdl/HentAktorId.kt | 32 +++++++++ .../no/nav/paw/pdl/LocalDateSerializer.kt | 15 ----- .../no/nav/paw/pdl/LocalDateTimeSerializer.kt | 15 ----- .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 66 ++++++------------- .../main/kotlin/no/nav/paw/pdl/Requests.kt | 14 ---- .../main/kotlin/no/nav/paw/pdl/Responses.kt | 56 ---------------- .../test/kotlin/no/nav/paw/MockPdlClient.kt | 21 ++++++ .../test/kotlin/no/nav/paw/pdl/MockUtils.kt | 46 ------------- .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 47 +++++++++---- .../src/test/resources/error-response.json | 2 +- 13 files changed, 130 insertions(+), 210 deletions(-) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt delete mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt delete mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt delete mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt delete mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt create mode 100644 paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt delete mode 100644 paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 7b294873..faba5d40 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -6,6 +6,7 @@ version = "0.2.2" plugins { kotlin("jvm") kotlin("plugin.serialization") + id("com.expediagroup.graphql") id("org.jmailen.kotlinter") id("maven-publish") } @@ -17,6 +18,12 @@ tasks { test { useJUnitPlatform() } + lintKotlinMain { + exclude("no/nav/paw/pdl/graphql/generated/**/*.kt") + } + formatKotlinMain { + exclude("no/nav/paw/pdl/graphql/generated/**/*.kt") + } } java { @@ -42,12 +49,22 @@ publishing { } } +graphql { + client { + packageName = "no.nav.paw.pdl.graphql.generated" + // uncomment if you need schema to be local + schemaFile = File("src/main/resources/pdl-schema.graphql") + queryFiles = file("src/main/resources").listFiles()?.toList()?.filter { it.name.endsWith(".graphql") }.orEmpty() + serializer = com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer.KOTLINX + } +} + dependencies { val coroutinesVersion: String by project - val junitJupiterVersion: String by project val kotlinSerializationVersion: String by project val ktorVersion: String by project val mockkVersion: String by project + val graphQLKotlinVersion: String by project api("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") @@ -55,11 +72,12 @@ dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-okhttp:$ktorVersion") implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("com.expediagroup:graphql-kotlin-ktor-client:$graphQLKotlinVersion") testImplementation("io.ktor:ktor-client-mock:$ktorVersion") testImplementation("io.mockk:mockk:$mockkVersion") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") - testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion") + testImplementation(kotlin("test")) } fun RepositoryHandler.mavenNav(repo: String): MavenArtifactRepository { diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index f3229148..d6bde9f8 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -3,10 +3,10 @@ kotlin.code.style=official # Plugin versions kotlinVersion=1.7.10 kotlinterVersion=3.12.0 +graphQLKotlinVersion=6.4.0 # Dependency versions coroutinesVersion=1.6.4 -junitJupiterVersion=5.9.0 kotlinSerializationVersion=1.4.0 ktorVersion=2.1.1 mockkVersion=1.12.7 diff --git a/paw-pdl-client/settings.gradle.kts b/paw-pdl-client/settings.gradle.kts index 7a873b6e..ea54d589 100644 --- a/paw-pdl-client/settings.gradle.kts +++ b/paw-pdl-client/settings.gradle.kts @@ -3,11 +3,13 @@ rootProject.name = "pdl-client" pluginManagement { val kotlinVersion: String by settings val kotlinterVersion: String by settings + val graphQLKotlinVersion: String by settings plugins { kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion id("org.jmailen.kotlinter") version kotlinterVersion + id("com.expediagroup.graphql") version graphQLKotlinVersion id("maven-publish") } } diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt new file mode 100644 index 00000000..b54c8f01 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt @@ -0,0 +1,32 @@ +package no.nav.paw.pdl + +import com.expediagroup.graphql.client.types.GraphQLClientError +import no.nav.paw.pdl.graphql.generated.HentIdenter +import no.nav.paw.pdl.graphql.generated.enums.IdentGruppe +import no.nav.paw.pdl.graphql.generated.hentidenter.IdentInformasjon + +suspend fun PdlClient.hentAktorId(ident: String): String? = hentIdenter(ident) + ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } + ?.ident + +suspend fun PdlClient.hentIdenter(ident: String): List? { + val query = HentIdenter(HentIdenter.Variables(ident)) + + logger.info("Henter 'aktorId' fra PDL") + + val resultat = execute(query) + + if (!resultat.errors.isNullOrEmpty()) { + logger.error("Henter 'aktorId' fra PDL feilet med: ${resultat.errors}") + throw PdlException(resultat.errors) + } + + logger.info("Hentet 'aktorId' fra PDL") + + return resultat + .data + ?.hentIdenter + ?.identer +} + +class PdlException(val errors: List?) : RuntimeException() diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt deleted file mode 100644 index cf03f220..00000000 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateSerializer.kt +++ /dev/null @@ -1,15 +0,0 @@ -package no.nav.paw.pdl - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import java.time.LocalDate - -internal object LocalDateSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING) - override fun serialize(encoder: Encoder, value: LocalDate) = encoder.encodeString(value.toString()) - override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString()) -} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt deleted file mode 100644 index cd0a5068..00000000 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/LocalDateTimeSerializer.kt +++ /dev/null @@ -1,15 +0,0 @@ -package no.nav.paw.pdl - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import java.time.LocalDateTime - -internal object LocalDateTimeSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING) - override fun serialize(encoder: Encoder, value: LocalDateTime) = encoder.encodeString(value.toString()) - override fun deserialize(decoder: Decoder): LocalDateTime = LocalDateTime.parse(decoder.decodeString()) -} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index ae418921..a061c71f 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -1,58 +1,32 @@ package no.nav.paw.pdl -import io.ktor.client.call.body +import com.expediagroup.graphql.client.ktor.GraphQLKtorClient +import com.expediagroup.graphql.client.types.GraphQLClientRequest +import com.expediagroup.graphql.client.types.GraphQLClientResponse +import io.ktor.client.HttpClient import io.ktor.client.request.bearerAuth import io.ktor.client.request.header -import io.ktor.client.request.post -import io.ktor.client.request.setBody -import io.ktor.http.ContentType -import io.ktor.http.contentType +import org.slf4j.LoggerFactory +import java.net.URL -/** - * Enkel GraphQL-klient for PDL som kan enten hente navn fra aktør eller fnr (ident) - * eller hente mer fullstendig data om en person via fnr eller aktørid (ident) - * - * Authorisasjon gjøres via den gitte Token prodvideren, og servicebrukeren som er angitt i token provideren må være i - * i AD-gruppen `0000-GA-TEMA_SYK` som dokumentert [her](https://pdldocs-navno.msappproxy.net/intern/index.html#_konsumentroller_basert_p%C3%A5_tema). - * - * Klienten vil alltid gi PDL-Temaet 'SYK', så om du trenger et annet tema må du endre denne klienten. - */ +// Se https://pdldocs-navno.msappproxy.net/ for dokumentasjon av PDL API-et class PdlClient( - private val url: String, + url: String, + // Tema: https://confluence.adeo.no/pages/viewpage.action?pageId=309311397 + private val tema: String, + httpClient: HttpClient = createHttpClient(), private val getAccessToken: () -> String ) { - private val httpClient = createHttpClient() + internal val logger = LoggerFactory.getLogger(this::class.java) - private val hentIdenterQuery = "hentIdenter.graphql".readQuery() + private val graphQLClient = GraphQLKtorClient( + url = URL(url), + httpClient = httpClient + ) - suspend fun hentIdenter(ident: String, userLoginToken: String? = null): String? = - PdlQuery(hentIdenterQuery, Variables(ident)) - .execute(userLoginToken) - ?.hentIdenter - ?.trekkUtIdent(PdlIdent.PdlIdentGruppe.AKTORID) - - // Funksjonen må være inline+reified for å kunne deserialisere T - private suspend inline fun PdlQuery.execute(userLoginToken: String?): T? { - val stsToken = getAccessToken() - - val response = httpClient.post(url) { - contentType(ContentType.Application.Json) - bearerAuth(userLoginToken ?: stsToken) - header("Tema", "OPP") - - setBody(this@execute) - } - .body>() - - if (!response.errors.isNullOrEmpty()) { - throw PdlException(response.errors) + internal suspend fun execute(query: GraphQLClientRequest): GraphQLClientResponse = + graphQLClient.execute(query) { + bearerAuth(getAccessToken()) + header("Tema", tema) } - - return response.data - } } - -class PdlException(val errors: List?) : RuntimeException() - -private fun String.readQuery(): String = - this.readResource().replace(Regex("[\r\n]"), "") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt deleted file mode 100644 index 9100e326..00000000 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Requests.kt +++ /dev/null @@ -1,14 +0,0 @@ -package no.nav.paw.pdl - -import kotlinx.serialization.Serializable - -@Serializable -internal data class PdlQuery( - val query: String, - val variables: Variables -) - -@Serializable -internal data class Variables( - val ident: String -) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt deleted file mode 100644 index 6e06128c..00000000 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Responses.kt +++ /dev/null @@ -1,56 +0,0 @@ -@file:UseSerializers(LocalDateSerializer::class, LocalDateTimeSerializer::class) - -package no.nav.paw.pdl - -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers - -@Serializable -internal data class PdlResponse( - val errors: List?, - val data: T? -) - -@Serializable -data class PdlHentIdenter( - val hentIdenter: PdlIdentResponse -) - -/** - * Tilsvarer graphql-spørringen hentIdenter.graphql - */ - -@Serializable -data class PdlHentFullPerson( - val hentIdenter: PdlIdentResponse? -) - -@Serializable -data class PdlIdentResponse(val identer: List) { - fun trekkUtIdent(gruppe: PdlIdent.PdlIdentGruppe): String? = identer.firstOrNull { it.gruppe == gruppe }?.ident -} - -@Serializable -data class PdlIdent(val ident: String, val gruppe: PdlIdentGruppe) { - enum class PdlIdentGruppe { AKTORID, FOLKEREGISTERIDENT, NPID } -} - -@Serializable -data class PdlError( - val message: String, - val locations: List, - val path: List?, - val extensions: PdlErrorExtension -) - -@Serializable -data class PdlErrorLocation( - val line: Int?, - val column: Int? -) - -@Serializable -data class PdlErrorExtension( - val code: String?, - val classification: String -) diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt new file mode 100644 index 00000000..85be0ca5 --- /dev/null +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -0,0 +1,21 @@ +package no.nav.paw + +import io.ktor.client.HttpClient +import io.ktor.client.engine.mock.MockEngine +import io.ktor.client.engine.mock.respond +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.headersOf +import no.nav.paw.pdl.PdlClient + +fun mockPdlClient(content: String): PdlClient { + val mockEngine = MockEngine { + respond( + content = content, + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + ) + } + return PdlClient("https://url", "teama", HttpClient(mockEngine)) { "fake token" } +} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt deleted file mode 100644 index 3a74961a..00000000 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/MockUtils.kt +++ /dev/null @@ -1,46 +0,0 @@ -package no.nav.paw.pdl - -import io.ktor.client.HttpClient -import io.ktor.client.engine.mock.MockEngine -import io.ktor.client.engine.mock.respond -import io.ktor.http.ContentType -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.headersOf -import io.mockk.every -import io.mockk.mockkStatic -import io.mockk.unmockkStatic -import kotlin.reflect.KFunction - -const val MOCK_FNR = "test-ident" - -object MockResponse { - val hentIdenter = "hentIdenter-response.json".readResource() - val error = "error-response.json".readResource() -} - -fun mockPdlClient(content: String): PdlClient { - val mockEngine = MockEngine { - respond( - content = content, - status = HttpStatusCode.OK, - headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - ) - } - - val mockHttpClient = HttpClient(mockEngine) { configureJsonHandler() } - - return mockFn(::createHttpClient) { - every { createHttpClient() } returns mockHttpClient - PdlClient("url") { "fake token" } - } -} - -private fun mockFn(fn: KFunction<*>, block: () -> T): T { - mockkStatic(fn) - return try { - block() - } finally { - unmockkStatic(fn) - } -} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index a42c57bb..d5a81edf 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -1,25 +1,44 @@ package no.nav.paw.pdl import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - +import no.nav.paw.mockPdlClient +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith class PdlClientTest { @Test - fun `Kaster PdlException ved feilrespons fra PDL`() { - assertThrows { - runBlocking { - mockPdlClient(MockResponse.error).hentIdenter(MOCK_FNR) + fun `Forventer gyldig respons fra hentAktorId`() { + val response = readResource("hentIdenter-response.json") + val pdlClient = mockPdlClient(response) + val resultat = runBlocking { pdlClient.hentAktorId("2649500819544") } + + val forventet = "2649500819544" + assertEquals(forventet, resultat) + } + + @Test + fun `Forventer feilmelding fra hentIdenter`() { + val response = readResource("error-response.json") + val pdlClient = mockPdlClient(response) + assertFailsWith( + block = { + runBlocking { + pdlClient.hentIdenter("2649500819544") + } } - } + ) } @Test - fun `HentIdenter returnerer en identer`() { - val response = runBlocking { - mockPdlClient(MockResponse.hentIdenter).hentIdenter(MOCK_FNR) - } - assertEquals("2649500819544", response) + fun `Forventer gyldig respons fra hentIdenter`() { + val response = readResource("hentIdenter-response.json") + val pdlClient = mockPdlClient(response) + val resultat = runBlocking { pdlClient.hentIdenter("2649500819544") } + + val forventet = "09127821914" + assertEquals(forventet, resultat!!.first().ident) } } + +private fun readResource(filename: String) = + ClassLoader.getSystemResource(filename).readText() diff --git a/paw-pdl-client/src/test/resources/error-response.json b/paw-pdl-client/src/test/resources/error-response.json index 8051f50d..e9b63be1 100644 --- a/paw-pdl-client/src/test/resources/error-response.json +++ b/paw-pdl-client/src/test/resources/error-response.json @@ -3,7 +3,7 @@ "errors": [ { "message": "error message", - "locations": [{"line": null, "column": null}], + "locations": null, "path": null, "extensions": { "code": null, From f0151b700af1a34639f1f64c48f905ee2c2038be Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 17 Feb 2023 20:28:07 +0100 Subject: [PATCH 08/64] r: oppdaterer versjon --- paw-pdl-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index ddb13923..02b90f4c 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.1.0" +version = "0.1.1" plugins { kotlin("jvm") From fbcee6afbfc12b5ef32d567d6eb090e76e8ee971 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 17 Feb 2023 21:21:42 +0100 Subject: [PATCH 09/64] r: oppdaterer versjon --- paw-pdl-client/README.md | 60 +++++++++++++++++++ paw-pdl-client/build.gradle.kts | 2 +- .../main/kotlin/no/nav/paw/pdl/HentAktorId.kt | 3 - .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 3 + .../src/main/kotlin/no/nav/paw/pdl/Utils.kt | 3 - .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 17 +++--- 6 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 paw-pdl-client/README.md diff --git a/paw-pdl-client/README.md b/paw-pdl-client/README.md new file mode 100644 index 00000000..87b72dc7 --- /dev/null +++ b/paw-pdl-client/README.md @@ -0,0 +1,60 @@ +# paw-pdl-client + +Klient for å gjøre spørringer mot Persondataløsningen [PDL](https://pdldocs-navno.msappproxy.net/ekstern/index.html). + +### Bruk av paw-pdl-client + +**_gradle.build.kts_** + +```kts +dependencies { + implementation("no.nav.paw.pdl-client:${Versions.pdlClient}") +} +``` + +### Klienten instansieres slik + +For mer informasjon om tema-koder [sjekk her](https://confluence.adeo.no/pages/viewpage.action?pageId=309311397). + +```kt +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import no.nav.paw.tokenprovier.OAuth2TokenProvider +import no.nav.paw.pdl-client.PdlCLient + +fun main() { + val url = "http://pdl-api.default.svc.nais.local/graphql" + val accessTokenProvider = RestSTSAccessTokenProvider() + + val pdlClient = pdlClient(url, "tema", accessTokenProvider::getToken) + + val result = runBlocking { pdlClient.hentAktorId("fnr") } + println(result) +} +``` + +### Lokal utvikling + +For å teste klienten-endringer i en annen applikasjon uten å publisere remote, kjør: + +```sh +./gradlew publishToMavenLocal +``` + +Pakken blir da publisert til lokalt repository, husk at du må legge til `mavenLocal()` i applikasjonen: + +```dsl +repositories { + mavenLocal() + mavenCentral() +} +``` + +### Henvendelser + +Spørsmål knyttet til koden eller prosjektet kan rettes mot: + +- Jonas Enge + +### For NAV-ansatte + +Interne henvendelser kan sendes via Slack i kanalen #team-paw-dev. diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 02b90f4c..6b36c446 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.1.1" +version = "0.1.2" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt index b54c8f01..de8532ec 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt @@ -1,6 +1,5 @@ package no.nav.paw.pdl -import com.expediagroup.graphql.client.types.GraphQLClientError import no.nav.paw.pdl.graphql.generated.HentIdenter import no.nav.paw.pdl.graphql.generated.enums.IdentGruppe import no.nav.paw.pdl.graphql.generated.hentidenter.IdentInformasjon @@ -28,5 +27,3 @@ suspend fun PdlClient.hentIdenter(ident: String): List? { ?.hentIdenter ?.identer } - -class PdlException(val errors: List?) : RuntimeException() diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index a061c71f..e104b505 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -1,6 +1,7 @@ package no.nav.paw.pdl import com.expediagroup.graphql.client.ktor.GraphQLKtorClient +import com.expediagroup.graphql.client.types.GraphQLClientError import com.expediagroup.graphql.client.types.GraphQLClientRequest import com.expediagroup.graphql.client.types.GraphQLClientResponse import io.ktor.client.HttpClient @@ -30,3 +31,5 @@ class PdlClient( header("Tema", tema) } } + +class PdlException(val errors: List?) : RuntimeException() diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt index 03e75128..cda7635e 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt @@ -22,6 +22,3 @@ internal fun HttpClientConfig<*>.configureJsonHandler() { ) } } - -internal fun String.readResource(): String = - ClassLoader.getSystemResource(this).readText() diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index d5a81edf..21a59491 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -5,21 +5,22 @@ import no.nav.paw.mockPdlClient import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith + class PdlClientTest { @Test fun `Forventer gyldig respons fra hentAktorId`() { - val response = readResource("hentIdenter-response.json") - val pdlClient = mockPdlClient(response) - val resultat = runBlocking { pdlClient.hentAktorId("2649500819544") } + val respons = readResource("hentIdenter-response.json") + val pdlClient = mockPdlClient(respons) + val resultat = runBlocking { pdlClient.hentAktorId("2649500819544") } val forventet = "2649500819544" assertEquals(forventet, resultat) } @Test fun `Forventer feilmelding fra hentIdenter`() { - val response = readResource("error-response.json") - val pdlClient = mockPdlClient(response) + val respons = readResource("error-response.json") + val pdlClient = mockPdlClient(respons) assertFailsWith( block = { runBlocking { @@ -31,10 +32,10 @@ class PdlClientTest { @Test fun `Forventer gyldig respons fra hentIdenter`() { - val response = readResource("hentIdenter-response.json") - val pdlClient = mockPdlClient(response) - val resultat = runBlocking { pdlClient.hentIdenter("2649500819544") } + val respons = readResource("hentIdenter-response.json") + val pdlClient = mockPdlClient(respons) + val resultat = runBlocking { pdlClient.hentIdenter("2649500819544") } val forventet = "09127821914" assertEquals(forventet, resultat!!.first().ident) } From 4db5f34874fee435774855b82ac7ce1a624b6d18 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 20 Feb 2023 15:43:58 +0100 Subject: [PATCH 10/64] PdlClient: inn-parameter med default-verdi til slutt --- paw-pdl-client/build.gradle.kts | 2 +- paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt | 4 ++-- paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 6b36c446..020c0ea9 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.1.2" +version = "0.1.3" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index e104b505..8bfdeb2d 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -15,8 +15,8 @@ class PdlClient( url: String, // Tema: https://confluence.adeo.no/pages/viewpage.action?pageId=309311397 private val tema: String, - httpClient: HttpClient = createHttpClient(), - private val getAccessToken: () -> String + private val getAccessToken: () -> String, + httpClient: HttpClient = createHttpClient() ) { internal val logger = LoggerFactory.getLogger(this::class.java) diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt index 85be0ca5..9c8dd07f 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -17,5 +17,5 @@ fun mockPdlClient(content: String): PdlClient { headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) ) } - return PdlClient("https://url", "teama", HttpClient(mockEngine)) { "fake token" } + return PdlClient("https://url", "tema", { "fake token" }, HttpClient(mockEngine)) } From 21c9109b0fe68c2d44db0426b69bdf1da4d8d334 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 23 Feb 2023 10:16:00 +0100 Subject: [PATCH 11/64] =?UTF-8?q?r:=20endrer=20rekkef=C3=B8lge=20p=C3=A5?= =?UTF-8?q?=20http-klient=20parameter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/paw-pdl-client.yml | 2 +- paw-pdl-client/build.gradle.kts | 3 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../main/kotlin/no/nav/paw/pdl/HentAktorId.kt | 10 +- .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 4 +- .../src/main/resources/pdl-schema.graphql | 1123 +++++++++-------- .../test/kotlin/no/nav/paw/MockPdlClient.kt | 2 +- 7 files changed, 583 insertions(+), 563 deletions(-) diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index e4f0fe0d..88c2d03b 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -24,6 +24,6 @@ jobs: - name: Build with Gradle and Publish artifact working-directory: ./paw-pdl-client - run: ./gradlew build publish + run: ./gradlew build test publish env: ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 020c0ea9..c73dc0e0 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.1.3" +version = "0.1.4" plugins { kotlin("jvm") @@ -52,7 +52,6 @@ publishing { graphql { client { packageName = "no.nav.paw.pdl.graphql.generated" - // uncomment if you need schema to be local schemaFile = File("src/main/resources/pdl-schema.graphql") queryFiles = file("src/main/resources").listFiles()?.toList()?.filter { it.name.endsWith(".graphql") }.orEmpty() serializer = com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer.KOTLINX diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties index ae04661e..f72df95a 100644 --- a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties +++ b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt index de8532ec..b14837f8 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt @@ -13,16 +13,16 @@ suspend fun PdlClient.hentIdenter(ident: String): List? { logger.info("Henter 'aktorId' fra PDL") - val resultat = execute(query) + val respons = execute(query) - if (!resultat.errors.isNullOrEmpty()) { - logger.error("Henter 'aktorId' fra PDL feilet med: ${resultat.errors}") - throw PdlException(resultat.errors) + respons.errors?.let { + logger.error("Henter 'aktorId' fra PDL feilet med: ${respons.errors}") + throw PdlException(it) } logger.info("Hentet 'aktorId' fra PDL") - return resultat + return respons .data ?.hentIdenter ?.identer diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index 8bfdeb2d..3d4c5e08 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -15,8 +15,8 @@ class PdlClient( url: String, // Tema: https://confluence.adeo.no/pages/viewpage.action?pageId=309311397 private val tema: String, - private val getAccessToken: () -> String, - httpClient: HttpClient = createHttpClient() + httpClient: HttpClient, + private val getAccessToken: () -> String ) { internal val logger = LoggerFactory.getLogger(this::class.java) diff --git a/paw-pdl-client/src/main/resources/pdl-schema.graphql b/paw-pdl-client/src/main/resources/pdl-schema.graphql index 7bf99a43..3001ef13 100644 --- a/paw-pdl-client/src/main/resources/pdl-schema.graphql +++ b/paw-pdl-client/src/main/resources/pdl-schema.graphql @@ -1,4 +1,4 @@ -#Fra https://github.com/navikt/pdl/blob/master/apps/api/src/main/resources/schemas/pdl.graphqls +# Hentet fra https://raw.githubusercontent.com/navikt/pdl/master/apps/api/src/main/resources/schemas/pdl.graphqls # ISO-8601 representasjon for en kalenderdato. YYYY-MM-DD. Eksempel: 2018-01-01. scalar Date @@ -9,857 +9,878 @@ scalar DateTime scalar Long schema { - query: Query + query: Query } type Query { - hentPerson(ident: ID!): Person - hentPersonBolk(identer: [ID!]!): [HentPersonBolkResult!]! - hentIdenter(ident: ID!, grupper: [IdentGruppe!], historikk: Boolean = false): Identliste - hentIdenterBolk(identer: [ID!]!, grupper: [IdentGruppe!], historikk: Boolean = false): [HentIdenterBolkResult!]! - hentGeografiskTilknytning(ident: ID!): GeografiskTilknytning - hentGeografiskTilknytningBolk(identer: [ID!]!): [hentGeografiskTilknytningBolkResult!]! - sokPerson(criteria:[Criterion], paging:Paging): PersonSearchResult - sokAdresse(criteria:[Criterion], paging:Paging): AdresseSearchResult - forslagAdresse(parameters:CompletionParameters): AdresseCompletionResult - hentAdresse(matrikkelId: ID!): KartverketAdresse + hentPerson(ident: ID!): Person + hentPersonBolk(identer: [ID!]!): [HentPersonBolkResult!]! + hentIdenter( + ident: ID! + grupper: [IdentGruppe!] + historikk: Boolean = false + ): Identliste + hentIdenterBolk( + identer: [ID!]! + grupper: [IdentGruppe!] + historikk: Boolean = false + ): [HentIdenterBolkResult!]! + hentGeografiskTilknytning(ident: ID!): GeografiskTilknytning + hentGeografiskTilknytningBolk( + identer: [ID!]! + ): [hentGeografiskTilknytningBolkResult!]! + sokPerson(criteria: [Criterion], paging: Paging): PersonSearchResult + sokAdresse(criteria: [Criterion], paging: Paging): AdresseSearchResult + forslagAdresse(parameters: CompletionParameters): AdresseCompletionResult + hentAdresse(matrikkelId: ID!): KartverketAdresse } type KartverketAdresse { - id: Long! - vegadresse: KartverketVegadresse - matrikkeladresse: KartverketMatrikkeladresse + id: Long! + vegadresse: KartverketVegadresse + matrikkeladresse: KartverketMatrikkeladresse } type KartverketMatrikkeladresse { - undernummer: Int - representasjonspunkt: KartverketRepresentasjonspunkt - adressetilleggsnavn: String - kortnavn: String - postnummeromraade: KartverketPostnummeromraade - grunnkrets: KartverketGrunnkrets - bydel: KartverketBydel - matrikkelnummer: KartverketMatrikkelnummer + undernummer: Int + representasjonspunkt: KartverketRepresentasjonspunkt + adressetilleggsnavn: String + kortnavn: String + postnummeromraade: KartverketPostnummeromraade + grunnkrets: KartverketGrunnkrets + bydel: KartverketBydel + matrikkelnummer: KartverketMatrikkelnummer } type KartverketMatrikkelnummer { - kommunenummer: String - gaardsnummer: Int - bruksnummer: Int - festenummer: Int - seksjonsnummer: Int + kommunenummer: String + gaardsnummer: Int + bruksnummer: Int + festenummer: Int + seksjonsnummer: Int } type KartverketVegadresse { - nummer: Int - bokstav: String - representasjonspunkt: KartverketRepresentasjonspunkt - adressetilleggsnavn: String - kortnavn: String - postnummeromraade: KartverketPostnummeromraade - grunnkrets: KartverketGrunnkrets - veg: KartverketVeg - bydel: KartverketBydel + nummer: Int + bokstav: String + representasjonspunkt: KartverketRepresentasjonspunkt + adressetilleggsnavn: String + kortnavn: String + postnummeromraade: KartverketPostnummeromraade + grunnkrets: KartverketGrunnkrets + veg: KartverketVeg + bydel: KartverketBydel } type KartverketPostnummeromraade { - poststed: String - postnummer: String + poststed: String + postnummer: String } type KartverketGrunnkrets { - grunnkretsnavn: String - grunnkretsnummer: String + grunnkretsnavn: String + grunnkretsnummer: String } type KartverketRepresentasjonspunkt { - posisjonskvalitet: Int - x: Float - y: Float - z: Float + posisjonskvalitet: Int + x: Float + y: Float + z: Float } type KartverketBydel { - bydelsnavn: String - bydelsnummer: String + bydelsnavn: String + bydelsnummer: String } type KartverketVeg { - adressekode: Int - adressenavn: String - kortnavn: String - stedsnummer: String - kommune: KartverketKommune + adressekode: Int + adressenavn: String + kortnavn: String + stedsnummer: String + kommune: KartverketKommune } type KartverketKommune { - nummer: String - navn: String - fylke: KartverketFylke + nummer: String + navn: String + fylke: KartverketFylke } type KartverketFylke { - nummer: String - navn: String + nummer: String + navn: String } type Identliste { - identer: [IdentInformasjon!]! + identer: [IdentInformasjon!]! } type HentIdenterBolkResult { - ident: String! - identer: [IdentInformasjon!] - code: String! + ident: String! + identer: [IdentInformasjon!] + code: String! } type IdentInformasjon { - ident: String! - gruppe: IdentGruppe! - historisk: Boolean! + ident: String! + gruppe: IdentGruppe! + historisk: Boolean! } enum IdentGruppe { - AKTORID, - FOLKEREGISTERIDENT, - NPID + AKTORID + FOLKEREGISTERIDENT + NPID } type HentPersonBolkResult { - ident: String! - person: Person - code: String! + ident: String! + person: Person + code: String! } type Person { - adressebeskyttelse(historikk: Boolean = false): [Adressebeskyttelse!]! - bostedsadresse(historikk: Boolean = false): [Bostedsadresse!]! - deltBosted(historikk: Boolean = false): [DeltBosted!]! - doedfoedtBarn: [DoedfoedtBarn!]! - doedsfall: [Doedsfall!]! - falskIdentitet: FalskIdentitet - foedsel: [Foedsel!]! - folkeregisteridentifikator(historikk: Boolean = false): [Folkeregisteridentifikator!]! - folkeregisterpersonstatus(historikk: Boolean = false): [Folkeregisterpersonstatus!]! - forelderBarnRelasjon: [ForelderBarnRelasjon!]! - foreldreansvar(historikk: Boolean = false): [Foreldreansvar!]! - fullmakt(historikk: Boolean = false): [Fullmakt!]! - identitetsgrunnlag(historikk: Boolean = false): [Identitetsgrunnlag!]! - kjoenn(historikk: Boolean = false): [Kjoenn!]! - kontaktadresse(historikk: Boolean = false): [Kontaktadresse!]! - kontaktinformasjonForDoedsbo(historikk: Boolean = false): [KontaktinformasjonForDoedsbo!]! - navn(historikk: Boolean = false): [Navn!]! - opphold(historikk: Boolean = false):[Opphold!]! - oppholdsadresse(historikk: Boolean = false):[Oppholdsadresse!]! - sikkerhetstiltak:[Sikkerhetstiltak!]! - sivilstand(historikk: Boolean = false):[Sivilstand!]! - statsborgerskap(historikk: Boolean = false): [Statsborgerskap!]! - telefonnummer: [Telefonnummer!]! - tilrettelagtKommunikasjon:[TilrettelagtKommunikasjon!]! - utenlandskIdentifikasjonsnummer(historikk: Boolean = false): [UtenlandskIdentifikasjonsnummer!]! - innflyttingTilNorge: [InnflyttingTilNorge!]! - utflyttingFraNorge: [UtflyttingFraNorge!]! - vergemaalEllerFremtidsfullmakt(historikk: Boolean = false): [VergemaalEllerFremtidsfullmakt!]! + adressebeskyttelse(historikk: Boolean = false): [Adressebeskyttelse!]! + bostedsadresse(historikk: Boolean = false): [Bostedsadresse!]! + deltBosted(historikk: Boolean = false): [DeltBosted!]! + doedfoedtBarn: [DoedfoedtBarn!]! + doedsfall: [Doedsfall!]! + falskIdentitet: FalskIdentitet + foedsel: [Foedsel!]! + folkeregisteridentifikator( + historikk: Boolean = false + ): [Folkeregisteridentifikator!]! + folkeregisterpersonstatus( + historikk: Boolean = false + ): [Folkeregisterpersonstatus!]! + forelderBarnRelasjon: [ForelderBarnRelasjon!]! + foreldreansvar(historikk: Boolean = false): [Foreldreansvar!]! + fullmakt(historikk: Boolean = false): [Fullmakt!]! + identitetsgrunnlag(historikk: Boolean = false): [Identitetsgrunnlag!]! + kjoenn(historikk: Boolean = false): [Kjoenn!]! + kontaktadresse(historikk: Boolean = false): [Kontaktadresse!]! + kontaktinformasjonForDoedsbo( + historikk: Boolean = false + ): [KontaktinformasjonForDoedsbo!]! + navn(historikk: Boolean = false): [Navn!]! + opphold(historikk: Boolean = false): [Opphold!]! + oppholdsadresse(historikk: Boolean = false): [Oppholdsadresse!]! + sikkerhetstiltak: [Sikkerhetstiltak!]! + sivilstand(historikk: Boolean = false): [Sivilstand!]! + statsborgerskap(historikk: Boolean = false): [Statsborgerskap!]! + telefonnummer: [Telefonnummer!]! + tilrettelagtKommunikasjon: [TilrettelagtKommunikasjon!]! + utenlandskIdentifikasjonsnummer( + historikk: Boolean = false + ): [UtenlandskIdentifikasjonsnummer!]! + innflyttingTilNorge: [InnflyttingTilNorge!]! + utflyttingFraNorge: [UtflyttingFraNorge!]! + vergemaalEllerFremtidsfullmakt( + historikk: Boolean = false + ): [VergemaalEllerFremtidsfullmakt!]! } type DeltBosted { - startdatoForKontrakt: Date! - sluttdatoForKontrakt: Date + startdatoForKontrakt: Date! + sluttdatoForKontrakt: Date - coAdressenavn: String - vegadresse: Vegadresse - matrikkeladresse: Matrikkeladresse - utenlandskAdresse: UtenlandskAdresse - ukjentBosted: UkjentBosted + coAdressenavn: String + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + utenlandskAdresse: UtenlandskAdresse + ukjentBosted: UkjentBosted - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } type Bostedsadresse { - angittFlyttedato: Date - gyldigFraOgMed: DateTime - gyldigTilOgMed: DateTime + angittFlyttedato: Date + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime - coAdressenavn: String - vegadresse: Vegadresse - matrikkeladresse: Matrikkeladresse - utenlandskAdresse: UtenlandskAdresse - ukjentBosted: UkjentBosted + coAdressenavn: String + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + utenlandskAdresse: UtenlandskAdresse + ukjentBosted: UkjentBosted - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Oppholdsadresse { - gyldigFraOgMed: DateTime - gyldigTilOgMed: DateTime + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime - coAdressenavn: String - utenlandskAdresse: UtenlandskAdresse - vegadresse: Vegadresse - matrikkeladresse: Matrikkeladresse - oppholdAnnetSted: String + coAdressenavn: String + utenlandskAdresse: UtenlandskAdresse + vegadresse: Vegadresse + matrikkeladresse: Matrikkeladresse + oppholdAnnetSted: String - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Kontaktadresse { - gyldigFraOgMed: DateTime - gyldigTilOgMed: DateTime - type: KontaktadresseType! + gyldigFraOgMed: DateTime + gyldigTilOgMed: DateTime + type: KontaktadresseType! - coAdressenavn: String - postboksadresse: Postboksadresse - vegadresse: Vegadresse - postadresseIFrittFormat: PostadresseIFrittFormat - utenlandskAdresse: UtenlandskAdresse - utenlandskAdresseIFrittFormat: UtenlandskAdresseIFrittFormat + coAdressenavn: String + postboksadresse: Postboksadresse + vegadresse: Vegadresse + postadresseIFrittFormat: PostadresseIFrittFormat + utenlandskAdresse: UtenlandskAdresse + utenlandskAdresseIFrittFormat: UtenlandskAdresseIFrittFormat - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } enum KontaktadresseType { - Innland, - Utland + Innland + Utland } type Vegadresse { - matrikkelId: Long - husnummer: String - husbokstav: String - bruksenhetsnummer: String - adressenavn: String - kommunenummer: String - bydelsnummer: String - tilleggsnavn: String - postnummer: String - koordinater: Koordinater + matrikkelId: Long + husnummer: String + husbokstav: String + bruksenhetsnummer: String + adressenavn: String + kommunenummer: String + bydelsnummer: String + tilleggsnavn: String + postnummer: String + koordinater: Koordinater } type Matrikkeladresse { - matrikkelId: Long - bruksenhetsnummer: String - tilleggsnavn: String - postnummer: String - kommunenummer: String - koordinater: Koordinater + matrikkelId: Long + bruksenhetsnummer: String + tilleggsnavn: String + postnummer: String + kommunenummer: String + koordinater: Koordinater } type UkjentBosted { - bostedskommune: String + bostedskommune: String } type UtenlandskAdresse { - adressenavnNummer: String - bygningEtasjeLeilighet: String - postboksNummerNavn: String - postkode: String - bySted: String - regionDistriktOmraade: String - landkode: String! + adressenavnNummer: String + bygningEtasjeLeilighet: String + postboksNummerNavn: String + postkode: String + bySted: String + regionDistriktOmraade: String + landkode: String! } type UtenlandskAdresseIFrittFormat { - adresselinje1: String - adresselinje2: String - adresselinje3: String - postkode: String - byEllerStedsnavn: String - landkode: String! + adresselinje1: String + adresselinje2: String + adresselinje3: String + postkode: String + byEllerStedsnavn: String + landkode: String! } type Postboksadresse { - postbokseier: String - postboks: String! - postnummer: String + postbokseier: String + postboks: String! + postnummer: String } type PostadresseIFrittFormat { - adresselinje1: String - adresselinje2: String - adresselinje3: String - postnummer: String + adresselinje1: String + adresselinje2: String + adresselinje3: String + postnummer: String } type Koordinater { - x: Float - y: Float - z: Float - kvalitet: Int + x: Float + y: Float + z: Float + kvalitet: Int } type FalskIdentitet { - erFalsk: Boolean! - rettIdentitetVedIdentifikasjonsnummer: String - rettIdentitetErUkjent: Boolean - rettIdentitetVedOpplysninger: FalskIdentitetIdentifiserendeInformasjon - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + erFalsk: Boolean! + rettIdentitetVedIdentifikasjonsnummer: String + rettIdentitetErUkjent: Boolean + rettIdentitetVedOpplysninger: FalskIdentitetIdentifiserendeInformasjon + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type FalskIdentitetIdentifiserendeInformasjon { - personnavn: Personnavn! - foedselsdato: Date - statsborgerskap: [String!]! - kjoenn: KjoennType + personnavn: Personnavn! + foedselsdato: Date + statsborgerskap: [String!]! + kjoenn: KjoennType } type KontaktinformasjonForDoedsbo { - skifteform: KontaktinformasjonForDoedsboSkifteform! - attestutstedelsesdato: Date! - personSomKontakt: KontaktinformasjonForDoedsboPersonSomKontakt - advokatSomKontakt: KontaktinformasjonForDoedsboAdvokatSomKontakt - organisasjonSomKontakt: KontaktinformasjonForDoedsboOrganisasjonSomKontakt - adresse: KontaktinformasjonForDoedsboAdresse! - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + skifteform: KontaktinformasjonForDoedsboSkifteform! + attestutstedelsesdato: Date! + personSomKontakt: KontaktinformasjonForDoedsboPersonSomKontakt + advokatSomKontakt: KontaktinformasjonForDoedsboAdvokatSomKontakt + organisasjonSomKontakt: KontaktinformasjonForDoedsboOrganisasjonSomKontakt + adresse: KontaktinformasjonForDoedsboAdresse! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } enum KontaktinformasjonForDoedsboSkifteform { - OFFENTLIG - ANNET + OFFENTLIG + ANNET } type KontaktinformasjonForDoedsboPersonSomKontakt { - foedselsdato: Date - personnavn: Personnavn - identifikasjonsnummer: String + foedselsdato: Date + personnavn: Personnavn + identifikasjonsnummer: String } type KontaktinformasjonForDoedsboAdvokatSomKontakt { - personnavn: Personnavn! - organisasjonsnavn: String - organisasjonsnummer: String + personnavn: Personnavn! + organisasjonsnavn: String + organisasjonsnummer: String } type KontaktinformasjonForDoedsboOrganisasjonSomKontakt { - kontaktperson: Personnavn - organisasjonsnavn: String! - organisasjonsnummer: String + kontaktperson: Personnavn + organisasjonsnavn: String! + organisasjonsnummer: String } type KontaktinformasjonForDoedsboAdresse { - adresselinje1: String! - adresselinje2: String - poststedsnavn: String! - postnummer: String! - landkode: String + adresselinje1: String! + adresselinje2: String + poststedsnavn: String! + postnummer: String! + landkode: String } type UtenlandskIdentifikasjonsnummer { - identifikasjonsnummer: String! - utstederland: String! - opphoert: Boolean! - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + identifikasjonsnummer: String! + utstederland: String! + opphoert: Boolean! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Adressebeskyttelse { - gradering: AdressebeskyttelseGradering! - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + gradering: AdressebeskyttelseGradering! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } enum AdressebeskyttelseGradering { - STRENGT_FORTROLIG_UTLAND, - STRENGT_FORTROLIG, - FORTROLIG, - UGRADERT + STRENGT_FORTROLIG_UTLAND + STRENGT_FORTROLIG + FORTROLIG + UGRADERT } type Foedsel { - foedselsaar: Int - foedselsdato: Date - foedeland: String - foedested: String - foedekommune: String - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + foedselsaar: Int + foedselsdato: Date + foedeland: String + foedested: String + foedekommune: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Kjoenn { - kjoenn: KjoennType - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + kjoenn: KjoennType + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Doedsfall { - doedsdato: Date - metadata: Metadata! - folkeregistermetadata: Folkeregistermetadata + doedsdato: Date + metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata } type ForelderBarnRelasjon { - relatertPersonsIdent: String - relatertPersonsRolle: ForelderBarnRelasjonRolle! - minRolleForPerson: ForelderBarnRelasjonRolle - relatertPersonUtenFolkeregisteridentifikator: RelatertBiPerson - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + relatertPersonsIdent: String + relatertPersonsRolle: ForelderBarnRelasjonRolle! + minRolleForPerson: ForelderBarnRelasjonRolle + relatertPersonUtenFolkeregisteridentifikator: RelatertBiPerson + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type DoedfoedtBarn { - dato: Date - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + dato: Date + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } enum Familierelasjonsrolle { - BARN, - MOR, - FAR, - MEDMOR + BARN + MOR + FAR + MEDMOR } enum ForelderBarnRelasjonRolle { - BARN, - MOR, - FAR, - MEDMOR + BARN + MOR + FAR + MEDMOR } type Folkeregisterpersonstatus { - status: String! - forenkletStatus: String! - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + status: String! + forenkletStatus: String! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } type GeografiskTilknytning { - gtType: GtType! - gtKommune: String - gtBydel: String - gtLand: String - regel: String! + gtType: GtType! + gtKommune: String + gtBydel: String + gtLand: String + regel: String! } type hentGeografiskTilknytningBolkResult { - ident: String! - geografiskTilknytning: GeografiskTilknytning - code: String! + ident: String! + geografiskTilknytning: GeografiskTilknytning + code: String! } enum GtType { - KOMMUNE, - BYDEL, - UTLAND, - UDEFINERT + KOMMUNE + BYDEL + UTLAND + UDEFINERT } type Navn { - fornavn: String! - mellomnavn: String - etternavn: String! - forkortetNavn: String - originaltNavn: OriginaltNavn - gyldigFraOgMed: Date + fornavn: String! + mellomnavn: String + etternavn: String! + forkortetNavn: String + originaltNavn: OriginaltNavn + gyldigFraOgMed: Date - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type OriginaltNavn { - fornavn: String - mellomnavn: String - etternavn: String + fornavn: String + mellomnavn: String + etternavn: String } type Personnavn { - fornavn: String! - mellomnavn: String - etternavn: String! + fornavn: String! + mellomnavn: String + etternavn: String! } enum KjoennType { - MANN, KVINNE, UKJENT + MANN + KVINNE + UKJENT } type Identitetsgrunnlag { - status: Identitetsgrunnlagsstatus! - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + status: Identitetsgrunnlagsstatus! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } enum Identitetsgrunnlagsstatus { - IKKE_KONTROLLERT - KONTROLLERT, - INGEN_STATUS + IKKE_KONTROLLERT + KONTROLLERT + INGEN_STATUS } type Folkeregistermetadata { - ajourholdstidspunkt: DateTime - gyldighetstidspunkt: DateTime - opphoerstidspunkt: DateTime - kilde: String - aarsak: String - sekvens: Int + ajourholdstidspunkt: DateTime + gyldighetstidspunkt: DateTime + opphoerstidspunkt: DateTime + kilde: String + aarsak: String + sekvens: Int } type Telefonnummer { - landskode: String! - nummer: String! - prioritet: Int! - metadata: Metadata! + landskode: String! + nummer: String! + prioritet: Int! + metadata: Metadata! } type TilrettelagtKommunikasjon { - talespraaktolk: Tolk - tegnspraaktolk: Tolk - metadata: Metadata! + talespraaktolk: Tolk + tegnspraaktolk: Tolk + metadata: Metadata! } type Tolk { - spraak: String + spraak: String } enum FullmaktsRolle { - FULLMAKTSGIVER, - FULLMEKTIG + FULLMAKTSGIVER + FULLMEKTIG } type Fullmakt { - motpartsPersonident: String! - motpartsRolle: FullmaktsRolle! - omraader: [String!]! - gyldigFraOgMed: Date! - gyldigTilOgMed: Date! - metadata: Metadata! + motpartsPersonident: String! + motpartsRolle: FullmaktsRolle! + omraader: [String!]! + gyldigFraOgMed: Date! + gyldigTilOgMed: Date! + metadata: Metadata! } type Folkeregisteridentifikator { - identifikasjonsnummer: String! - status: String! - type: String! - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + identifikasjonsnummer: String! + status: String! + type: String! + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } type SikkerhetstiltakKontaktperson { - personident: String! - enhet: String! + personident: String! + enhet: String! } type Sikkerhetstiltak { - tiltakstype: String! - beskrivelse: String! - kontaktperson: SikkerhetstiltakKontaktperson - gyldigFraOgMed: Date! - gyldigTilOgMed: Date! - metadata: Metadata! + tiltakstype: String! + beskrivelse: String! + kontaktperson: SikkerhetstiltakKontaktperson + gyldigFraOgMed: Date! + gyldigTilOgMed: Date! + metadata: Metadata! } type Statsborgerskap { - land: String! - bekreftelsesdato: Date - gyldigFraOgMed: Date - gyldigTilOgMed: Date - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + land: String! + bekreftelsesdato: Date + gyldigFraOgMed: Date + gyldigTilOgMed: Date + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Opphold { - type: Oppholdstillatelse! - oppholdFra: Date - oppholdTil: Date - folkeregistermetadata: Folkeregistermetadata! - metadata: Metadata! + type: Oppholdstillatelse! + oppholdFra: Date + oppholdTil: Date + folkeregistermetadata: Folkeregistermetadata! + metadata: Metadata! } enum Oppholdstillatelse { - MIDLERTIDIG - PERMANENT - OPPLYSNING_MANGLER + MIDLERTIDIG + PERMANENT + OPPLYSNING_MANGLER } type Sivilstand { - type: Sivilstandstype! - gyldigFraOgMed: Date - relatertVedSivilstand: String - bekreftelsesdato: Date + type: Sivilstandstype! + gyldigFraOgMed: Date + relatertVedSivilstand: String + bekreftelsesdato: Date - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } enum Sivilstandstype { - UOPPGITT - UGIFT - GIFT - ENKE_ELLER_ENKEMANN - SKILT - SEPARERT - REGISTRERT_PARTNER - SEPARERT_PARTNER - SKILT_PARTNER - GJENLEVENDE_PARTNER + UOPPGITT + UGIFT + GIFT + ENKE_ELLER_ENKEMANN + SKILT + SEPARERT + REGISTRERT_PARTNER + SEPARERT_PARTNER + SKILT_PARTNER + GJENLEVENDE_PARTNER } type InnflyttingTilNorge { - fraflyttingsland: String - fraflyttingsstedIUtlandet: String - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + fraflyttingsland: String + fraflyttingsstedIUtlandet: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type UtflyttingFraNorge { - tilflyttingsland: String - tilflyttingsstedIUtlandet: String - utflyttingsdato: Date - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + tilflyttingsland: String + tilflyttingsstedIUtlandet: String + utflyttingsdato: Date + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type VergeEllerFullmektig { - navn: Personnavn - motpartsPersonident: String - omfang: String - omfangetErInnenPersonligOmraade: Boolean! + navn: Personnavn + motpartsPersonident: String + omfang: String + omfangetErInnenPersonligOmraade: Boolean! } type VergemaalEllerFremtidsfullmakt { - type: String - embete: String - vergeEllerFullmektig: VergeEllerFullmektig! + type: String + embete: String + vergeEllerFullmektig: VergeEllerFullmektig! - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type Foreldreansvar { - ansvar: String - ansvarlig: String - ansvarssubjekt: String - ansvarligUtenIdentifikator: RelatertBiPerson + ansvar: String + ansvarlig: String + ansvarssubjekt: String + ansvarligUtenIdentifikator: RelatertBiPerson - folkeregistermetadata: Folkeregistermetadata - metadata: Metadata! + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! } type RelatertBiPerson { - navn: Personnavn - foedselsdato: Date - statsborgerskap: String - kjoenn: KjoennType + navn: Personnavn + foedselsdato: Date + statsborgerskap: String + kjoenn: KjoennType } type Metadata { - # I PDL så får alle forekomster av en opplysning en ID som representerer dens unike forekomst. - # F.eks, så vil en Opprett ha ID X, korriger ID Y (der hvor den spesifiserer at den korrigerer X). - # Dersom en opplysning ikke er lagret i PDL, så vil denne verdien ikke være utfylt. - opplysningsId: String + # I PDL så får alle forekomster av en opplysning en ID som representerer dens unike forekomst. + # F.eks, så vil en Opprett ha ID X, korriger ID Y (der hvor den spesifiserer at den korrigerer X). + # Dersom en opplysning ikke er lagret i PDL, så vil denne verdien ikke være utfylt. + opplysningsId: String - # Master refererer til hvem som eier opplysningen, f.eks så har PDL en kopi av Folkeregisteret, da vil master være FREG og eventuelle endringer på dette må gå via Folkeregisteret (API mot dem eller andre rutiner). - master: String! + # Master refererer til hvem som eier opplysningen, f.eks så har PDL en kopi av Folkeregisteret, da vil master være FREG og eventuelle endringer på dette må gå via Folkeregisteret (API mot dem eller andre rutiner). + master: String! - # En liste over alle endringer som har blitt utført over tid. - # Vær obs på at denne kan endre seg og man burde takle at det finnes flere korrigeringer i listen, så dersom man ønsker å kun vise den siste, så må man selv filtrere ut dette. - # Det kan også ved svært få tilfeller skje at opprett blir fjernet. F.eks ved splitt tilfeller av identer. Dette skal skje i svært få tilfeller. Dersom man ønsker å presentere opprettet tidspunktet, så blir det tidspunktet på den første endringen. - endringer: [Endring!]! + # En liste over alle endringer som har blitt utført over tid. + # Vær obs på at denne kan endre seg og man burde takle at det finnes flere korrigeringer i listen, så dersom man ønsker å kun vise den siste, så må man selv filtrere ut dette. + # Det kan også ved svært få tilfeller skje at opprett blir fjernet. F.eks ved splitt tilfeller av identer. Dette skal skje i svært få tilfeller. Dersom man ønsker å presentere opprettet tidspunktet, så blir det tidspunktet på den første endringen. + endringer: [Endring!]! - # Feltet betegner hvorvidt dette er en funksjonelt historisk opplysning, for eksempel en tidligere fraflyttet adresse eller et foreldreansvar som er utløpt fordi barnet har fylt 18 år. - # I de fleste tilfeller kan dette utledes ved å se på de andre feltene i opplysningen. Dette er imidlertid ikke alltid tilfellet, blant annet for foreldreansvar. - # Feltet bør brukes av konsumenter som henter informasjon fra GraphQL med historikk, men som også trenger å utlede gjeldende informasjon. - historisk: Boolean! + # Feltet betegner hvorvidt dette er en funksjonelt historisk opplysning, for eksempel en tidligere fraflyttet adresse eller et foreldreansvar som er utløpt fordi barnet har fylt 18 år. + # I de fleste tilfeller kan dette utledes ved å se på de andre feltene i opplysningen. Dette er imidlertid ikke alltid tilfellet, blant annet for foreldreansvar. + # Feltet bør brukes av konsumenter som henter informasjon fra GraphQL med historikk, men som også trenger å utlede gjeldende informasjon. + historisk: Boolean! } # Endring som har blitt utført på opplysningen. F.eks: Opprett -> Korriger -> Korriger type Endring { - # Hvilke type endring som har blitt utført. - type: Endringstype! - # Tidspunktet for registrering. - registrert: DateTime! - # Hvem endringen har blitt utført av, ofte saksbehandler (f.eks Z990200), men kan også være system (f.eks srvXXXX). Denne blir satt til "Folkeregisteret" for det vi får fra dem. - registrertAv: String! - # Hvilke system endringen har kommet fra (f.eks srvXXX). Denne blir satt til "FREG" for det vi får fra Folkeregisteret. - systemkilde: String! - # Opphavet til informasjonen. I NAV blir dette satt i forbindelse med registrering (f.eks: Sykehuskassan). - # Fra Folkeregisteret får vi opphaven til dems opplysning, altså NAV, UDI, Politiet, Skatteetaten o.l.. Fra Folkeregisteret kan det også være tekniske navn som: DSF_MIGRERING, m.m.. - kilde: String! + # Hvilke type endring som har blitt utført. + type: Endringstype! + # Tidspunktet for registrering. + registrert: DateTime! + # Hvem endringen har blitt utført av, ofte saksbehandler (f.eks Z990200), men kan også være system (f.eks srvXXXX). Denne blir satt til "Folkeregisteret" for det vi får fra dem. + registrertAv: String! + # Hvilke system endringen har kommet fra (f.eks srvXXX). Denne blir satt til "FREG" for det vi får fra Folkeregisteret. + systemkilde: String! + # Opphavet til informasjonen. I NAV blir dette satt i forbindelse med registrering (f.eks: Sykehuskassan). + # Fra Folkeregisteret får vi opphaven til dems opplysning, altså NAV, UDI, Politiet, Skatteetaten o.l.. Fra Folkeregisteret kan det også være tekniske navn som: DSF_MIGRERING, m.m.. + kilde: String! + + hendelseId: String! } enum Endringstype { - OPPRETT - KORRIGER - OPPHOER + OPPRETT + KORRIGER + OPPHOER } input Criterion { - # Feltnavn ikludert sti til ønsket felt (Eksempel: person.navn.fornavn) - fieldName:String! + # Feltnavn ikludert sti til ønsket felt (Eksempel: person.navn.fornavn) + fieldName: String! - searchRule:SearchRule! - # Søk i historiske data - # true = søker kun i historiske data. - # false = søker kun i gjeldende data. - # null = søke i både historiske og gjeldende data. - searchHistorical:Boolean + searchRule: SearchRule! + # Søk i historiske data + # true = søker kun i historiske data. + # false = søker kun i gjeldende data. + # null = søke i både historiske og gjeldende data. + searchHistorical: Boolean } input SearchRule { - # Sjekker om feltet finnes / at det ikke har en null verdi. - exists:String - # Filtrerer bort treff hvor felt inneholder input verdi - notEquals:String - # Begrenser treff til kun de hvor felt har input verdi - equals:String - # Gir treff når opgitt felt inneholder en eller flere ord fra input verdien. - contains:String - # Søk som gir treff også for små variasjoner i skrivemåte - fuzzy:String - # Søk som gir tilfeldig poengsum til hvert treff (kun ment til generering av testdata) - random:String - # Bruk "?" som wildcard for enkelt tegn, og "*" som wildcard for 0 eller flere tegn. - wildcard:String - # Gir treff når opgitt feltstarter med opgitt verdi. - startsWith:String - # Regex søk for spesielle situasjoner (Dette er en treg opprasjon og bør ikke brukes) - regex:String - # Brukes til søke etter datoer som kommer etter opgitt dato. - after:String - # Brukes til søke etter datoer som kommer før opgitt dato. - before:String - # Brukes til å søke i tall og finner verdier som er mindre en input verdi. - lessThan:String - # Brukes til å søke i tall og finner verdier som er størren en input verdi. - greaterThan:String - # Søk fra og med (se fromExcluding for bare fra men ikke med) - # kan benyttes på tall og dato - from:String - # Søk til og med (se toExcluding for bare til men ikke med) - # kan benyttes på tall og dato - to:String - # Søk fra men ikke med oppgitt verdi - # kan benyttes på tall og dato - fromExcluding:String, - # Søk til men ikke med oppgitt verdi - # kan benyttes på tall og dato - toExcluding:String - - # [Flag] Kan brukes til å overstyre standard oppførsellen for søk i felter (standard er case insensitive) - caseSensitive:Boolean - # [Flag] Brukes til å deaktivere fonetisk søk feltene som har dette som standard (Navn) - disablePhonetic:Boolean - # Boost brukes til å gi ett søkekriterie høyere eller lavere vektlegging en de andre søke kriteriene. - boost:Float + # Sjekker om feltet finnes / at det ikke har en null verdi. + exists: String + # Filtrerer bort treff hvor felt inneholder input verdi + notEquals: String + # Begrenser treff til kun de hvor felt har input verdi + equals: String + # Gir treff når opgitt felt inneholder en eller flere ord fra input verdien. + contains: String + # Søk som gir treff også for små variasjoner i skrivemåte + fuzzy: String + # Søk som gir tilfeldig poengsum til hvert treff (kun ment til generering av testdata) + random: String + # Bruk "?" som wildcard for enkelt tegn, og "*" som wildcard for 0 eller flere tegn. + wildcard: String + # Gir treff når opgitt feltstarter med opgitt verdi. + startsWith: String + # Regex søk for spesielle situasjoner (Dette er en treg opprasjon og bør ikke brukes) + regex: String + # Brukes til søke etter datoer som kommer etter opgitt dato. + after: String + # Brukes til søke etter datoer som kommer før opgitt dato. + before: String + # Brukes til å søke i tall og finner verdier som er mindre en input verdi. + lessThan: String + # Brukes til å søke i tall og finner verdier som er størren en input verdi. + greaterThan: String + # Søk fra og med (se fromExcluding for bare fra men ikke med) + # kan benyttes på tall og dato + from: String + # Søk til og med (se toExcluding for bare til men ikke med) + # kan benyttes på tall og dato + to: String + # Søk fra men ikke med oppgitt verdi + # kan benyttes på tall og dato + fromExcluding: String + # Søk til men ikke med oppgitt verdi + # kan benyttes på tall og dato + toExcluding: String + + # [Flag] Kan brukes til å overstyre standard oppførsellen for søk i felter (standard er case insensitive) + caseSensitive: Boolean + # [Flag] Brukes til å deaktivere fonetisk søk feltene som har dette som standard (Navn) + disablePhonetic: Boolean + # Boost brukes til å gi ett søkekriterie høyere eller lavere vektlegging en de andre søke kriteriene. + boost: Float } input Paging { - # Hvilken side i resultatsettet man ønsker vist. - pageNumber:Int = 1 - # antall treff per side (maks 100) - resultsPerPage:Int = 10 - # Liste over felter man ønsker resultatene sortert etter - # Standard er "score". Score er poengsummen Elasticsearch tildeler hvert resultat. - sortBy:[SearchSorting] + # Hvilken side i resultatsettet man ønsker vist. + pageNumber: Int = 1 + # antall treff per side (maks 100) + resultsPerPage: Int = 10 + # Liste over felter man ønsker resultatene sortert etter + # Standard er "score". Score er poengsummen Elasticsearch tildeler hvert resultat. + sortBy: [SearchSorting] } input SearchSorting { - # Feltnavn ikludert sti til ønsket felt (eksepmel: person.navn.fornavn) - fieldName:String! - direction:Direction! + # Feltnavn ikludert sti til ønsket felt (eksepmel: person.navn.fornavn) + fieldName: String! + direction: Direction! } enum Direction { - ASC, - DESC + ASC + DESC } type PersonSearchResult { - # treff liste - hits : [PersonSearchHit!]! - # Side nummer for siden som vises - pageNumber:Int - # Totalt antall sider - totalPages:Int - # Totalt antall treff (øvre grense er satt til 10 000) - totalHits:Int - + # treff liste + hits: [PersonSearchHit!]! + # Side nummer for siden som vises + pageNumber: Int + # Totalt antall sider + totalPages: Int + # Totalt antall treff (øvre grense er satt til 10 000) + totalHits: Int } type PersonSearchHit { - # forespurte data - person :Person - # forespurte data - identer(historikk: Boolean = false): [IdentInformasjon!]! - # Poengsummen elasticsearch har gitt dette resultatet (brukt til feilsøking, og tuning av søk) - score :Float - # Infromasjon om hva som ga treff i søke resultatet. - highlights:[PersonSearchHighlight] + # forespurte data + person: Person + # forespurte data + identer(historikk: Boolean = false): [IdentInformasjon!]! + # Poengsummen elasticsearch har gitt dette resultatet (brukt til feilsøking, og tuning av søk) + score: Float + # Infromasjon om hva som ga treff i søke resultatet. + highlights: [PersonSearchHighlight] } type PersonSearchHighlight { - # Navn/Sti til opplysningen som ga treff. Merk at dette ikke er feltet som ga treff men opplysningen. - # F.eks. hvis du søker på person.navn.fornavn så vil opplysingen være person.navn. - opplysning:String - # Gitt att opplysningen som ga treff har en opplysningsId så vil den returneres her. - # alle søk under person skal ha opplysningsId, men søk i identer vil kunne returnere treff uten opplysningsId. - opplysningsId: String - # Forteller hvorvidt opplysningen som ga treff er markert som historisk. - historisk: Boolean - # liste med feltene og verdiene som ga treff. - # Merk at for fritekst søk så vil disse kunne referere til hjelpe felter som ikke er synelig i resultatene. - matches:[SearchMatch] + # Navn/Sti til opplysningen som ga treff. Merk at dette ikke er feltet som ga treff men opplysningen. + # F.eks. hvis du søker på person.navn.fornavn så vil opplysingen være person.navn. + opplysning: String + # Gitt att opplysningen som ga treff har en opplysningsId så vil den returneres her. + # alle søk under person skal ha opplysningsId, men søk i identer vil kunne returnere treff uten opplysningsId. + opplysningsId: String + # Forteller hvorvidt opplysningen som ga treff er markert som historisk. + historisk: Boolean + # liste med feltene og verdiene som ga treff. + # Merk at for fritekst søk så vil disse kunne referere til hjelpe felter som ikke er synelig i resultatene. + matches: [SearchMatch] } type SearchMatch { - # feltnavn med sti til feltet so ga treff. - field:String! - type: String - # Verdien som ga treff - fragments: [String] + # feltnavn med sti til feltet so ga treff. + field: String! + type: String + # Verdien som ga treff + fragments: [String] } type AdresseSearchResult { - hits : [AdresseSearchHit!]! - pageNumber:Int, - totalPages:Int - totalHits:Int - + hits: [AdresseSearchHit!]! + pageNumber: Int + totalPages: Int + totalHits: Int } type AdresseSearchHit { - vegadresse : VegadresseResult - matrikkeladresse : MatrikkeladresseResult - score :Float + vegadresse: VegadresseResult + matrikkeladresse: MatrikkeladresseResult + score: Float } type VegadresseResult { - matrikkelId:String - husnummer:Int - husbokstav:String - adressenavn:String - adressekode:String - tilleggsnavn:String - fylkesnavn:String - fylkesnummer:String - kommunenavn:String - kommunenummer:String - postnummer:String - poststed:String - bydelsnavn:String - bydelsnummer:String + matrikkelId: String + husnummer: Int + husbokstav: String + adressenavn: String + adressekode: String + tilleggsnavn: String + fylkesnavn: String + fylkesnummer: String + kommunenavn: String + kommunenummer: String + postnummer: String + poststed: String + bydelsnavn: String + bydelsnummer: String } type MatrikkeladresseResult { - matrikkelId:String - tilleggsnavn:String - kommunenummer:String - gaardsnummer:String - bruksnummer:String - postnummer:String - poststed:String + matrikkelId: String + tilleggsnavn: String + kommunenummer: String + gaardsnummer: String + bruksnummer: String + postnummer: String + poststed: String } type AdresseCompletionResult { - suggestions: [String!]! - addressFound : CompletionAdresse + suggestions: [String!]! + addressFound: CompletionAdresse } type CompletionAdresse { - vegadresse : VegadresseResult - matrikkeladresse : MatrikkeladresseResult + vegadresse: VegadresseResult + matrikkeladresse: MatrikkeladresseResult } input CompletionParameters { - - completionField: String! - maxSuggestions: Int - fieldValues: [CompletionFieldValue]! + completionField: String! + maxSuggestions: Int + fieldValues: [CompletionFieldValue]! } input CompletionFieldValue { - fieldName: String! - fieldValue: String + fieldName: String! + fieldValue: String } diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt index 9c8dd07f..f275fab2 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -17,5 +17,5 @@ fun mockPdlClient(content: String): PdlClient { headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) ) } - return PdlClient("https://url", "tema", { "fake token" }, HttpClient(mockEngine)) + return PdlClient("https://url", "tema", HttpClient(mockEngine)) { "fake token" } } From 2fc0d8566c43a7763cd8002630e16804b2a5545c Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Tue, 28 Feb 2023 10:32:59 +0100 Subject: [PATCH 12/64] Oppdaterer README --- paw-pdl-client/README.md | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/paw-pdl-client/README.md b/paw-pdl-client/README.md index 87b72dc7..3db91210 100644 --- a/paw-pdl-client/README.md +++ b/paw-pdl-client/README.md @@ -17,19 +17,33 @@ dependencies { For mer informasjon om tema-koder [sjekk her](https://confluence.adeo.no/pages/viewpage.action?pageId=309311397). ```kt +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import no.nav.paw.tokenprovier.OAuth2TokenProvider +import no.nav.common.token_client.builder.AzureAdTokenClientBuilder import no.nav.paw.pdl-client.PdlCLient fun main() { val url = "http://pdl-api.default.svc.nais.local/graphql" - val accessTokenProvider = RestSTSAccessTokenProvider() - - val pdlClient = pdlClient(url, "tema", accessTokenProvider::getToken) - + val httpClient = HttpClient(OkHttp) { + install(ContentNegotiation) { + jackson() + } + } + val pdlClient = pdlClient(url, "tema", httpClient) { getAccessToken() } val result = runBlocking { pdlClient.hentAktorId("fnr") } println(result) } + +private val aadMachineToMachineTokenClient = AzureAdTokenClientBuilder.builder() + .withNaisDefaults() + .buildMachineToMachineTokenClient() + +fun getAccessToken(): String { + return aadMachineToMachineTokenClient.createMachineToMachineToken( + "api://${pdlCluster}.$namespace.$appName/.default" + ) +} ``` ### Lokal utvikling From 758e171a9bc1cab3e3035b1a50aa9b102c7ed1b0 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 27 Mar 2023 10:57:26 +0200 Subject: [PATCH 13/64] paw-aareg-client --- .github/workflows/paw-aareg-client.yml | 29 +++ .github/workflows/paw-pdl-client.yml | 2 +- paw-aareg-client/README.md | 36 +++ paw-aareg-client/build.gradle.kts | 78 ++++++ paw-aareg-client/gradle.properties | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + paw-aareg-client/gradlew | 234 ++++++++++++++++++ paw-aareg-client/gradlew.bat | 89 +++++++ paw-aareg-client/settings.gradle.kts | 15 ++ .../kotlin/no/nav/paw/aareg/AaregClient.kt | 53 ++++ .../kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 46 ++++ .../no/nav/paw/aareg/LocalDateSerializer.kt | 15 ++ .../nav/paw/aareg/LocalDateTimeSerializer.kt | 15 ++ .../src/main/kotlin/no/nav/paw/aareg/Utils.kt | 28 +++ .../no/nav/paw/aareg/AaregClientTest.kt | 50 ++++ .../test/kotlin/no/nav/paw/aareg/MockUtils.kt | 43 ++++ .../test/resources/aareg-arbeidsforhold.json | 164 ++++++++++++ .../src/test/resources/error.json | 19 ++ 19 files changed, 932 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/paw-aareg-client.yml create mode 100644 paw-aareg-client/README.md create mode 100644 paw-aareg-client/build.gradle.kts create mode 100644 paw-aareg-client/gradle.properties create mode 100644 paw-aareg-client/gradle/wrapper/gradle-wrapper.jar create mode 100644 paw-aareg-client/gradle/wrapper/gradle-wrapper.properties create mode 100755 paw-aareg-client/gradlew create mode 100644 paw-aareg-client/gradlew.bat create mode 100644 paw-aareg-client/settings.gradle.kts create mode 100644 paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt create mode 100644 paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt create mode 100644 paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt create mode 100644 paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt create mode 100644 paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt create mode 100644 paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt create mode 100644 paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt create mode 100644 paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json create mode 100644 paw-aareg-client/src/test/resources/error.json diff --git a/.github/workflows/paw-aareg-client.yml b/.github/workflows/paw-aareg-client.yml new file mode 100644 index 00000000..032c7093 --- /dev/null +++ b/.github/workflows/paw-aareg-client.yml @@ -0,0 +1,29 @@ +name: paw-aareg-client + +on: + push: + branches: + - main + paths: + - 'paw-aareg-client/**' + +jobs: + build: + name: Build and push + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Verify Gradle wrapper checksum + uses: gradle/wrapper-validation-action@v1 + + - name: Build with Gradle and Publish artifact + working-directory: ./paw-aareg-client + run: ./gradlew build test publish + env: + ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index 88c2d03b..4787f6ab 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -1,4 +1,4 @@ -name: paw-pds-client +name: paw-pdl-client on: push: diff --git a/paw-aareg-client/README.md b/paw-aareg-client/README.md new file mode 100644 index 00000000..67bf8b9f --- /dev/null +++ b/paw-aareg-client/README.md @@ -0,0 +1,36 @@ +# paw-aareg-client + +Henter arbeidsforhold fra Arbeidsgiver- og arbeidstakerregisteret ([aareg](https://navikt.github.io/aareg/)). + +### Bruk av paw-aareg-client + +***gradle.build.kts*** +```kts +val tokenproviderVersion: String by project +val aaregClientVersion: String by project + +dependencies { + implementation("no.nav.paw:tokenprovider:$tokenproviderVersion") + implementation("no.nav.paw:aareg-client:$aaregClientVersion") +} +``` + +### Klienten instansieres slik + +```kt +import kotlinx.coroutines.runBlocking +import no.nav.paw.tokenprovider.OAuth2TokenProvider +import no.nav.paw.aareg.AaregClient + +fun main() { + val url = "https://modapp-q1.adeo.no/aareg-services" + val tokenProvider = OAuth2TokenProvider( + // Token config + ) + + val aaregClient = AaregClient(url) { tokenProvider.getToken() } + + val arbeidsforhold = runBlocking { aaregClient.hentArbeidsforhold("fnr", "callId") } + println(arbeidsforhold) +} +``` diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts new file mode 100644 index 00000000..a894d9f1 --- /dev/null +++ b/paw-aareg-client/build.gradle.kts @@ -0,0 +1,78 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("org.jmailen.kotlinter") + id("maven-publish") + java +} + +group = "no.nav.paw" +version = "0.1.0" + +tasks { + withType { + kotlinOptions.jvmTarget = "11" + } + test { + useJUnitPlatform() + } +} + + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + + withSourcesJar() +} + +repositories { + mavenCentral() + mavenNav("*") +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + } + } + repositories { + mavenNav("paw-${rootProject.name}") + } +} + +dependencies { + val ktorVersion: String by project + val mockkVersion: String by project + val kotlinSerializationVersion: String by project + val junitJupiterVersion: String by project + val slf4jVersion: String by project + + api("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") + + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-okhttp:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("io.ktor:ktor-client-logging:$ktorVersion") + + testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion") + testImplementation("io.ktor:ktor-client-mock:$ktorVersion") + testImplementation("io.mockk:mockk:$mockkVersion") + testImplementation("org.slf4j:slf4j-simple:$slf4jVersion") +} + +fun RepositoryHandler.mavenNav(repo: String): MavenArtifactRepository { + val githubPassword: String by project + + return maven { + setUrl("https://maven.pkg.github.com/navikt/$repo") + credentials { + username = "x-access-token" + password = githubPassword + } + } +} diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties new file mode 100644 index 00000000..20ad08ac --- /dev/null +++ b/paw-aareg-client/gradle.properties @@ -0,0 +1,12 @@ +kotlin.code.style=official + +# Plugin versions +kotlinVersion=1.7.10 +kotlinterVersion=3.12.0 + +ktorVersion=2.1.1 +mockkVersion=1.12.7 +kotlinSerializationVersion=1.4.0 +junitJupiterVersion=5.9.0 +slf4jVersion=2.0.4 +sonarqubeVersion=3.5.0.2730 \ No newline at end of file diff --git a/paw-aareg-client/gradle/wrapper/gradle-wrapper.jar b/paw-aareg-client/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..41d9927a4d4fb3f96a785543079b8df6723c946b GIT binary patch literal 59821 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 literal 0 HcmV?d00001 diff --git a/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties b/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..41dfb879 --- /dev/null +++ b/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/paw-aareg-client/gradlew b/paw-aareg-client/gradlew new file mode 100755 index 00000000..1b6c7873 --- /dev/null +++ b/paw-aareg-client/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/paw-aareg-client/gradlew.bat b/paw-aareg-client/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/paw-aareg-client/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/paw-aareg-client/settings.gradle.kts b/paw-aareg-client/settings.gradle.kts new file mode 100644 index 00000000..70824e10 --- /dev/null +++ b/paw-aareg-client/settings.gradle.kts @@ -0,0 +1,15 @@ +rootProject.name = "aareg-client" + +pluginManagement { + val kotlinVersion: String by settings + val kotlinterVersion: String by settings + val sonarqubeVersion: String by settings + + plugins { + kotlin("jvm") version kotlinVersion + kotlin("plugin.serialization") version kotlinVersion + id("org.jmailen.kotlinter") version kotlinterVersion + id("maven-publish") + id("org.sonarqube") version sonarqubeVersion + } +} diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt new file mode 100644 index 00000000..63b173a2 --- /dev/null +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt @@ -0,0 +1,53 @@ +package no.nav.paw.aareg + +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException +import io.ktor.client.request.bearerAuth +import io.ktor.client.request.get +import io.ktor.client.request.header +import io.ktor.client.statement.bodyAsText +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.serialization.JsonConvertException +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.net.ConnectException + +/** + * klient for å hente ut aktive arbeidsforhold på en person + */ + +class AaregClient( + private val url: String, + private val getAccessToken: () -> String +) { + private val sikkerLogg: Logger = LoggerFactory.getLogger("tjenestekall") + private val aaregClientLogger: Logger = LoggerFactory.getLogger("paw-aareg-client") + private val httpClient = createHttpClient() + + suspend fun hentArbeidsforhold(ident: String, callId: String): List { + val token = getAccessToken() + try { + val payload = httpClient.get(url) { + contentType(ContentType.Application.Json) + bearerAuth(token) + header("X-Correlation-ID", callId) + header("Nav-Consumer-Token", "Bearer $token") + header("Nav-Personident", ident) + }.also { + sikkerLogg.debug("Svar fra aareg-API: " + it.bodyAsText()) + }.body>() + return payload + } catch (responseException: ResponseException) { + aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet med http-kode ${responseException.response.status}") + return emptyList() + } catch (connectException: ConnectException) { + aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet:", connectException) + return emptyList() + } catch (jsonConvertException: JsonConvertException) { + aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet, kunne ikke lese JSON") + sikkerLogg.error("Hente arbeidsforhold callId=[$callId] feilet", jsonConvertException) + return emptyList() + } + } +} diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt new file mode 100644 index 00000000..a348cee3 --- /dev/null +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt @@ -0,0 +1,46 @@ +package no.nav.paw.aareg + +import kotlinx.serialization.Serializable +import java.time.LocalDate +import java.time.LocalDateTime + +@Serializable +data class Arbeidsforhold( + val arbeidsgiver: Arbeidsgiver, + val opplysningspliktig: Opplysningspliktig, + val arbeidsavtaler: List, + val ansettelsesperiode: Ansettelsesperiode, + @Serializable(with = LocalDateTimeSerializer::class) + val registrert: LocalDateTime +) + +@Serializable +data class Arbeidsavtale( + val stillingsprosent: Double, + val gyldighetsperiode: Periode +) + +@Serializable +data class Ansettelsesperiode( + val periode: Periode +) + +@Serializable +data class Arbeidsgiver( + val type: String, + val organisasjonsnummer: String? +) + +@Serializable +data class Periode( + @Serializable(with = LocalDateSerializer::class) + val fom: LocalDate?, + @Serializable(with = LocalDateSerializer::class) + val tom: LocalDate? = null +) + +@Serializable +data class Opplysningspliktig( + val type: String, + val organisasjonsnummer: String? +) diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt new file mode 100644 index 00000000..b0ef6980 --- /dev/null +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt @@ -0,0 +1,15 @@ +package no.nav.paw.aareg + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDate + +object LocalDateSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING) + override fun serialize(encoder: Encoder, value: LocalDate) = encoder.encodeString(value.toString()) + override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString()) +} diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt new file mode 100644 index 00000000..f1ee25a3 --- /dev/null +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt @@ -0,0 +1,15 @@ +package no.nav.paw.aareg + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDateTime + +object LocalDateTimeSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING) + override fun serialize(encoder: Encoder, value: LocalDateTime) = encoder.encodeString(value.toString()) + override fun deserialize(decoder: Decoder): LocalDateTime = LocalDateTime.parse(decoder.decodeString()) +} diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt new file mode 100644 index 00000000..22ff109b --- /dev/null +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt @@ -0,0 +1,28 @@ +package no.nav.paw.aareg + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json + +internal fun createHttpClient(): HttpClient = + HttpClient(OkHttp) { configureJsonHandler() } + +@OptIn(ExperimentalSerializationApi::class) +internal fun HttpClientConfig<*>.configureJsonHandler() { + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + explicitNulls = false + } + ) + } + expectSuccess = true +} + +internal fun String.readResource(): String = + ClassLoader.getSystemResource(this).readText() diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt new file mode 100644 index 00000000..e0da587c --- /dev/null +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -0,0 +1,50 @@ +package no.nav.paw.aareg + +import io.ktor.http.HttpStatusCode +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class AaregClientTest { + + /* + API Description: + https://navikt.github.io/aareg/tjenester/integrasjon/api/ + */ + @Test + fun `Returnerer gyldig objekt når alt er oK`() { + val response = runBlocking { + mockAaregClient(MockResponse.arbeidsforhold) + .hentArbeidsforhold("ident", "call-id") + } + assertTrue(response.any { it.arbeidsgiver.organisasjonsnummer == "896929119" }) + } + + @Test + fun test_OK_svar_Med_Uventet_JSON() { + val response = runBlocking { + mockAaregClient(MockResponse.error) + .hentArbeidsforhold("hei", "54-56 That's My Number") + } + val empty = emptyList() + assertEquals(empty, response) + } + + @Test + fun test_Server_Error() { + val response = runBlocking { + mockAaregClient("blablabla", HttpStatusCode.InternalServerError) + .hentArbeidsforhold("hei", "123456") + } + val empty = emptyList() + assertEquals(empty, response) + } + + @Test + fun realDeal() { + val client = AaregClient(url = "blah") { "tja" } + val response = runBlocking { client.hentArbeidsforhold("hei", "Number 2") } + assertEquals(emptyList(), response) + } +} diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt new file mode 100644 index 00000000..9aebc5d4 --- /dev/null +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt @@ -0,0 +1,43 @@ +package no.nav.paw.aareg + +import io.ktor.client.HttpClient +import io.ktor.client.engine.mock.MockEngine +import io.ktor.client.engine.mock.respond +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.headersOf +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.unmockkStatic +import kotlin.reflect.KFunction + +object MockResponse { + val arbeidsforhold = "aareg-arbeidsforhold.json".readResource() + val error = "error.json".readResource() +} +fun mockAaregClient(content: String, statusCode: HttpStatusCode = HttpStatusCode.OK): AaregClient { + val mockEngine = MockEngine { + respond( + content = content, + status = statusCode, + headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + ) + } + + val mockHttpClient = HttpClient(mockEngine) { configureJsonHandler() } + + return mockFn(::createHttpClient) { + every { createHttpClient() } returns mockHttpClient + AaregClient("url") { "fake token" } + } +} + +private fun mockFn(fn: KFunction<*>, block: () -> T): T { + mockkStatic(fn) + return try { + block() + } finally { + unmockkStatic(fn) + } +} diff --git a/paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json b/paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json new file mode 100644 index 00000000..f677ff7f --- /dev/null +++ b/paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json @@ -0,0 +1,164 @@ +[ + { + "navArbeidsforholdId": 51505573, + "arbeidsforholdId": "1", + "arbeidstaker": { + "type": "Person", + "offentligIdent": "22018520056", + "aktoerId": "2884609777831" + }, + "arbeidsgiver": { + "type": "Organisasjon", + "organisasjonsnummer": "896929119" + }, + "opplysningspliktig": { + "type": "Organisasjon", + "organisasjonsnummer": "928497704" + }, + "type": "ordinaertArbeidsforhold", + "ansettelsesperiode": { + "periode": { + "fom": "2001-01-22" + }, + "bruksperiode": { + "fom": "2021-01-22T12:07:35.844" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + }, + "arbeidsavtaler": [ + { + "type": "Ordinaer", + "arbeidstidsordning": "ikkeSkift", + "yrke": "3310101", + "stillingsprosent": 100.0, + "antallTimerPrUke": 37.5, + "beregnetAntallTimerPrUke": 37.5, + "bruksperiode": { + "fom": "2021-01-22T12:07:35.844" + }, + "gyldighetsperiode": { + "fom": "2001-01-01" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + } + ], + "varsler": [ + { + "entitet": "ARBEIDSFORHOLD", + "varslingskode": "NAVEND" + } + ], + "innrapportertEtterAOrdningen": true, + "registrert": "2021-01-22T12:07:35.785", + "sistBekreftet": "2021-01-22T12:07:35", + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + }, + { + "navArbeidsforholdId": 51507953, + "arbeidsforholdId": "2", + "arbeidstaker": { + "type": "Person", + "offentligIdent": "22018520056", + "aktoerId": "2884609777831" + }, + "arbeidsgiver": { + "type": "Organisasjon", + "organisasjonsnummer": "896929119" + }, + "opplysningspliktig": { + "type": "Organisasjon", + "organisasjonsnummer": "928497704" + }, + "type": "ordinaertArbeidsforhold", + "ansettelsesperiode": { + "periode": { + "fom": "2001-03-15" + }, + "bruksperiode": { + "fom": "2021-03-15T12:45:29.413" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + }, + "arbeidsavtaler": [ + { + "type": "Ordinaer", + "arbeidstidsordning": "ikkeSkift", + "yrke": "5221126", + "stillingsprosent": 100.0, + "antallTimerPrUke": 37.5, + "beregnetAntallTimerPrUke": 37.5, + "bruksperiode": { + "fom": "2021-03-15T12:45:29.413" + }, + "gyldighetsperiode": { + "fom": "2001-03-01" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + } + ], + "varsler": [ + { + "entitet": "ARBEIDSFORHOLD", + "varslingskode": "NAVEND" + } + ], + "innrapportertEtterAOrdningen": true, + "registrert": "2021-03-15T12:45:29.319", + "sistBekreftet": "2021-03-15T12:45:29", + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + } +] \ No newline at end of file diff --git a/paw-aareg-client/src/test/resources/error.json b/paw-aareg-client/src/test/resources/error.json new file mode 100644 index 00000000..55860e82 --- /dev/null +++ b/paw-aareg-client/src/test/resources/error.json @@ -0,0 +1,19 @@ +{ + "errors": [ + { + "message": "En ukjent feil oppstod", + "locations": [], + "extensions": { + "errormessages": { + "code": "AA-000", + "message": "Det oppsto en feil under behandlingen av forespøselen", + "details": null + }, + "classification": "ExecutionAborted" + } + } + ], + "data": { + "finnArbeidsforhold": null + } +} \ No newline at end of file From d001231f69321d6b60dd252e6288788dd7f45c2f Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 27 Mar 2023 11:40:51 +0200 Subject: [PATCH 14/64] Update build.gradle.kts --- paw-aareg-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index a894d9f1..5275298f 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -40,7 +40,7 @@ publishing { } } repositories { - mavenNav("paw-${rootProject.name}") + mavenNav("paw-kotlin-clients") } } From 6b2fb949f7a724e8478fb43b6eec72f155e1140d Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 27 Mar 2023 11:54:15 +0200 Subject: [PATCH 15/64] oppdaterer ktor versjon --- paw-aareg-client/build.gradle.kts | 2 +- paw-aareg-client/gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index 5275298f..905f187b 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.0" +version = "0.1.1" tasks { withType { diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties index 20ad08ac..03be0b1c 100644 --- a/paw-aareg-client/gradle.properties +++ b/paw-aareg-client/gradle.properties @@ -4,7 +4,7 @@ kotlin.code.style=official kotlinVersion=1.7.10 kotlinterVersion=3.12.0 -ktorVersion=2.1.1 +ktorVersion=2.2.4 mockkVersion=1.12.7 kotlinSerializationVersion=1.4.0 junitJupiterVersion=5.9.0 From c517da9a636207dc7bca9f6eeaf34e3439626369 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 31 Mar 2023 13:53:56 +0200 Subject: [PATCH 16/64] Update README.md --- paw-aareg-client/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/paw-aareg-client/README.md b/paw-aareg-client/README.md index 67bf8b9f..e9508b13 100644 --- a/paw-aareg-client/README.md +++ b/paw-aareg-client/README.md @@ -2,6 +2,8 @@ Henter arbeidsforhold fra Arbeidsgiver- og arbeidstakerregisteret ([aareg](https://navikt.github.io/aareg/)). +Se URL-er på https://github.com/navikt/aareg-services + ### Bruk av paw-aareg-client ***gradle.build.kts*** From 546e13959c92c0f3ef1c98d98441943313259e39 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 3 Apr 2023 12:39:54 +0200 Subject: [PATCH 17/64] =?UTF-8?q?Fom=20kan=20ikke=20v=C3=A6re=20valgfri?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-aareg-client/.gitignore | 31 +++++++++++++++++++ paw-aareg-client/build.gradle.kts | 2 +- .../kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 paw-aareg-client/.gitignore diff --git a/paw-aareg-client/.gitignore b/paw-aareg-client/.gitignore new file mode 100644 index 00000000..241e4dfe --- /dev/null +++ b/paw-aareg-client/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# IDEA & Gradle +/.gradle +/.idea +/out +/lib +/build +*.iml +*.ipr +*.iws + +# Package Files # +*.jar +!gradle-wrapper.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#mac files +**/.DS_Store diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index 905f187b..f4d63131 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.1" +version = "0.1.2" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt index a348cee3..8481299e 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt @@ -34,7 +34,7 @@ data class Arbeidsgiver( @Serializable data class Periode( @Serializable(with = LocalDateSerializer::class) - val fom: LocalDate?, + val fom: LocalDate, @Serializable(with = LocalDateSerializer::class) val tom: LocalDate? = null ) From 1598a7385ff08b45d391fe4ef761cef0925668d9 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 17 Apr 2023 15:06:17 +0200 Subject: [PATCH 18/64] Ikke send med Nav-Consumer-Token + kast exception --- .gitignore | 4 ++-- paw-aareg-client/build.gradle.kts | 2 +- .../src/main/kotlin/no/nav/paw/aareg/AaregClient.kt | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 241e4dfe..dd6e2101 100644 --- a/.gitignore +++ b/.gitignore @@ -5,11 +5,11 @@ *.log # IDEA & Gradle -/.gradle +**/.gradle /.idea /out /lib -/build +**/build *.iml *.ipr *.iws diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index f4d63131..63ff10d8 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.2" +version = "0.1.3" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt index 63b173a2..404c1069 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt @@ -31,8 +31,7 @@ class AaregClient( val payload = httpClient.get(url) { contentType(ContentType.Application.Json) bearerAuth(token) - header("X-Correlation-ID", callId) - header("Nav-Consumer-Token", "Bearer $token") + header("Nav-Call-Id", callId) header("Nav-Personident", ident) }.also { sikkerLogg.debug("Svar fra aareg-API: " + it.bodyAsText()) @@ -40,14 +39,14 @@ class AaregClient( return payload } catch (responseException: ResponseException) { aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet med http-kode ${responseException.response.status}") - return emptyList() + throw responseException } catch (connectException: ConnectException) { aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet:", connectException) - return emptyList() + throw connectException } catch (jsonConvertException: JsonConvertException) { aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet, kunne ikke lese JSON") sikkerLogg.error("Hente arbeidsforhold callId=[$callId] feilet", jsonConvertException) - return emptyList() + throw jsonConvertException } } } From 385748b1a122d1eaa30cfc360ea46f0f12e773d0 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 17 Apr 2023 15:13:28 +0200 Subject: [PATCH 19/64] Kommenter ut feilende tester --- .../no/nav/paw/aareg/AaregClientTest.kt | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt index e0da587c..a0dd1874 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -20,31 +20,31 @@ class AaregClientTest { } assertTrue(response.any { it.arbeidsgiver.organisasjonsnummer == "896929119" }) } - - @Test - fun test_OK_svar_Med_Uventet_JSON() { - val response = runBlocking { - mockAaregClient(MockResponse.error) - .hentArbeidsforhold("hei", "54-56 That's My Number") - } - val empty = emptyList() - assertEquals(empty, response) - } - - @Test - fun test_Server_Error() { - val response = runBlocking { - mockAaregClient("blablabla", HttpStatusCode.InternalServerError) - .hentArbeidsforhold("hei", "123456") - } - val empty = emptyList() - assertEquals(empty, response) - } - - @Test - fun realDeal() { - val client = AaregClient(url = "blah") { "tja" } - val response = runBlocking { client.hentArbeidsforhold("hei", "Number 2") } - assertEquals(emptyList(), response) - } +// +// @Test +// fun test_OK_svar_Med_Uventet_JSON() { +// val response = runBlocking { +// mockAaregClient(MockResponse.error) +// .hentArbeidsforhold("hei", "54-56 That's My Number") +// } +// val empty = emptyList() +// assertEquals(empty, response) +// } +// +// @Test +// fun test_Server_Error() { +// val response = runBlocking { +// mockAaregClient("blablabla", HttpStatusCode.InternalServerError) +// .hentArbeidsforhold("hei", "123456") +// } +// val empty = emptyList() +// assertEquals(empty, response) +// } +// +// @Test +// fun realDeal() { +// val client = AaregClient(url = "blah") { "tja" } +// val response = runBlocking { client.hentArbeidsforhold("hei", "Number 2") } +// assertEquals(emptyList(), response) +// } } From b9489ab498389742b37c049c8c01e5668c8a6fd9 Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 17 Apr 2023 15:17:47 +0200 Subject: [PATCH 20/64] Linting --- .../src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt index a0dd1874..fe56a82a 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -1,8 +1,6 @@ package no.nav.paw.aareg -import io.ktor.http.HttpStatusCode import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test From 512f3c759fd9ecc49578deaccce1d2144b5d752c Mon Sep 17 00:00:00 2001 From: Jostein Holje Date: Mon, 17 Apr 2023 15:23:09 +0200 Subject: [PATCH 21/64] 0.1.4 --- paw-aareg-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index 63ff10d8..cad24585 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.3" +version = "0.1.4" tasks { withType { From c7a3050a5d83cf3371a9d570db0f19baa7d0b933 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 17 Apr 2023 16:58:50 +0200 Subject: [PATCH 22/64] =?UTF-8?q?H=C3=A5ndterer=20ingen=20perioder=20i=20a?= =?UTF-8?q?nsettelseperioder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-aareg-client/README.md | 7 +- paw-aareg-client/build.gradle.kts | 2 +- .../kotlin/no/nav/paw/aareg/AaregClient.kt | 1 + .../kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 2 +- .../no/nav/paw/aareg/AaregClientTest.kt | 9 + .../test/kotlin/no/nav/paw/aareg/MockUtils.kt | 2 + .../resources/aareg-ingen-arbeidsforhold.json | 161 ++++++++++++++++++ 7 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json diff --git a/paw-aareg-client/README.md b/paw-aareg-client/README.md index e9508b13..0edf2934 100644 --- a/paw-aareg-client/README.md +++ b/paw-aareg-client/README.md @@ -4,9 +4,12 @@ Henter arbeidsforhold fra Arbeidsgiver- og arbeidstakerregisteret ([aareg](https Se URL-er på https://github.com/navikt/aareg-services +Se dokumentasjon for aareg på https://aareg-services.dev.intern.nav.no/swagger-ui/index.html + ### Bruk av paw-aareg-client -***gradle.build.kts*** +**_gradle.build.kts_** + ```kts val tokenproviderVersion: String by project val aaregClientVersion: String by project @@ -16,7 +19,7 @@ dependencies { implementation("no.nav.paw:aareg-client:$aaregClientVersion") } ``` - + ### Klienten instansieres slik ```kt diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index cad24585..83b5b5b0 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.4" +version = "0.1.5" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt index 404c1069..77c680f1 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt @@ -34,6 +34,7 @@ class AaregClient( header("Nav-Call-Id", callId) header("Nav-Personident", ident) }.also { + aaregClientLogger.info("Hentet arbeidsforhold fra aareg med status=$it.status()") sikkerLogg.debug("Svar fra aareg-API: " + it.bodyAsText()) }.body>() return payload diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt index 8481299e..ec66e94e 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt @@ -22,7 +22,7 @@ data class Arbeidsavtale( @Serializable data class Ansettelsesperiode( - val periode: Periode + val periode: Periode? ) @Serializable diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt index fe56a82a..d94356a0 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -18,6 +18,15 @@ class AaregClientTest { } assertTrue(response.any { it.arbeidsgiver.organisasjonsnummer == "896929119" }) } + + @Test + fun `Returnerer gyldig objekt når ingen perioder`() { + val response = runBlocking { + mockAaregClient(MockResponse.ingenArbeidsforhold) + .hentArbeidsforhold("ident", "call-id") + } + assertTrue(response.any { it.ansettelsesperiode.periode == null }) + } // // @Test // fun test_OK_svar_Med_Uventet_JSON() { diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt index 9aebc5d4..07bd9085 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt @@ -14,6 +14,8 @@ import kotlin.reflect.KFunction object MockResponse { val arbeidsforhold = "aareg-arbeidsforhold.json".readResource() + val ingenArbeidsforhold = "aareg-ingen-arbeidsforhold.json".readResource() + val error = "error.json".readResource() } fun mockAaregClient(content: String, statusCode: HttpStatusCode = HttpStatusCode.OK): AaregClient { diff --git a/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json b/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json new file mode 100644 index 00000000..b0d24322 --- /dev/null +++ b/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json @@ -0,0 +1,161 @@ +[ + { + "navArbeidsforholdId": 51505573, + "arbeidsforholdId": "1", + "arbeidstaker": { + "type": "Person", + "offentligIdent": "22018520056", + "aktoerId": "2884609777831" + }, + "arbeidsgiver": { + "type": "Organisasjon", + "organisasjonsnummer": "896929119" + }, + "opplysningspliktig": { + "type": "Organisasjon", + "organisasjonsnummer": "928497704" + }, + "type": "ordinaertArbeidsforhold", + "ansettelsesperiode": { + "bruksperiode": { + "fom": "2021-01-22T12:07:35.844" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + }, + "arbeidsavtaler": [ + { + "type": "Ordinaer", + "arbeidstidsordning": "ikkeSkift", + "yrke": "3310101", + "stillingsprosent": 100.0, + "antallTimerPrUke": 37.5, + "beregnetAntallTimerPrUke": 37.5, + "bruksperiode": { + "fom": "2021-01-22T12:07:35.844" + }, + "gyldighetsperiode": { + "fom": "2001-01-01" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + } + ], + "varsler": [ + { + "entitet": "ARBEIDSFORHOLD", + "varslingskode": "NAVEND" + } + ], + "innrapportertEtterAOrdningen": true, + "registrert": "2021-01-22T12:07:35.785", + "sistBekreftet": "2021-01-22T12:07:35", + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-01-22T12:07:35.844", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", + "endretTidspunkt": "2021-01-22T12:07:35.844", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" + } + }, + { + "navArbeidsforholdId": 51507953, + "arbeidsforholdId": "2", + "arbeidstaker": { + "type": "Person", + "offentligIdent": "22018520056", + "aktoerId": "2884609777831" + }, + "arbeidsgiver": { + "type": "Organisasjon", + "organisasjonsnummer": "896929119" + }, + "opplysningspliktig": { + "type": "Organisasjon", + "organisasjonsnummer": "928497704" + }, + "type": "ordinaertArbeidsforhold", + "ansettelsesperiode": { + "periode": { + "fom": "2001-03-15" + }, + "bruksperiode": { + "fom": "2021-03-15T12:45:29.413" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + }, + "arbeidsavtaler": [ + { + "type": "Ordinaer", + "arbeidstidsordning": "ikkeSkift", + "yrke": "5221126", + "stillingsprosent": 100.0, + "antallTimerPrUke": 37.5, + "beregnetAntallTimerPrUke": 37.5, + "bruksperiode": { + "fom": "2021-03-15T12:45:29.413" + }, + "gyldighetsperiode": { + "fom": "2001-03-01" + }, + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + } + ], + "varsler": [ + { + "entitet": "ARBEIDSFORHOLD", + "varslingskode": "NAVEND" + } + ], + "innrapportertEtterAOrdningen": true, + "registrert": "2021-03-15T12:45:29.319", + "sistBekreftet": "2021-03-15T12:45:29", + "sporingsinformasjon": { + "opprettetTidspunkt": "2021-03-15T12:45:29.413", + "opprettetAv": "srvtestnorge-aareg", + "opprettetKilde": "AAREG", + "opprettetKildereferanse": "DOLLY", + "endretTidspunkt": "2021-03-15T12:45:29.413", + "endretAv": "srvtestnorge-aareg", + "endretKilde": "AAREG", + "endretKildereferanse": "DOLLY" + } + } +] \ No newline at end of file From 1e661c3b3ffd65374aba37481f249b97150a51f3 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 17 Apr 2023 17:14:10 +0200 Subject: [PATCH 23/64] =?UTF-8?q?Revert:=20H=C3=A5ndterer=20ingen=20period?= =?UTF-8?q?er=20i=20ansettelseperioder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/aareg-ingen-arbeidsforhold.json | 161 ------------------ 1 file changed, 161 deletions(-) delete mode 100644 paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json diff --git a/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json b/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json deleted file mode 100644 index b0d24322..00000000 --- a/paw-aareg-client/src/test/resources/aareg-ingen-arbeidsforhold.json +++ /dev/null @@ -1,161 +0,0 @@ -[ - { - "navArbeidsforholdId": 51505573, - "arbeidsforholdId": "1", - "arbeidstaker": { - "type": "Person", - "offentligIdent": "22018520056", - "aktoerId": "2884609777831" - }, - "arbeidsgiver": { - "type": "Organisasjon", - "organisasjonsnummer": "896929119" - }, - "opplysningspliktig": { - "type": "Organisasjon", - "organisasjonsnummer": "928497704" - }, - "type": "ordinaertArbeidsforhold", - "ansettelsesperiode": { - "bruksperiode": { - "fom": "2021-01-22T12:07:35.844" - }, - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-01-22T12:07:35.844", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", - "endretTidspunkt": "2021-01-22T12:07:35.844", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" - } - }, - "arbeidsavtaler": [ - { - "type": "Ordinaer", - "arbeidstidsordning": "ikkeSkift", - "yrke": "3310101", - "stillingsprosent": 100.0, - "antallTimerPrUke": 37.5, - "beregnetAntallTimerPrUke": 37.5, - "bruksperiode": { - "fom": "2021-01-22T12:07:35.844" - }, - "gyldighetsperiode": { - "fom": "2001-01-01" - }, - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-01-22T12:07:35.844", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", - "endretTidspunkt": "2021-01-22T12:07:35.844", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" - } - } - ], - "varsler": [ - { - "entitet": "ARBEIDSFORHOLD", - "varslingskode": "NAVEND" - } - ], - "innrapportertEtterAOrdningen": true, - "registrert": "2021-01-22T12:07:35.785", - "sistBekreftet": "2021-01-22T12:07:35", - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-01-22T12:07:35.844", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8", - "endretTidspunkt": "2021-01-22T12:07:35.844", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "Dolly 92e7cef8-7097-4cf5-8ffa-b9960d0dd3f8" - } - }, - { - "navArbeidsforholdId": 51507953, - "arbeidsforholdId": "2", - "arbeidstaker": { - "type": "Person", - "offentligIdent": "22018520056", - "aktoerId": "2884609777831" - }, - "arbeidsgiver": { - "type": "Organisasjon", - "organisasjonsnummer": "896929119" - }, - "opplysningspliktig": { - "type": "Organisasjon", - "organisasjonsnummer": "928497704" - }, - "type": "ordinaertArbeidsforhold", - "ansettelsesperiode": { - "periode": { - "fom": "2001-03-15" - }, - "bruksperiode": { - "fom": "2021-03-15T12:45:29.413" - }, - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-03-15T12:45:29.413", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "DOLLY", - "endretTidspunkt": "2021-03-15T12:45:29.413", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "DOLLY" - } - }, - "arbeidsavtaler": [ - { - "type": "Ordinaer", - "arbeidstidsordning": "ikkeSkift", - "yrke": "5221126", - "stillingsprosent": 100.0, - "antallTimerPrUke": 37.5, - "beregnetAntallTimerPrUke": 37.5, - "bruksperiode": { - "fom": "2021-03-15T12:45:29.413" - }, - "gyldighetsperiode": { - "fom": "2001-03-01" - }, - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-03-15T12:45:29.413", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "DOLLY", - "endretTidspunkt": "2021-03-15T12:45:29.413", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "DOLLY" - } - } - ], - "varsler": [ - { - "entitet": "ARBEIDSFORHOLD", - "varslingskode": "NAVEND" - } - ], - "innrapportertEtterAOrdningen": true, - "registrert": "2021-03-15T12:45:29.319", - "sistBekreftet": "2021-03-15T12:45:29", - "sporingsinformasjon": { - "opprettetTidspunkt": "2021-03-15T12:45:29.413", - "opprettetAv": "srvtestnorge-aareg", - "opprettetKilde": "AAREG", - "opprettetKildereferanse": "DOLLY", - "endretTidspunkt": "2021-03-15T12:45:29.413", - "endretAv": "srvtestnorge-aareg", - "endretKilde": "AAREG", - "endretKildereferanse": "DOLLY" - } - } -] \ No newline at end of file From 2962ed64fa4a35d9f6c1ccf4eebe09b3f9a8f6d1 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Mon, 17 Apr 2023 17:15:42 +0200 Subject: [PATCH 24/64] =?UTF-8?q?Revert:=20H=C3=A5ndterer=20ingen=20period?= =?UTF-8?q?er=20i=20ansettelseperioder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-aareg-client/build.gradle.kts | 2 +- .../src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 2 +- .../src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt | 9 --------- .../src/test/kotlin/no/nav/paw/aareg/MockUtils.kt | 1 - 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index 83b5b5b0..ad61be8d 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.5" +version = "0.1.6" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt index ec66e94e..8481299e 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt @@ -22,7 +22,7 @@ data class Arbeidsavtale( @Serializable data class Ansettelsesperiode( - val periode: Periode? + val periode: Periode ) @Serializable diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt index d94356a0..fe56a82a 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -18,15 +18,6 @@ class AaregClientTest { } assertTrue(response.any { it.arbeidsgiver.organisasjonsnummer == "896929119" }) } - - @Test - fun `Returnerer gyldig objekt når ingen perioder`() { - val response = runBlocking { - mockAaregClient(MockResponse.ingenArbeidsforhold) - .hentArbeidsforhold("ident", "call-id") - } - assertTrue(response.any { it.ansettelsesperiode.periode == null }) - } // // @Test // fun test_OK_svar_Med_Uventet_JSON() { diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt index 07bd9085..757a12bb 100644 --- a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt +++ b/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt @@ -14,7 +14,6 @@ import kotlin.reflect.KFunction object MockResponse { val arbeidsforhold = "aareg-arbeidsforhold.json".readResource() - val ingenArbeidsforhold = "aareg-ingen-arbeidsforhold.json".readResource() val error = "error.json".readResource() } From c04f7580daa6d5b8426857e62d3a15d547ed148e Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Tue, 18 Apr 2023 12:22:23 +0200 Subject: [PATCH 25/64] Logger riktig status ved suksess --- paw-aareg-client/build.gradle.kts | 2 +- .../main/kotlin/no/nav/paw/aareg/AaregClient.kt | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index ad61be8d..fce025e3 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.6" +version = "0.1.7" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt index 77c680f1..7ec7a162 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt @@ -21,8 +21,8 @@ class AaregClient( private val url: String, private val getAccessToken: () -> String ) { - private val sikkerLogg: Logger = LoggerFactory.getLogger("tjenestekall") - private val aaregClientLogger: Logger = LoggerFactory.getLogger("paw-aareg-client") + private val sikkerLogger: Logger = LoggerFactory.getLogger("tjenestekall") + private val logger: Logger = LoggerFactory.getLogger("paw-aareg-client") private val httpClient = createHttpClient() suspend fun hentArbeidsforhold(ident: String, callId: String): List { @@ -34,19 +34,19 @@ class AaregClient( header("Nav-Call-Id", callId) header("Nav-Personident", ident) }.also { - aaregClientLogger.info("Hentet arbeidsforhold fra aareg med status=$it.status()") - sikkerLogg.debug("Svar fra aareg-API: " + it.bodyAsText()) + logger.info("Hentet arbeidsforhold fra aareg med status=${it.status}") + sikkerLogger.debug("Svar fra aareg-API: " + it.bodyAsText()) }.body>() return payload } catch (responseException: ResponseException) { - aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet med http-kode ${responseException.response.status}") + logger.error("Hente arbeidsforhold callId=[$callId] feilet med http-kode ${responseException.response.status}") throw responseException } catch (connectException: ConnectException) { - aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet:", connectException) + logger.error("Hente arbeidsforhold callId=[$callId] feilet:", connectException) throw connectException } catch (jsonConvertException: JsonConvertException) { - aaregClientLogger.error("Hente arbeidsforhold callId=[$callId] feilet, kunne ikke lese JSON") - sikkerLogg.error("Hente arbeidsforhold callId=[$callId] feilet", jsonConvertException) + logger.error("Hente arbeidsforhold callId=[$callId] feilet, kunne ikke lese JSON") + sikkerLogger.error("Hente arbeidsforhold callId=[$callId] feilet", jsonConvertException) throw jsonConvertException } } From c2bc61fd2357fe1fa99d9055632f53cf8dbcd5e9 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Wed, 19 Apr 2023 14:08:13 +0200 Subject: [PATCH 26/64] =?UTF-8?q?Endre=20stillingsprosent=20i=20arbeidsavt?= =?UTF-8?q?ale=20til=20=C3=A5=20v=C3=A6re=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-aareg-client/build.gradle.kts | 2 +- .../src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index fce025e3..f1493232 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.7" +version = "0.1.8" tasks { withType { diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt index 8481299e..31ac11db 100644 --- a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt +++ b/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt @@ -16,7 +16,7 @@ data class Arbeidsforhold( @Serializable data class Arbeidsavtale( - val stillingsprosent: Double, + val stillingsprosent: Double?, val gyldighetsperiode: Periode ) From 32efc94c18c0f5604f007ba920b06047cf13220f Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Fri, 9 Jun 2023 10:06:11 +0200 Subject: [PATCH 27/64] Legger til callId og consumerId --- paw-pdl-client/build.gradle.kts | 2 +- paw-pdl-client/gradle.properties | 2 +- .../src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt | 12 ++++++------ .../src/main/kotlin/no/nav/paw/pdl/PdlClient.kt | 5 ++++- .../src/test/kotlin/no/nav/paw/MockPdlClient.kt | 2 +- .../src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt | 8 +++++--- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index c73dc0e0..443f4814 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.1.4" +version = "0.2.0" plugins { kotlin("jvm") diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index d6bde9f8..851e1f52 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -8,5 +8,5 @@ graphQLKotlinVersion=6.4.0 # Dependency versions coroutinesVersion=1.6.4 kotlinSerializationVersion=1.4.0 -ktorVersion=2.1.1 +ktorVersion=2.3.1 mockkVersion=1.12.7 diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt index b14837f8..e216a85d 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt @@ -4,23 +4,23 @@ import no.nav.paw.pdl.graphql.generated.HentIdenter import no.nav.paw.pdl.graphql.generated.enums.IdentGruppe import no.nav.paw.pdl.graphql.generated.hentidenter.IdentInformasjon -suspend fun PdlClient.hentAktorId(ident: String): String? = hentIdenter(ident) +suspend fun PdlClient.hentAktorId(ident: String, callId: String): String? = hentIdenter(ident, callId) ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } ?.ident -suspend fun PdlClient.hentIdenter(ident: String): List? { +suspend fun PdlClient.hentIdenter(ident: String, callId: String): List? { val query = HentIdenter(HentIdenter.Variables(ident)) - logger.info("Henter 'aktorId' fra PDL") + logger.info("Henter 'hentIdenter' fra PDL") - val respons = execute(query) + val respons = execute(query, callId) respons.errors?.let { - logger.error("Henter 'aktorId' fra PDL feilet med: ${respons.errors}") + logger.error("Henter 'hentIdenter' fra PDL feilet med: ${respons.errors}") throw PdlException(it) } - logger.info("Hentet 'aktorId' fra PDL") + logger.info("Hentet 'hentIdenter' fra PDL") return respons .data diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index 3d4c5e08..178a9d77 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -15,6 +15,7 @@ class PdlClient( url: String, // Tema: https://confluence.adeo.no/pages/viewpage.action?pageId=309311397 private val tema: String, + private val navConsumerId: String, httpClient: HttpClient, private val getAccessToken: () -> String ) { @@ -25,10 +26,12 @@ class PdlClient( httpClient = httpClient ) - internal suspend fun execute(query: GraphQLClientRequest): GraphQLClientResponse = + internal suspend fun execute(query: GraphQLClientRequest, callId: String): GraphQLClientResponse = graphQLClient.execute(query) { bearerAuth(getAccessToken()) header("Tema", tema) + header("Nav-Call-Id", callId) + header("Nav-Consumer-Id", navConsumerId) } } diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt index f275fab2..e310922c 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -17,5 +17,5 @@ fun mockPdlClient(content: String): PdlClient { headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) ) } - return PdlClient("https://url", "tema", HttpClient(mockEngine)) { "fake token" } + return PdlClient("https://url", "tema", "consumerId", HttpClient(mockEngine)) { "fake token" } } diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 21a59491..82098154 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -2,17 +2,19 @@ package no.nav.paw.pdl import kotlinx.coroutines.runBlocking import no.nav.paw.mockPdlClient +import java.util.UUID import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith class PdlClientTest { + val callId = UUID.randomUUID().toString() @Test fun `Forventer gyldig respons fra hentAktorId`() { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentAktorId("2649500819544") } + val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId) } val forventet = "2649500819544" assertEquals(forventet, resultat) } @@ -24,7 +26,7 @@ class PdlClientTest { assertFailsWith( block = { runBlocking { - pdlClient.hentIdenter("2649500819544") + pdlClient.hentIdenter("2649500819544", callId) } } ) @@ -35,7 +37,7 @@ class PdlClientTest { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentIdenter("2649500819544") } + val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId) } val forventet = "09127821914" assertEquals(forventet, resultat!!.first().ident) } From 8abf34c30753a1679c9b819fc311a5fca4997296 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 29 Jun 2023 17:02:36 +0200 Subject: [PATCH 28/64] Fix lint --- paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 82098154..1b21f6a2 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -9,6 +9,7 @@ import kotlin.test.assertFailsWith class PdlClientTest { val callId = UUID.randomUUID().toString() + @Test fun `Forventer gyldig respons fra hentAktorId`() { val respons = readResource("hentIdenter-response.json") From f5cdae7d0d12955f0273bd81d7603c6bdb1a1a48 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Tue, 3 Oct 2023 13:04:13 +0200 Subject: [PATCH 29/64] Legger til workflow permissions til write packages --- .github/workflows/paw-aareg-client.yml | 2 ++ .github/workflows/paw-pdl-client.yml | 2 ++ .../kotlin/no/nav/paw/pdl/{HentAktorId.kt => HentIdenter.kt} | 0 3 files changed, 4 insertions(+) rename paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/{HentAktorId.kt => HentIdenter.kt} (100%) diff --git a/.github/workflows/paw-aareg-client.yml b/.github/workflows/paw-aareg-client.yml index 032c7093..b734776e 100644 --- a/.github/workflows/paw-aareg-client.yml +++ b/.github/workflows/paw-aareg-client.yml @@ -11,6 +11,8 @@ jobs: build: name: Build and push runs-on: ubuntu-latest + permissions: + packages: write steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index 4787f6ab..3042fbe1 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -11,6 +11,8 @@ jobs: build: name: Build and push runs-on: ubuntu-latest + permissions: + packages: write steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentAktorId.kt rename to paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt From 3b531cfe0eac8b1037e18883f24a59a37b18cbd7 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Tue, 3 Oct 2023 13:04:53 +0200 Subject: [PATCH 30/64] Oppdaterer klient og legger til hentOpphold --- paw-pdl-client/build.gradle.kts | 7 +- paw-pdl-client/gradle.properties | 8 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- paw-pdl-client/gradlew | 6 - paw-pdl-client/gradlew.bat | 180 +++++++++--------- .../main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 6 +- .../main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 24 +++ .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 7 +- .../src/main/kotlin/no/nav/paw/pdl/Utils.kt | 2 +- .../src/main/resources/hentOpphold.graphql | 9 + .../test/kotlin/no/nav/paw/MockPdlClient.kt | 4 +- .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 23 ++- .../test/resources/hentOpphold-response.json | 13 ++ 14 files changed, 169 insertions(+), 122 deletions(-) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt create mode 100644 paw-pdl-client/src/main/resources/hentOpphold.graphql create mode 100644 paw-pdl-client/src/test/resources/hentOpphold-response.json diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 443f4814..b1f2ab5e 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.2.0" +version = "0.3.1" plugins { kotlin("jvm") @@ -13,7 +13,7 @@ plugins { tasks { withType { - kotlinOptions.jvmTarget = "11" + kotlinOptions.jvmTarget = "17" } test { useJUnitPlatform() @@ -27,9 +27,6 @@ tasks { } java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - withSourcesJar() } diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index 851e1f52..5ad38ef1 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -1,12 +1,12 @@ kotlin.code.style=official # Plugin versions -kotlinVersion=1.7.10 -kotlinterVersion=3.12.0 -graphQLKotlinVersion=6.4.0 +kotlinVersion=1.9.10 +kotlinterVersion=3.16.0 +graphQLKotlinVersion=7.0.1 # Dependency versions coroutinesVersion=1.6.4 kotlinSerializationVersion=1.4.0 -ktorVersion=2.3.1 +ktorVersion=2.3.4 mockkVersion=1.12.7 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar b/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 9041 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 delta 10158 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 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties index f72df95a..db9a6b82 100644 --- a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties +++ b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/paw-pdl-client/gradlew b/paw-pdl-client/gradlew index a69d9cb6..1b6c7873 100755 --- a/paw-pdl-client/gradlew +++ b/paw-pdl-client/gradlew @@ -205,12 +205,6 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/paw-pdl-client/gradlew.bat b/paw-pdl-client/gradlew.bat index f127cfd4..ac1b06f9 100644 --- a/paw-pdl-client/gradlew.bat +++ b/paw-pdl-client/gradlew.bat @@ -1,91 +1,89 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index e216a85d..3136e807 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -4,16 +4,16 @@ import no.nav.paw.pdl.graphql.generated.HentIdenter import no.nav.paw.pdl.graphql.generated.enums.IdentGruppe import no.nav.paw.pdl.graphql.generated.hentidenter.IdentInformasjon -suspend fun PdlClient.hentAktorId(ident: String, callId: String): String? = hentIdenter(ident, callId) +suspend fun PdlClient.hentAktorId(ident: String, callId: String?, navConsumerId: String?): String? = hentIdenter(ident, callId, navConsumerId) ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } ?.ident -suspend fun PdlClient.hentIdenter(ident: String, callId: String): List? { +suspend fun PdlClient.hentIdenter(ident: String, callId: String?, navConsumerId: String?): List? { val query = HentIdenter(HentIdenter.Variables(ident)) logger.info("Henter 'hentIdenter' fra PDL") - val respons = execute(query, callId) + val respons = execute(query, callId, navConsumerId) respons.errors?.let { logger.error("Henter 'hentIdenter' fra PDL feilet med: ${respons.errors}") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt new file mode 100644 index 00000000..9f2b7a95 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt @@ -0,0 +1,24 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentOpphold +import no.nav.paw.pdl.graphql.generated.hentopphold.Opphold + +suspend fun PdlClient.hentOpphold(ident: String, callId: String?, navConsumerId: String?): List? { + val query = HentOpphold(HentOpphold.Variables(ident)) + + logger.info("Henter 'hentPerson' fra PDL") + + val respons = execute(query, callId, navConsumerId) + + respons.errors?.let { + logger.error("Henter 'hentPerson' fra PDL feilet med: ${respons.errors}") + throw PdlException(it) + } + + logger.info("Hentet 'hentPerson' fra PDL") + + return respons + .data + ?.hentPerson + ?.opphold +} diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index 178a9d77..49e71868 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -15,18 +15,17 @@ class PdlClient( url: String, // Tema: https://confluence.adeo.no/pages/viewpage.action?pageId=309311397 private val tema: String, - private val navConsumerId: String, httpClient: HttpClient, - private val getAccessToken: () -> String + private val getAccessToken: () -> String, ) { internal val logger = LoggerFactory.getLogger(this::class.java) private val graphQLClient = GraphQLKtorClient( url = URL(url), - httpClient = httpClient + httpClient = httpClient, ) - internal suspend fun execute(query: GraphQLClientRequest, callId: String): GraphQLClientResponse = + internal suspend fun execute(query: GraphQLClientRequest, callId: String?, navConsumerId: String?): GraphQLClientResponse = graphQLClient.execute(query) { bearerAuth(getAccessToken()) header("Tema", tema) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt index cda7635e..bd8df7ee 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt @@ -18,7 +18,7 @@ internal fun HttpClientConfig<*>.configureJsonHandler() { Json { ignoreUnknownKeys = true explicitNulls = false - } + }, ) } } diff --git a/paw-pdl-client/src/main/resources/hentOpphold.graphql b/paw-pdl-client/src/main/resources/hentOpphold.graphql new file mode 100644 index 00000000..a4255d86 --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentOpphold.graphql @@ -0,0 +1,9 @@ +query($ident: ID!) { + hentPerson(ident: $ident) { + opphold { + type + oppholdFra + oppholdTil + } + } +} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt index e310922c..9c3c2219 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -14,8 +14,8 @@ fun mockPdlClient(content: String): PdlClient { respond( content = content, status = HttpStatusCode.OK, - headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()), ) } - return PdlClient("https://url", "tema", "consumerId", HttpClient(mockEngine)) { "fake token" } + return PdlClient("https://url", "tema", HttpClient(mockEngine)) { "fake token" } } diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 1b21f6a2..b668302a 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -2,20 +2,23 @@ package no.nav.paw.pdl import kotlinx.coroutines.runBlocking import no.nav.paw.mockPdlClient -import java.util.UUID +import no.nav.paw.pdl.graphql.generated.enums.Oppholdstillatelse +import no.nav.paw.pdl.graphql.generated.hentopphold.Opphold +import java.util.* import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith class PdlClientTest { val callId = UUID.randomUUID().toString() + val navConsumerId = "nav-consumer-id" @Test fun `Forventer gyldig respons fra hentAktorId`() { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId) } + val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId, navConsumerId) } val forventet = "2649500819544" assertEquals(forventet, resultat) } @@ -27,9 +30,9 @@ class PdlClientTest { assertFailsWith( block = { runBlocking { - pdlClient.hentIdenter("2649500819544", callId) + pdlClient.hentIdenter("2649500819544", callId, navConsumerId) } - } + }, ) } @@ -38,10 +41,20 @@ class PdlClientTest { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId) } + val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId, navConsumerId) } val forventet = "09127821914" assertEquals(forventet, resultat!!.first().ident) } + + @Test + fun `Forventer gyldig respons fra hentOpphold`() { + val respons = readResource("hentOpphold-response.json") + val pdlClient = mockPdlClient(respons) + + val resultat = runBlocking { pdlClient.hentOpphold("2649500819544", callId, navConsumerId) } + val forventet = Oppholdstillatelse.PERMANENT + assertEquals(forventet, resultat!!.first().type) + } } private fun readResource(filename: String) = diff --git a/paw-pdl-client/src/test/resources/hentOpphold-response.json b/paw-pdl-client/src/test/resources/hentOpphold-response.json new file mode 100644 index 00000000..ae95b68a --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentOpphold-response.json @@ -0,0 +1,13 @@ +{ + "data": { + "hentPerson": { + "opphold": [ + { + "type": "PERMANENT", + "oppholdFra": "2010-01-20", + "oppholdTil": "2022-01-20" + } + ] + } + } +} \ No newline at end of file From f77c7ebcc91db249cdcc744eedf0f846c50d9e14 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Tue, 3 Oct 2023 13:19:50 +0200 Subject: [PATCH 31/64] Fjerne ubrukt import --- paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index b668302a..63bef6af 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -3,7 +3,6 @@ package no.nav.paw.pdl import kotlinx.coroutines.runBlocking import no.nav.paw.mockPdlClient import no.nav.paw.pdl.graphql.generated.enums.Oppholdstillatelse -import no.nav.paw.pdl.graphql.generated.hentopphold.Opphold import java.util.* import kotlin.test.Test import kotlin.test.assertEquals From de3238c383c4f4f1481c27006d60ff52d5fea218 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 20 Dec 2023 08:53:47 +0100 Subject: [PATCH 32/64] La til 'hentPerson' --- .../main/kotlin/no/nav/paw/pdl/HentPerson.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt new file mode 100644 index 00000000..ce282a42 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -0,0 +1,23 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentPerson +import no.nav.paw.pdl.graphql.generated.hentperson.Person + +suspend fun PdlClient.hentPerson(ident: String, callId: String?, navConsumerId: String?): Person? { + val query = HentPerson(HentPerson.Variables(ident)) + + logger.info("Henter 'hentPerson' fra PDL") + + val respons = execute(query, callId, navConsumerId) + + respons.errors?.let { + logger.error("Henter 'hentPerson' fra PDL feilet med: ${respons.errors}") + throw PdlException(it) + } + + logger.info("Hentet 'hentPerson' fra PDL") + + return respons + .data + ?.hentPerson +} From 3cc86945e44cebfc52f900319df33633853aa1aa Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 20 Dec 2023 09:43:29 +0100 Subject: [PATCH 33/64] =?UTF-8?q?La=20til=20initiell=20st=C3=B8tte=20for?= =?UTF-8?q?=20=C3=A5=20hente=20basis=20info=20om=20en=20person=20(f=C3=B8d?= =?UTF-8?q?selsdato,=20adresse=20og=20oppholdtilatelse)=20i=20et=20kall?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-pdl-client/build.gradle.kts | 3 ++ .../main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 8 +++-- .../main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 8 +++-- .../main/kotlin/no/nav/paw/pdl/HentPerson.kt | 16 +++++++--- .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 14 ++++++-- .../src/main/resources/hentPerson.graphql | 32 +++++++++++++++++++ 6 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 paw-pdl-client/src/main/resources/hentPerson.graphql diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index b1f2ab5e..bbe7f0be 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -28,6 +28,9 @@ tasks { java { withSourcesJar() + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } } repositories { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index 3136e807..7106555c 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -13,11 +13,15 @@ suspend fun PdlClient.hentIdenter(ident: String, callId: String?, navConsumerId: logger.info("Henter 'hentIdenter' fra PDL") - val respons = execute(query, callId, navConsumerId) + val respons = execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + ) respons.errors?.let { logger.error("Henter 'hentIdenter' fra PDL feilet med: ${respons.errors}") - throw PdlException(it) + throw PdlException("'hentIdenter' fra pdl feilet", it) } logger.info("Hentet 'hentIdenter' fra PDL") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt index 9f2b7a95..08e9f33e 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt @@ -8,11 +8,15 @@ suspend fun PdlClient.hentOpphold(ident: String, callId: String?, navConsumerId: logger.info("Henter 'hentPerson' fra PDL") - val respons = execute(query, callId, navConsumerId) + val respons = execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + ) respons.errors?.let { logger.error("Henter 'hentPerson' fra PDL feilet med: ${respons.errors}") - throw PdlException(it) + throw PdlException("'hentPerson' feilet", it) } logger.info("Hentet 'hentPerson' fra PDL") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index ce282a42..b9fa50de 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -3,16 +3,24 @@ package no.nav.paw.pdl import no.nav.paw.pdl.graphql.generated.HentPerson import no.nav.paw.pdl.graphql.generated.hentperson.Person -suspend fun PdlClient.hentPerson(ident: String, callId: String?, navConsumerId: String?): Person? { +suspend fun PdlClient.hentPerson( + ident: String, + callId: String?, + traceparent: String? = null, + navConsumerId: String? +): Person? { val query = HentPerson(HentPerson.Variables(ident)) logger.info("Henter 'hentPerson' fra PDL") - val respons = execute(query, callId, navConsumerId) + val respons = execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + ) respons.errors?.let { - logger.error("Henter 'hentPerson' fra PDL feilet med: ${respons.errors}") - throw PdlException(it) + throw PdlException("'hentPerson' feilet", it) } logger.info("Hentet 'hentPerson' fra PDL") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index 49e71868..dcd9f47a 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -8,6 +8,7 @@ import io.ktor.client.HttpClient import io.ktor.client.request.bearerAuth import io.ktor.client.request.header import org.slf4j.LoggerFactory +import java.io.IOException import java.net.URL // Se https://pdldocs-navno.msappproxy.net/ for dokumentasjon av PDL API-et @@ -25,13 +26,22 @@ class PdlClient( httpClient = httpClient, ) - internal suspend fun execute(query: GraphQLClientRequest, callId: String?, navConsumerId: String?): GraphQLClientResponse = + internal suspend fun execute( + query: GraphQLClientRequest, + callId: String?, + traceparent: String? = null, + navConsumerId: String?, + ): GraphQLClientResponse = graphQLClient.execute(query) { bearerAuth(getAccessToken()) header("Tema", tema) header("Nav-Call-Id", callId) header("Nav-Consumer-Id", navConsumerId) + traceparent?.let { header("traceparent", it) } } } -class PdlException(val errors: List?) : RuntimeException() +class PdlException( + message: String? = null, + val errors: List?, +) : IOException(message) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql new file mode 100644 index 00000000..5ecd200a --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -0,0 +1,32 @@ +query($ident: ID!) { + hentPerson(ident: $ident) { + foedsel { + foedselsdato + foedselsaar + } + opphold { + oppholdFra + oppholdTil + } + bostedsadresse { + vegadresse { + adressenavn + husnummer + husbokstav + postnummer + kommunenummer + } + matrikkeladresse { + postnummer + kommunenummer + tilleggsnavn + } + utenlandskAdresse { + adressenavnNummer + bySted + regionDistriktOmraade + landkode + } + } + } +} From 3da9449a0007507611c259a98b05bad59d948f3c Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 20 Dec 2023 13:24:53 +0100 Subject: [PATCH 34/64] Fikset linter feil --- paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index b9fa50de..5887ae8c 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -7,7 +7,7 @@ suspend fun PdlClient.hentPerson( ident: String, callId: String?, traceparent: String? = null, - navConsumerId: String? + navConsumerId: String?, ): Person? { val query = HentPerson(HentPerson.Variables(ident)) @@ -17,6 +17,7 @@ suspend fun PdlClient.hentPerson( query = query, callId = callId, navConsumerId = navConsumerId, + traceparent = traceparent, ) respons.errors?.let { From cf8496724fb547decaab52ceb5a1f8a29282b3ec Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 20 Dec 2023 13:40:36 +0100 Subject: [PATCH 35/64] Oppdaterte versjonsnummeret --- paw-pdl-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index bbe7f0be..cf7f9c8a 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.1" +version = "0.3.2" plugins { kotlin("jvm") From 1f82d7adf87e77a32201fdbefd05981eb85e480e Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Thu, 21 Dec 2023 12:27:14 +0100 Subject: [PATCH 36/64] =?UTF-8?q?endret=20hentPerson=20til=20=C3=A5=20inlk?= =?UTF-8?q?udere=20forenkletStatus=20folk.reg.=20status=20istedenfor=20ful?= =?UTF-8?q?l=20adresse=20info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-pdl-client/build.gradle.kts | 2 +- .../src/main/resources/hentPerson.graphql | 21 ++----------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index cf7f9c8a..75577346 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.2" +version = "0.3.3" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index 5ecd200a..2101f16e 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -8,25 +8,8 @@ query($ident: ID!) { oppholdFra oppholdTil } - bostedsadresse { - vegadresse { - adressenavn - husnummer - husbokstav - postnummer - kommunenummer - } - matrikkeladresse { - postnummer - kommunenummer - tilleggsnavn - } - utenlandskAdresse { - adressenavnNummer - bySted - regionDistriktOmraade - landkode - } + folkeregisterpersonstatus { + forenkletStatus } } } From 2490d4f372915bae6fd0faf10e9bc1e0442edd54 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Thu, 21 Dec 2023 14:54:50 +0100 Subject: [PATCH 37/64] Utvidet hentPerson (igjen) --- paw-pdl-client/build.gradle.kts | 2 +- .../main/kotlin/no/nav/paw/pdl/HentPerson.kt | 9 ++++-- .../src/main/resources/hentPerson.graphql | 29 ++++++++++++++++++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 75577346..b77bce03 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.3" +version = "0.3.4" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index 5887ae8c..dcb20581 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -8,10 +8,13 @@ suspend fun PdlClient.hentPerson( callId: String?, traceparent: String? = null, navConsumerId: String?, + historisk: Boolean = false, ): Person? { - val query = HentPerson(HentPerson.Variables(ident)) + val query = HentPerson( + HentPerson.Variables(ident, false), + ) - logger.info("Henter 'hentPerson' fra PDL") + logger.trace("Henter 'hentPerson' fra PDL") val respons = execute( query = query, @@ -24,7 +27,7 @@ suspend fun PdlClient.hentPerson( throw PdlException("'hentPerson' feilet", it) } - logger.info("Hentet 'hentPerson' fra PDL") + logger.trace("Hentet 'hentPerson' fra PDL") return respons .data diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index 2101f16e..63500777 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -1,4 +1,4 @@ -query($ident: ID!) { +query($ident: ID!, $historisk: Boolean) { hentPerson(ident: $ident) { foedsel { foedselsdato @@ -7,9 +7,36 @@ query($ident: ID!) { opphold { oppholdFra oppholdTil + type } folkeregisterpersonstatus { forenkletStatus } + bostedsadresse(historikk: $historisk) { + angittFlyttedato + gyldigFraOgMed + gyldigTilOgMed + vegadresse { + kommunenummer + } + matrikkeladresse { + kommunenummer + } + ukjentBosted { + bostedskommune + } + } + innflyttingTilNorge { + folkeregistermetadata { + gyldighetstidspunkt + ajourholdstidspunkt + } + } + utflyttingFraNorge { + folkeregistermetadata { + gyldighetstidspunkt + ajourholdstidspunkt + } + } } } From 75cad659feaa99000792d5b1d7a24b99ecfa8ba8 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Tue, 2 Jan 2024 09:06:36 +0100 Subject: [PATCH 38/64] La til 'utflyttingsDato' i 'hentPerson' --- paw-pdl-client/build.gradle.kts | 2 +- paw-pdl-client/src/main/resources/hentPerson.graphql | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index b77bce03..8419bf91 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.4" +version = "0.3.5" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index 63500777..f2c52a1e 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -33,6 +33,7 @@ query($ident: ID!, $historisk: Boolean) { } } utflyttingFraNorge { + utflyttingsdato folkeregistermetadata { gyldighetstidspunkt ajourholdstidspunkt From 3f7a19494856c1b58882a253e4c668dc18de0649 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 3 Jan 2024 11:51:48 +0100 Subject: [PATCH 39/64] La til 'utenlandskAdresse' --- paw-pdl-client/build.gradle.kts | 2 +- paw-pdl-client/src/main/resources/hentPerson.graphql | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 8419bf91..840a254e 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.5" +version = "0.3.6" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index f2c52a1e..df17549e 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -25,6 +25,9 @@ query($ident: ID!, $historisk: Boolean) { ukjentBosted { bostedskommune } + utenlandskAdresse { + landkode + } } innflyttingTilNorge { folkeregistermetadata { From 7a4541964b8e599595c33bbb336d7228288c1192 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Wed, 3 Jan 2024 12:01:45 +0100 Subject: [PATCH 40/64] Fikset 'historisk' alltid false for 'hentPerson' --- paw-pdl-client/build.gradle.kts | 2 +- paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 840a254e..23a3ed27 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.6" +version = "0.3.7" plugins { kotlin("jvm") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index dcb20581..40211db9 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -11,7 +11,7 @@ suspend fun PdlClient.hentPerson( historisk: Boolean = false, ): Person? { val query = HentPerson( - HentPerson.Variables(ident, false), + HentPerson.Variables(ident, historisk), ) logger.trace("Henter 'hentPerson' fra PDL") From 63a1c15336ee1a626c2e37a115becfd64c76632f Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 12 Jan 2024 13:03:20 +0100 Subject: [PATCH 41/64] =?UTF-8?q?La=20til=20st=C3=B8tte=20for=20=C3=A5=20h?= =?UTF-8?q?ente=20f=C3=B8dselsdato=20og=20=C3=A5r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/no/nav/paw/pdl/HentFoedsel.kt | 36 +++++++++++++++++++ .../src/main/resources/hentFoedsel.graphql | 8 +++++ 2 files changed, 44 insertions(+) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt create mode 100644 paw-pdl-client/src/main/resources/hentFoedsel.graphql diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt new file mode 100644 index 00000000..b02daeda --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt @@ -0,0 +1,36 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentFoedsel +import no.nav.paw.pdl.graphql.generated.hentfoedsel.Foedsel + +suspend fun PdlClient.hentFoedsel( + ident: String, + callId: String?, + traceparent: String? = null, + navConsumerId: String?, +): Foedsel? { + val query = HentFoedsel( + HentFoedsel.Variables(ident), + ) + + logger.trace("Henter 'hentFoedsel' fra PDL") + + val respons = execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + ) + + respons.errors?.let { + throw PdlException("'hentPerson' feilet", it) + } + + logger.trace("Hentet 'hentFoedsel' fra PDL") + + return respons + .data + ?.hentPerson + ?.foedsel + ?.firstOrNull() +} diff --git a/paw-pdl-client/src/main/resources/hentFoedsel.graphql b/paw-pdl-client/src/main/resources/hentFoedsel.graphql new file mode 100644 index 00000000..abd56026 --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentFoedsel.graphql @@ -0,0 +1,8 @@ +query($ident: ID!) { + hentPerson(ident: $ident) { + foedsel { + foedselsdato + foedselsaar + } + } +} From 1ea63334954685a98a524e3a39d53e086ce235da Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 12 Jan 2024 13:07:57 +0100 Subject: [PATCH 42/64] Endret til autogenerert versjonsnummer --- .github/workflows/paw-aareg-client.yml | 2 +- .github/workflows/paw-pdl-client.yml | 2 +- paw-aareg-client/build.gradle.kts | 2 +- paw-pdl-client/build.gradle.kts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/paw-aareg-client.yml b/.github/workflows/paw-aareg-client.yml index b734776e..9a08ceea 100644 --- a/.github/workflows/paw-aareg-client.yml +++ b/.github/workflows/paw-aareg-client.yml @@ -26,6 +26,6 @@ jobs: - name: Build with Gradle and Publish artifact working-directory: ./paw-aareg-client - run: ./gradlew build test publish + run: ./gradlew -Pversion=$(date +'%y.%m.%d').${{ github.run_number }}-${{ github.run_attempt }} build test publish env: ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml index 3042fbe1..2e291cf9 100644 --- a/.github/workflows/paw-pdl-client.yml +++ b/.github/workflows/paw-pdl-client.yml @@ -26,6 +26,6 @@ jobs: - name: Build with Gradle and Publish artifact working-directory: ./paw-pdl-client - run: ./gradlew build test publish + run: ./gradlew -Pversion=$(date +'%y.%m.%d').${{ github.run_number }}-${{ github.run_attempt }} build test publish env: ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index f1493232..bbfcd087 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "no.nav.paw" -version = "0.1.8" +version = "1.0-SNAPSHOT" tasks { withType { diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 23a3ed27..42c89d3c 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "0.3.7" +version = "1.0-SNAPSHOT" plugins { kotlin("jvm") From 225681d9ec8a59fc67d36b2623e6597a6e78fc3f Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 12 Jan 2024 13:14:39 +0100 Subject: [PATCH 43/64] Flyttet default versjonsnummer til gradle.properties --- paw-aareg-client/build.gradle.kts | 1 - paw-aareg-client/gradle.properties | 2 ++ paw-pdl-client/build.gradle.kts | 1 - paw-pdl-client/gradle.properties | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/paw-aareg-client/build.gradle.kts b/paw-aareg-client/build.gradle.kts index bbfcd087..c2f92199 100644 --- a/paw-aareg-client/build.gradle.kts +++ b/paw-aareg-client/build.gradle.kts @@ -9,7 +9,6 @@ plugins { } group = "no.nav.paw" -version = "1.0-SNAPSHOT" tasks { withType { diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties index 03be0b1c..691adc62 100644 --- a/paw-aareg-client/gradle.properties +++ b/paw-aareg-client/gradle.properties @@ -1,3 +1,5 @@ +version=1.0-SNAPSHOT + kotlin.code.style=official # Plugin versions diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 42c89d3c..f9efaee2 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -1,7 +1,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile group = "no.nav.paw" -version = "1.0-SNAPSHOT" plugins { kotlin("jvm") diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index 5ad38ef1..a24f500e 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -1,3 +1,5 @@ +version=1.0-SNAPSHOT + kotlin.code.style=official # Plugin versions From d42a412ec19b41e8bafd8b99d2df565e8e0f744e Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Sat, 9 Mar 2024 13:09:48 +0100 Subject: [PATCH 44/64] Oppdaterer avhengigheter og legger til test for hentPerson --- paw-pdl-client/build.gradle.kts | 4 +- paw-pdl-client/gradle.properties | 12 ++--- .../gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 43462 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 +- paw-pdl-client/gradlew | 41 ++++++++++++------ paw-pdl-client/gradlew.bat | 35 ++++++++------- .../main/kotlin/no/nav/paw/pdl/HentFoedsel.kt | 20 +++++---- .../main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 30 ++++++++----- .../main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 17 +++++--- .../main/kotlin/no/nav/paw/pdl/HentPerson.kt | 20 +++++---- .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 11 ++--- .../src/main/kotlin/no/nav/paw/pdl/Utils.kt | 3 +- .../test/kotlin/no/nav/paw/MockPdlClient.kt | 15 ++++--- .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 15 +++++-- .../test/resources/hentPerson-response.json | 39 +++++++++++++++++ 15 files changed, 177 insertions(+), 89 deletions(-) create mode 100644 paw-pdl-client/src/test/resources/hentPerson-response.json diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index f9efaee2..60587d9e 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -12,7 +12,7 @@ plugins { tasks { withType { - kotlinOptions.jvmTarget = "17" + kotlinOptions.jvmTarget = "21" } test { useJUnitPlatform() @@ -28,7 +28,7 @@ tasks { java { withSourcesJar() toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } } diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index a24f500e..ea20881b 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -3,12 +3,12 @@ version=1.0-SNAPSHOT kotlin.code.style=official # Plugin versions -kotlinVersion=1.9.10 -kotlinterVersion=3.16.0 -graphQLKotlinVersion=7.0.1 +kotlinVersion=1.9.23 +kotlinterVersion=4.2.0 +graphQLKotlinVersion=7.0.2 # Dependency versions coroutinesVersion=1.6.4 -kotlinSerializationVersion=1.4.0 -ktorVersion=2.3.4 -mockkVersion=1.12.7 +kotlinSerializationVersion=1.6.3 +ktorVersion=2.3.9 +mockkVersion=1.13.10 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar b/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 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 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties index db9a6b82..a80b22ce 100644 --- a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties +++ b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/paw-pdl-client/gradlew b/paw-pdl-client/gradlew index 1b6c7873..1aa94a42 100755 --- a/paw-pdl-client/gradlew +++ b/paw-pdl-client/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/paw-pdl-client/gradlew.bat b/paw-pdl-client/gradlew.bat index ac1b06f9..7101f8e4 100644 --- a/paw-pdl-client/gradlew.bat +++ b/paw-pdl-client/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt index b02daeda..27f5840d 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt @@ -9,18 +9,20 @@ suspend fun PdlClient.hentFoedsel( traceparent: String? = null, navConsumerId: String?, ): Foedsel? { - val query = HentFoedsel( - HentFoedsel.Variables(ident), - ) + val query = + HentFoedsel( + HentFoedsel.Variables(ident), + ) logger.trace("Henter 'hentFoedsel' fra PDL") - val respons = execute( - query = query, - callId = callId, - navConsumerId = navConsumerId, - traceparent = traceparent, - ) + val respons = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + ) respons.errors?.let { throw PdlException("'hentPerson' feilet", it) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index 7106555c..4aab1e90 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -4,20 +4,30 @@ import no.nav.paw.pdl.graphql.generated.HentIdenter import no.nav.paw.pdl.graphql.generated.enums.IdentGruppe import no.nav.paw.pdl.graphql.generated.hentidenter.IdentInformasjon -suspend fun PdlClient.hentAktorId(ident: String, callId: String?, navConsumerId: String?): String? = hentIdenter(ident, callId, navConsumerId) - ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } - ?.ident - -suspend fun PdlClient.hentIdenter(ident: String, callId: String?, navConsumerId: String?): List? { +suspend fun PdlClient.hentAktorId( + ident: String, + callId: String?, + navConsumerId: String?, +): String? = + hentIdenter(ident, callId, navConsumerId) + ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } + ?.ident + +suspend fun PdlClient.hentIdenter( + ident: String, + callId: String?, + navConsumerId: String?, +): List? { val query = HentIdenter(HentIdenter.Variables(ident)) logger.info("Henter 'hentIdenter' fra PDL") - val respons = execute( - query = query, - callId = callId, - navConsumerId = navConsumerId, - ) + val respons = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + ) respons.errors?.let { logger.error("Henter 'hentIdenter' fra PDL feilet med: ${respons.errors}") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt index 08e9f33e..3c38490e 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt @@ -3,16 +3,21 @@ package no.nav.paw.pdl import no.nav.paw.pdl.graphql.generated.HentOpphold import no.nav.paw.pdl.graphql.generated.hentopphold.Opphold -suspend fun PdlClient.hentOpphold(ident: String, callId: String?, navConsumerId: String?): List? { +suspend fun PdlClient.hentOpphold( + ident: String, + callId: String?, + navConsumerId: String?, +): List? { val query = HentOpphold(HentOpphold.Variables(ident)) logger.info("Henter 'hentPerson' fra PDL") - val respons = execute( - query = query, - callId = callId, - navConsumerId = navConsumerId, - ) + val respons = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + ) respons.errors?.let { logger.error("Henter 'hentPerson' fra PDL feilet med: ${respons.errors}") diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index 40211db9..35ae1ca2 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -10,18 +10,20 @@ suspend fun PdlClient.hentPerson( navConsumerId: String?, historisk: Boolean = false, ): Person? { - val query = HentPerson( - HentPerson.Variables(ident, historisk), - ) + val query = + HentPerson( + HentPerson.Variables(ident, historisk), + ) logger.trace("Henter 'hentPerson' fra PDL") - val respons = execute( - query = query, - callId = callId, - navConsumerId = navConsumerId, - traceparent = traceparent, - ) + val respons = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + ) respons.errors?.let { throw PdlException("'hentPerson' feilet", it) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index dcd9f47a..58974315 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -9,7 +9,7 @@ import io.ktor.client.request.bearerAuth import io.ktor.client.request.header import org.slf4j.LoggerFactory import java.io.IOException -import java.net.URL +import java.net.URI // Se https://pdldocs-navno.msappproxy.net/ for dokumentasjon av PDL API-et class PdlClient( @@ -21,10 +21,11 @@ class PdlClient( ) { internal val logger = LoggerFactory.getLogger(this::class.java) - private val graphQLClient = GraphQLKtorClient( - url = URL(url), - httpClient = httpClient, - ) + private val graphQLClient = + GraphQLKtorClient( + url = URI.create(url).toURL(), + httpClient = httpClient, + ) internal suspend fun execute( query: GraphQLClientRequest, diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt index bd8df7ee..f4388637 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt @@ -8,8 +8,7 @@ import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json -internal fun createHttpClient(): HttpClient = - HttpClient(OkHttp) { configureJsonHandler() } +internal fun createHttpClient(): HttpClient = HttpClient(OkHttp) { configureJsonHandler() } @OptIn(ExperimentalSerializationApi::class) internal fun HttpClientConfig<*>.configureJsonHandler() { diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt index 9c3c2219..81cc189d 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt @@ -10,12 +10,13 @@ import io.ktor.http.headersOf import no.nav.paw.pdl.PdlClient fun mockPdlClient(content: String): PdlClient { - val mockEngine = MockEngine { - respond( - content = content, - status = HttpStatusCode.OK, - headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()), - ) - } + val mockEngine = + MockEngine { + respond( + content = content, + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()), + ) + } return PdlClient("https://url", "tema", HttpClient(mockEngine)) { "fake token" } } diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 63bef6af..1967aadf 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -3,7 +3,7 @@ package no.nav.paw.pdl import kotlinx.coroutines.runBlocking import no.nav.paw.mockPdlClient import no.nav.paw.pdl.graphql.generated.enums.Oppholdstillatelse -import java.util.* +import java.util.UUID import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -54,7 +54,16 @@ class PdlClientTest { val forventet = Oppholdstillatelse.PERMANENT assertEquals(forventet, resultat!!.first().type) } + + @Test + fun `Forventer gyldig respons fra hentPerson`() { + val respons = readResource("hentPerson-response.json") + val pdlClient = mockPdlClient(respons) + + val resultat = runBlocking { pdlClient.hentPerson("2649500819544", callId, null, navConsumerId) } + val forventet = Oppholdstillatelse.PERMANENT + assertEquals(forventet, resultat!!.opphold.first().type) + } } -private fun readResource(filename: String) = - ClassLoader.getSystemResource(filename).readText() +private fun readResource(filename: String) = ClassLoader.getSystemResource(filename).readText() diff --git a/paw-pdl-client/src/test/resources/hentPerson-response.json b/paw-pdl-client/src/test/resources/hentPerson-response.json new file mode 100644 index 00000000..885efeba --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentPerson-response.json @@ -0,0 +1,39 @@ +{ + "data": { + "hentPerson": { + "foedsel": [ + { + "foedselsdato": "1986-11-26", + "foedselsaar": "1986" + } + ], + "opphold": [ + { + "oppholdFra": "2010-01-20", + "oppholdTil": "2022-01-20", + "type": "PERMANENT" + } + ], + "folkeregisterpersonstatus": [ + { + "forenkletStatus": "bosattEtterFolkeregisterloven" + } + ], + "bostedsadresse": [ + { + "angittFlyttedato": "2010-01-20", + "gyldigFraOgMed": "2010-01-20", + "gyldigTilOgMed": "2022-01-20", + "vegadresse": { + "kommunenummer": "0301" + }, + "matrikkeladresse": null, + "ukjentBosted": null, + "utenlandskAdresse": null + } + ], + "innflyttingTilNorge": [], + "utflyttingFraNorge": [] + } + } +} \ No newline at end of file From c85dcc5394de22a6c9063b927e17e7e46d524203 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Wed, 20 Mar 2024 10:58:17 +0100 Subject: [PATCH 45/64] Legger til eget kall for forenkletstatus --- .../no/nav/paw/pdl/HentForenkletStatus.kt | 34 +++++++++++++++++++ .../resources/hentForenkletStatus.graphql | 7 ++++ .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 11 ++++++ .../hentForenkletStatus-response.json | 11 ++++++ 4 files changed, 63 insertions(+) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt create mode 100644 paw-pdl-client/src/main/resources/hentForenkletStatus.graphql create mode 100644 paw-pdl-client/src/test/resources/hentForenkletStatus-response.json diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt new file mode 100644 index 00000000..932fcbeb --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt @@ -0,0 +1,34 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentForenkletStatus +import no.nav.paw.pdl.graphql.generated.hentforenkletstatus.Person + +suspend fun PdlClient.hentForenkletStatus( + ident: String, + callId: String?, + traceparent: String? = null, + navConsumerId: String?, +): Person? { + val query = + HentForenkletStatus( + HentForenkletStatus.Variables(ident), + ) + + val response = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + ) + + response.errors?.let { + throw PdlException("'hentForenkletStatus' feilet", it) + } + + logger.trace("Hentet 'hentForenkletStatus' fra PDL") + + return response + .data + ?.hentPerson +} diff --git a/paw-pdl-client/src/main/resources/hentForenkletStatus.graphql b/paw-pdl-client/src/main/resources/hentForenkletStatus.graphql new file mode 100644 index 00000000..5e1856b3 --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentForenkletStatus.graphql @@ -0,0 +1,7 @@ +query($ident: ID!) { + hentPerson(ident: $ident) { + folkeregisterpersonstatus { + forenkletStatus + } + } +} \ No newline at end of file diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 1967aadf..37be95db 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -7,6 +7,7 @@ import java.util.UUID import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertTrue class PdlClientTest { val callId = UUID.randomUUID().toString() @@ -64,6 +65,16 @@ class PdlClientTest { val forventet = Oppholdstillatelse.PERMANENT assertEquals(forventet, resultat!!.opphold.first().type) } + + @Test + fun `Forventer gyldig respons fra hentForenkletStatus`() { + val respons = readResource("hentForenkletStatus-response.json") + val pdlClient = mockPdlClient(respons) + + val resultat = runBlocking { pdlClient.hentForenkletStatus("2649500819544", callId, null, navConsumerId) } + val forventet = "bosattEtterFolkeregisterloven" + assertTrue { resultat!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } + } } private fun readResource(filename: String) = ClassLoader.getSystemResource(filename).readText() diff --git a/paw-pdl-client/src/test/resources/hentForenkletStatus-response.json b/paw-pdl-client/src/test/resources/hentForenkletStatus-response.json new file mode 100644 index 00000000..8086a5e4 --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentForenkletStatus-response.json @@ -0,0 +1,11 @@ +{ + "data": { + "hentPerson": { + "folkeregisterpersonstatus": [ + { + "forenkletStatus": "bosattEtterFolkeregisterloven" + } + ] + } + } +} \ No newline at end of file From d0a94a61340b2251cd17871c206d39a862dc41de Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Wed, 20 Mar 2024 11:50:48 +0100 Subject: [PATCH 46/64] Oppdaterer skjema og rydder --- .../src/main/kotlin/no/nav/paw/pdl/Utils.kt | 23 -- .../src/main/resources/pdl-schema.graphql | 292 ++++++++++-------- .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 4 +- 3 files changed, 160 insertions(+), 159 deletions(-) delete mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt deleted file mode 100644 index f4388637..00000000 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/Utils.kt +++ /dev/null @@ -1,23 +0,0 @@ -package no.nav.paw.pdl - -import io.ktor.client.HttpClient -import io.ktor.client.HttpClientConfig -import io.ktor.client.engine.okhttp.OkHttp -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json - -internal fun createHttpClient(): HttpClient = HttpClient(OkHttp) { configureJsonHandler() } - -@OptIn(ExperimentalSerializationApi::class) -internal fun HttpClientConfig<*>.configureJsonHandler() { - install(ContentNegotiation) { - json( - Json { - ignoreUnknownKeys = true - explicitNulls = false - }, - ) - } -} diff --git a/paw-pdl-client/src/main/resources/pdl-schema.graphql b/paw-pdl-client/src/main/resources/pdl-schema.graphql index 3001ef13..f44649a5 100644 --- a/paw-pdl-client/src/main/resources/pdl-schema.graphql +++ b/paw-pdl-client/src/main/resources/pdl-schema.graphql @@ -1,4 +1,4 @@ -# Hentet fra https://raw.githubusercontent.com/navikt/pdl/master/apps/api/src/main/resources/schemas/pdl.graphqls +# Hentet fra https://github.com/navikt/pdl/blob/master/apps/api/src/main/resources/schemas/pdl.graphqls # ISO-8601 representasjon for en kalenderdato. YYYY-MM-DD. Eksempel: 2018-01-01. scalar Date @@ -15,23 +15,13 @@ schema { type Query { hentPerson(ident: ID!): Person hentPersonBolk(identer: [ID!]!): [HentPersonBolkResult!]! - hentIdenter( - ident: ID! - grupper: [IdentGruppe!] - historikk: Boolean = false - ): Identliste - hentIdenterBolk( - identer: [ID!]! - grupper: [IdentGruppe!] - historikk: Boolean = false - ): [HentIdenterBolkResult!]! + hentIdenter(ident: ID!, grupper: [IdentGruppe!], historikk: Boolean = false): Identliste + hentIdenterBolk(identer: [ID!]!, grupper: [IdentGruppe!], historikk: Boolean = false): [HentIdenterBolkResult!]! hentGeografiskTilknytning(ident: ID!): GeografiskTilknytning - hentGeografiskTilknytningBolk( - identer: [ID!]! - ): [hentGeografiskTilknytningBolkResult!]! - sokPerson(criteria: [Criterion], paging: Paging): PersonSearchResult - sokAdresse(criteria: [Criterion], paging: Paging): AdresseSearchResult - forslagAdresse(parameters: CompletionParameters): AdresseCompletionResult + hentGeografiskTilknytningBolk(identer: [ID!]!): [hentGeografiskTilknytningBolkResult!]! + sokPerson(criteria:[Criterion], paging:Paging): PersonSearchResult + sokAdresse(criteria:[Criterion], paging:Paging): AdresseSearchResult + forslagAdresse(parameters:CompletionParameters): AdresseCompletionResult hentAdresse(matrikkelId: ID!): KartverketAdresse } @@ -130,8 +120,8 @@ type IdentInformasjon { } enum IdentGruppe { - AKTORID - FOLKEREGISTERIDENT + AKTORID, + FOLKEREGISTERIDENT, NPID } @@ -149,37 +139,30 @@ type Person { doedsfall: [Doedsfall!]! falskIdentitet: FalskIdentitet foedsel: [Foedsel!]! - folkeregisteridentifikator( - historikk: Boolean = false - ): [Folkeregisteridentifikator!]! - folkeregisterpersonstatus( - historikk: Boolean = false - ): [Folkeregisterpersonstatus!]! + foedselsdato: [Foedselsdato!]! + foedested: [Foedested!]! + folkeregisteridentifikator(historikk: Boolean = false): [Folkeregisteridentifikator!]! + folkeregisterpersonstatus(historikk: Boolean = false): [Folkeregisterpersonstatus!]! forelderBarnRelasjon: [ForelderBarnRelasjon!]! foreldreansvar(historikk: Boolean = false): [Foreldreansvar!]! fullmakt(historikk: Boolean = false): [Fullmakt!]! identitetsgrunnlag(historikk: Boolean = false): [Identitetsgrunnlag!]! kjoenn(historikk: Boolean = false): [Kjoenn!]! kontaktadresse(historikk: Boolean = false): [Kontaktadresse!]! - kontaktinformasjonForDoedsbo( - historikk: Boolean = false - ): [KontaktinformasjonForDoedsbo!]! + kontaktinformasjonForDoedsbo(historikk: Boolean = false): [KontaktinformasjonForDoedsbo!]! navn(historikk: Boolean = false): [Navn!]! - opphold(historikk: Boolean = false): [Opphold!]! - oppholdsadresse(historikk: Boolean = false): [Oppholdsadresse!]! - sikkerhetstiltak: [Sikkerhetstiltak!]! - sivilstand(historikk: Boolean = false): [Sivilstand!]! + opphold(historikk: Boolean = false):[Opphold!]! + oppholdsadresse(historikk: Boolean = false):[Oppholdsadresse!]! + sikkerhetstiltak:[Sikkerhetstiltak!]! + sivilstand(historikk: Boolean = false):[Sivilstand!]! statsborgerskap(historikk: Boolean = false): [Statsborgerskap!]! - telefonnummer: [Telefonnummer!]! - tilrettelagtKommunikasjon: [TilrettelagtKommunikasjon!]! - utenlandskIdentifikasjonsnummer( - historikk: Boolean = false - ): [UtenlandskIdentifikasjonsnummer!]! + telefonnummer(historikk: Boolean = false): [Telefonnummer!]! + tilrettelagtKommunikasjon:[TilrettelagtKommunikasjon!]! + utenlandskIdentifikasjonsnummer(historikk: Boolean = false): [UtenlandskIdentifikasjonsnummer!]! innflyttingTilNorge: [InnflyttingTilNorge!]! utflyttingFraNorge: [UtflyttingFraNorge!]! - vergemaalEllerFremtidsfullmakt( - historikk: Boolean = false - ): [VergemaalEllerFremtidsfullmakt!]! + vergemaalEllerFremtidsfullmakt(historikk: Boolean = false): [VergemaalEllerFremtidsfullmakt!]! + rettsligHandleevne(historikk: Boolean = false): [RettsligHandleevne!]! } type DeltBosted { @@ -242,7 +225,7 @@ type Kontaktadresse { } enum KontaktadresseType { - Innland + Innland, Utland } @@ -384,9 +367,9 @@ type Adressebeskyttelse { } enum AdressebeskyttelseGradering { - STRENGT_FORTROLIG_UTLAND - STRENGT_FORTROLIG - FORTROLIG + STRENGT_FORTROLIG_UTLAND, + STRENGT_FORTROLIG, + FORTROLIG, UGRADERT } @@ -400,6 +383,21 @@ type Foedsel { metadata: Metadata! } +type Foedested { + foedeland: String + foedested: String + foedekommune: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + +type Foedselsdato { + foedselsdato: Date + foedselsaar: Int + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + type Kjoenn { kjoenn: KjoennType folkeregistermetadata: Folkeregistermetadata @@ -428,16 +426,16 @@ type DoedfoedtBarn { } enum Familierelasjonsrolle { - BARN - MOR - FAR + BARN, + MOR, + FAR, MEDMOR } enum ForelderBarnRelasjonRolle { - BARN - MOR - FAR + BARN, + MOR, + FAR, MEDMOR } @@ -463,9 +461,9 @@ type hentGeografiskTilknytningBolkResult { } enum GtType { - KOMMUNE - BYDEL - UTLAND + KOMMUNE, + BYDEL, + UTLAND, UDEFINERT } @@ -473,7 +471,7 @@ type Navn { fornavn: String! mellomnavn: String etternavn: String! - forkortetNavn: String + forkortetNavn: String @deprecated originaltNavn: OriginaltNavn gyldigFraOgMed: Date @@ -494,9 +492,7 @@ type Personnavn { } enum KjoennType { - MANN - KVINNE - UKJENT + MANN, KVINNE, UKJENT } type Identitetsgrunnlag { @@ -507,7 +503,7 @@ type Identitetsgrunnlag { enum Identitetsgrunnlagsstatus { IKKE_KONTROLLERT - KONTROLLERT + KONTROLLERT, INGEN_STATUS } @@ -538,7 +534,7 @@ type Tolk { } enum FullmaktsRolle { - FULLMAKTSGIVER + FULLMAKTSGIVER, FULLMEKTIG } @@ -635,10 +631,23 @@ type UtflyttingFraNorge { } type VergeEllerFullmektig { - navn: Personnavn + navn: Personnavn @deprecated(reason:"Erstattes av navn iidentifiserendeInformasjon") + identifiserendeInformasjon: IdentifiserendeInformasjon motpartsPersonident: String omfang: String - omfangetErInnenPersonligOmraade: Boolean! + omfangetErInnenPersonligOmraade: Boolean + tjenesteomraade:[Tjenesteomraade!] +} +type IdentifiserendeInformasjon { + navn: Personnavn + kjoenn: String + foedselsdato:Date + statsborgerskap: [String!] + +} +type Tjenesteomraade { + tjenesteoppgave: String + tjenestevirksomhet: String } type VergemaalEllerFremtidsfullmakt { @@ -650,6 +659,13 @@ type VergemaalEllerFremtidsfullmakt { metadata: Metadata! } + +type RettsligHandleevne { + rettsligHandleevneomfang: String + folkeregistermetadata: Folkeregistermetadata + metadata: Metadata! +} + type Foreldreansvar { ansvar: String ansvarlig: String @@ -701,7 +717,7 @@ type Endring { # Fra Folkeregisteret får vi opphaven til dems opplysning, altså NAV, UDI, Politiet, Skatteetaten o.l.. Fra Folkeregisteret kan det også være tekniske navn som: DSF_MIGRERING, m.m.. kilde: String! - hendelseId: String! + hendelseId:String! } enum Endringstype { @@ -711,108 +727,114 @@ enum Endringstype { } input Criterion { - # Feltnavn ikludert sti til ønsket felt (Eksempel: person.navn.fornavn) - fieldName: String! + # Feltnavn inkludert sti til ønsket felt (Eksempel: person.navn.fornavn) + fieldName:String + + and:[Criterion] + or:[Criterion] + not:[Criterion] - searchRule: SearchRule! + searchRule:SearchRule # Søk i historiske data # true = søker kun i historiske data. # false = søker kun i gjeldende data. # null = søke i både historiske og gjeldende data. - searchHistorical: Boolean + searchHistorical:Boolean } + input SearchRule { # Sjekker om feltet finnes / at det ikke har en null verdi. - exists: String + exists:String # Filtrerer bort treff hvor felt inneholder input verdi - notEquals: String + notEquals:String # Begrenser treff til kun de hvor felt har input verdi - equals: String + equals:String # Gir treff når opgitt felt inneholder en eller flere ord fra input verdien. - contains: String + contains:String # Søk som gir treff også for små variasjoner i skrivemåte - fuzzy: String + fuzzy:String # Søk som gir tilfeldig poengsum til hvert treff (kun ment til generering av testdata) - random: String + random:String # Bruk "?" som wildcard for enkelt tegn, og "*" som wildcard for 0 eller flere tegn. - wildcard: String + wildcard:String # Gir treff når opgitt feltstarter med opgitt verdi. - startsWith: String + startsWith:String # Regex søk for spesielle situasjoner (Dette er en treg opprasjon og bør ikke brukes) - regex: String + regex:String # Brukes til søke etter datoer som kommer etter opgitt dato. - after: String + after:String # Brukes til søke etter datoer som kommer før opgitt dato. - before: String + before:String # Brukes til å søke i tall og finner verdier som er mindre en input verdi. - lessThan: String + lessThan:String # Brukes til å søke i tall og finner verdier som er størren en input verdi. - greaterThan: String + greaterThan:String # Søk fra og med (se fromExcluding for bare fra men ikke med) # kan benyttes på tall og dato - from: String + from:String # Søk til og med (se toExcluding for bare til men ikke med) # kan benyttes på tall og dato - to: String + to:String # Søk fra men ikke med oppgitt verdi # kan benyttes på tall og dato - fromExcluding: String + fromExcluding:String, # Søk til men ikke med oppgitt verdi # kan benyttes på tall og dato - toExcluding: String + toExcluding:String # [Flag] Kan brukes til å overstyre standard oppførsellen for søk i felter (standard er case insensitive) - caseSensitive: Boolean + caseSensitive:Boolean # [Flag] Brukes til å deaktivere fonetisk søk feltene som har dette som standard (Navn) - disablePhonetic: Boolean + disablePhonetic:Boolean # Boost brukes til å gi ett søkekriterie høyere eller lavere vektlegging en de andre søke kriteriene. - boost: Float + boost:Float } input Paging { # Hvilken side i resultatsettet man ønsker vist. - pageNumber: Int = 1 + pageNumber:Int = 1 # antall treff per side (maks 100) - resultsPerPage: Int = 10 + resultsPerPage:Int = 10 # Liste over felter man ønsker resultatene sortert etter # Standard er "score". Score er poengsummen Elasticsearch tildeler hvert resultat. - sortBy: [SearchSorting] + sortBy:[SearchSorting] } input SearchSorting { # Feltnavn ikludert sti til ønsket felt (eksepmel: person.navn.fornavn) - fieldName: String! - direction: Direction! + fieldName:String! + direction:Direction! } enum Direction { - ASC + ASC, DESC } type PersonSearchResult { # treff liste - hits: [PersonSearchHit!]! + hits : [PersonSearchHit!]! # Side nummer for siden som vises - pageNumber: Int + pageNumber:Int # Totalt antall sider - totalPages: Int + totalPages:Int # Totalt antall treff (øvre grense er satt til 10 000) - totalHits: Int + totalHits:Int + } type PersonSearchHit { # forespurte data - person: Person + person :Person # forespurte data identer(historikk: Boolean = false): [IdentInformasjon!]! # Poengsummen elasticsearch har gitt dette resultatet (brukt til feilsøking, og tuning av søk) - score: Float + score :Float # Infromasjon om hva som ga treff i søke resultatet. - highlights: [PersonSearchHighlight] + highlights:[PersonSearchHighlight] } type PersonSearchHighlight { # Navn/Sti til opplysningen som ga treff. Merk at dette ikke er feltet som ga treff men opplysningen. # F.eks. hvis du søker på person.navn.fornavn så vil opplysingen være person.navn. - opplysning: String + opplysning:String # Gitt att opplysningen som ga treff har en opplysningsId så vil den returneres her. # alle søk under person skal ha opplysningsId, men søk i identer vil kunne returnere treff uten opplysningsId. opplysningsId: String @@ -820,62 +842,64 @@ type PersonSearchHighlight { historisk: Boolean # liste med feltene og verdiene som ga treff. # Merk at for fritekst søk så vil disse kunne referere til hjelpe felter som ikke er synelig i resultatene. - matches: [SearchMatch] + matches:[SearchMatch] } type SearchMatch { # feltnavn med sti til feltet so ga treff. - field: String! + field:String! type: String # Verdien som ga treff fragments: [String] } type AdresseSearchResult { - hits: [AdresseSearchHit!]! - pageNumber: Int - totalPages: Int - totalHits: Int + hits : [AdresseSearchHit!]! + pageNumber:Int, + totalPages:Int + totalHits:Int + } type AdresseSearchHit { - vegadresse: VegadresseResult - matrikkeladresse: MatrikkeladresseResult - score: Float + vegadresse : VegadresseResult + matrikkeladresse : MatrikkeladresseResult + score :Float } type VegadresseResult { - matrikkelId: String - husnummer: Int - husbokstav: String - adressenavn: String - adressekode: String - tilleggsnavn: String - fylkesnavn: String - fylkesnummer: String - kommunenavn: String - kommunenummer: String - postnummer: String - poststed: String - bydelsnavn: String - bydelsnummer: String + matrikkelId:String + husnummer:Int + husbokstav:String + adressenavn:String + adressekode:String + tilleggsnavn:String + fylkesnavn:String + fylkesnummer:String + kommunenavn:String + kommunenummer:String + postnummer:String + poststed:String + bydelsnavn:String + bydelsnummer:String } type MatrikkeladresseResult { - matrikkelId: String - tilleggsnavn: String - kommunenummer: String - gaardsnummer: String - bruksnummer: String - postnummer: String - poststed: String + matrikkelId:String + tilleggsnavn:String + kommunenummer:String + gaardsnummer:String + bruksnummer:String + postnummer:String + poststed:String } type AdresseCompletionResult { suggestions: [String!]! - addressFound: CompletionAdresse + addressFound : CompletionAdresse } type CompletionAdresse { - vegadresse: VegadresseResult - matrikkeladresse: MatrikkeladresseResult + vegadresse : VegadresseResult + matrikkeladresse : MatrikkeladresseResult } input CompletionParameters { + completionField: String! maxSuggestions: Int fieldValues: [CompletionFieldValue]! @@ -883,4 +907,4 @@ input CompletionParameters { input CompletionFieldValue { fieldName: String! fieldValue: String -} +} \ No newline at end of file diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 37be95db..6a595629 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -10,8 +10,8 @@ import kotlin.test.assertFailsWith import kotlin.test.assertTrue class PdlClientTest { - val callId = UUID.randomUUID().toString() - val navConsumerId = "nav-consumer-id" + private val callId = UUID.randomUUID().toString() + private val navConsumerId = "nav-consumer-id" @Test fun `Forventer gyldig respons fra hentAktorId`() { From 32c5d43eca5cc149d6e377e04e944e7b7c0b367f Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Wed, 20 Mar 2024 13:06:50 +0100 Subject: [PATCH 47/64] Legger til hentForenkletStatusBolk --- .../no/nav/paw/pdl/HentForenkletStatusBolk.kt | 34 +++++++++++++++++++ .../resources/hentForenkletStatusBolk.graphql | 11 ++++++ .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 10 ++++++ .../hentForenkletStatusBolk-response.json | 17 ++++++++++ 4 files changed, 72 insertions(+) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt create mode 100644 paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql create mode 100644 paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt new file mode 100644 index 00000000..742d422e --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt @@ -0,0 +1,34 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentForenkletStatusBolk +import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult + +suspend fun PdlClient.hentForenkletStatusBolk( + ident: List, + callId: String?, + traceparent: String? = null, + navConsumerId: String?, +): List? { + val query = + HentForenkletStatusBolk( + HentForenkletStatusBolk.Variables(ident), + ) + + val response = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + ) + + response.errors?.let { + throw PdlException("'hentForenkletStatusBolk' feilet", it) + } + + logger.trace("Hentet 'hentForenkletStatusBolk' fra PDL") + + return response + .data + ?.hentPersonBolk +} diff --git a/paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql b/paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql new file mode 100644 index 00000000..29af5b2a --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql @@ -0,0 +1,11 @@ +query($identer: [ID!]!) { + hentPersonBolk(identer: $identer) { + ident + person { + folkeregisterpersonstatus { + forenkletStatus + } + } + code + } +} \ No newline at end of file diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 6a595629..301c42cd 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -75,6 +75,16 @@ class PdlClientTest { val forventet = "bosattEtterFolkeregisterloven" assertTrue { resultat!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } } + + @Test + fun `Forventer gyldig respons fra hentForenkletStatusBolk`() { + val respons = readResource("hentForenkletStatusBolk-response.json") + val pdlClient = mockPdlClient(respons) + + val resultat = runBlocking { pdlClient.hentForenkletStatusBolk(listOf("2649500819544"), callId, null, navConsumerId) } + val forventet = "bosattEtterFolkeregisterloven" + assertTrue { resultat!!.first().person!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } + } } private fun readResource(filename: String) = ClassLoader.getSystemResource(filename).readText() diff --git a/paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json b/paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json new file mode 100644 index 00000000..fd97a945 --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json @@ -0,0 +1,17 @@ +{ + "data": { + "hentPersonBolk": [ + { + "ident": "2649500819544", + "person": { + "folkeregisterpersonstatus": [ + { + "forenkletStatus": "bosattEtterFolkeregisterloven" + } + ] + }, + "code": "ok" + } + ] + } +} \ No newline at end of file From f6f8c0e456bb88e9b48511a891d549990808feff Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 22 Mar 2024 14:17:57 +0100 Subject: [PATCH 48/64] Endret garphQL lib til API siden ex fra denne pakken eksponeres --- paw-pdl-client/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-pdl-client/build.gradle.kts b/paw-pdl-client/build.gradle.kts index 60587d9e..ff6baaa4 100644 --- a/paw-pdl-client/build.gradle.kts +++ b/paw-pdl-client/build.gradle.kts @@ -70,7 +70,7 @@ dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-okhttp:$ktorVersion") implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") - implementation("com.expediagroup:graphql-kotlin-ktor-client:$graphQLKotlinVersion") + api("com.expediagroup:graphql-kotlin-ktor-client:$graphQLKotlinVersion") testImplementation("io.ktor:ktor-client-mock:$ktorVersion") testImplementation("io.mockk:mockk:$mockkVersion") From 165766877924ac27db1d26f4c50afe82c894d33e Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Mon, 13 May 2024 09:43:38 +0200 Subject: [PATCH 49/64] La til behandlilngsnummer i header --- .../src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt | 1 + .../main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt | 1 + .../kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt | 1 + .../src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 1 + .../src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 1 + .../src/main/kotlin/no/nav/paw/pdl/HentPerson.kt | 1 + .../src/main/kotlin/no/nav/paw/pdl/PdlClient.kt | 10 ++++++++-- 7 files changed, 14 insertions(+), 2 deletions(-) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt index 27f5840d..2987276b 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt @@ -22,6 +22,7 @@ suspend fun PdlClient.hentFoedsel( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, + behandlingsnummer = "B123", ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt index 932fcbeb..01de65c3 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt @@ -20,6 +20,7 @@ suspend fun PdlClient.hentForenkletStatus( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, + behandlingsnummer = "B123", ) response.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt index 742d422e..0ba5a8a4 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt @@ -20,6 +20,7 @@ suspend fun PdlClient.hentForenkletStatusBolk( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, + behandlingsnummer = "B123", ) response.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index 4aab1e90..82f23ec2 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -27,6 +27,7 @@ suspend fun PdlClient.hentIdenter( query = query, callId = callId, navConsumerId = navConsumerId, + behandlingsnummer = "B123", ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt index 3c38490e..512fdf0a 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt @@ -17,6 +17,7 @@ suspend fun PdlClient.hentOpphold( query = query, callId = callId, navConsumerId = navConsumerId, + behandlingsnummer = "B123", ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index 35ae1ca2..baf33eb7 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -23,6 +23,7 @@ suspend fun PdlClient.hentPerson( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, + behandlingsnummer = "B123", ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt index 58974315..eddfdf77 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt @@ -29,17 +29,23 @@ class PdlClient( internal suspend fun execute( query: GraphQLClientRequest, + behandlingsnummer: String, callId: String?, traceparent: String? = null, navConsumerId: String?, - ): GraphQLClientResponse = - graphQLClient.execute(query) { + ): GraphQLClientResponse { + if (behandlingsnummer.isBlank()) { + throw IllegalArgumentException("Behandlingsnummer kan ikke være tom") + } + return graphQLClient.execute(query) { bearerAuth(getAccessToken()) header("Tema", tema) header("Nav-Call-Id", callId) header("Nav-Consumer-Id", navConsumerId) + header("Behandlingsnummer", behandlingsnummer) traceparent?.let { header("traceparent", it) } } + } } class PdlException( From 423f05d541eee1d703b4be2ab65794af2cabc643 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Mon, 13 May 2024 09:52:32 +0200 Subject: [PATCH 50/64] Fikset test behandlingnummer hardkodet i selve klienten --- .../src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt | 3 ++- .../kotlin/no/nav/paw/pdl/HentForenkletStatus.kt | 3 ++- .../no/nav/paw/pdl/HentForenkletStatusBolk.kt | 3 ++- .../src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 6 ++++-- .../src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 3 ++- .../src/main/kotlin/no/nav/paw/pdl/HentPerson.kt | 3 ++- .../test/kotlin/no/nav/paw/pdl/PdlClientTest.kt | 14 +++++++------- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt index 2987276b..de22aadd 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt @@ -8,6 +8,7 @@ suspend fun PdlClient.hentFoedsel( callId: String?, traceparent: String? = null, navConsumerId: String?, + behandlingsnummer: String, ): Foedsel? { val query = HentFoedsel( @@ -22,7 +23,7 @@ suspend fun PdlClient.hentFoedsel( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt index 01de65c3..431194ec 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt @@ -8,6 +8,7 @@ suspend fun PdlClient.hentForenkletStatus( callId: String?, traceparent: String? = null, navConsumerId: String?, + behandlingsnummer: String, ): Person? { val query = HentForenkletStatus( @@ -20,7 +21,7 @@ suspend fun PdlClient.hentForenkletStatus( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) response.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt index 0ba5a8a4..6aa05fb0 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt @@ -8,6 +8,7 @@ suspend fun PdlClient.hentForenkletStatusBolk( callId: String?, traceparent: String? = null, navConsumerId: String?, + behandlingsnummer: String, ): List? { val query = HentForenkletStatusBolk( @@ -20,7 +21,7 @@ suspend fun PdlClient.hentForenkletStatusBolk( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) response.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index 82f23ec2..955a3489 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -8,8 +8,9 @@ suspend fun PdlClient.hentAktorId( ident: String, callId: String?, navConsumerId: String?, + behandlingsnummer: String, ): String? = - hentIdenter(ident, callId, navConsumerId) + hentIdenter(ident, callId, navConsumerId, behandlingsnummer) ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } ?.ident @@ -17,6 +18,7 @@ suspend fun PdlClient.hentIdenter( ident: String, callId: String?, navConsumerId: String?, + behandlingsnummer: String, ): List? { val query = HentIdenter(HentIdenter.Variables(ident)) @@ -27,7 +29,7 @@ suspend fun PdlClient.hentIdenter( query = query, callId = callId, navConsumerId = navConsumerId, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt index 512fdf0a..a553eabb 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt @@ -7,6 +7,7 @@ suspend fun PdlClient.hentOpphold( ident: String, callId: String?, navConsumerId: String?, + behandlingsnummer: String, ): List? { val query = HentOpphold(HentOpphold.Variables(ident)) @@ -17,7 +18,7 @@ suspend fun PdlClient.hentOpphold( query = query, callId = callId, navConsumerId = navConsumerId, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) respons.errors?.let { diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt index baf33eb7..16f8be00 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt @@ -9,6 +9,7 @@ suspend fun PdlClient.hentPerson( traceparent: String? = null, navConsumerId: String?, historisk: Boolean = false, + behandlingsnummer: String, ): Person? { val query = HentPerson( @@ -23,7 +24,7 @@ suspend fun PdlClient.hentPerson( callId = callId, navConsumerId = navConsumerId, traceparent = traceparent, - behandlingsnummer = "B123", + behandlingsnummer = behandlingsnummer, ) respons.errors?.let { diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 301c42cd..785775ae 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -18,7 +18,7 @@ class PdlClientTest { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId, navConsumerId) } + val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId, navConsumerId, "B123") } val forventet = "2649500819544" assertEquals(forventet, resultat) } @@ -30,7 +30,7 @@ class PdlClientTest { assertFailsWith( block = { runBlocking { - pdlClient.hentIdenter("2649500819544", callId, navConsumerId) + pdlClient.hentIdenter("2649500819544", callId, navConsumerId, "B123") } }, ) @@ -41,7 +41,7 @@ class PdlClientTest { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId, navConsumerId) } + val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId, navConsumerId, "B123") } val forventet = "09127821914" assertEquals(forventet, resultat!!.first().ident) } @@ -51,7 +51,7 @@ class PdlClientTest { val respons = readResource("hentOpphold-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentOpphold("2649500819544", callId, navConsumerId) } + val resultat = runBlocking { pdlClient.hentOpphold("2649500819544", callId, navConsumerId, "B123") } val forventet = Oppholdstillatelse.PERMANENT assertEquals(forventet, resultat!!.first().type) } @@ -61,7 +61,7 @@ class PdlClientTest { val respons = readResource("hentPerson-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentPerson("2649500819544", callId, null, navConsumerId) } + val resultat = runBlocking { pdlClient.hentPerson("2649500819544", callId, null, navConsumerId, behandlingsnummer = "B123") } val forventet = Oppholdstillatelse.PERMANENT assertEquals(forventet, resultat!!.opphold.first().type) } @@ -71,7 +71,7 @@ class PdlClientTest { val respons = readResource("hentForenkletStatus-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentForenkletStatus("2649500819544", callId, null, navConsumerId) } + val resultat = runBlocking { pdlClient.hentForenkletStatus("2649500819544", callId, null, navConsumerId, "B123") } val forventet = "bosattEtterFolkeregisterloven" assertTrue { resultat!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } } @@ -81,7 +81,7 @@ class PdlClientTest { val respons = readResource("hentForenkletStatusBolk-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentForenkletStatusBolk(listOf("2649500819544"), callId, null, navConsumerId) } + val resultat = runBlocking { pdlClient.hentForenkletStatusBolk(listOf("2649500819544"), callId, null, navConsumerId, "B123") } val forventet = "bosattEtterFolkeregisterloven" assertTrue { resultat!!.first().person!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } } From 2bba3cac9b8340ca9cd42a6bf02d35a65ae988fa Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 6 Jun 2024 07:53:19 +0200 Subject: [PATCH 51/64] =?UTF-8?q?Legger=20til=20historikk=20p=C3=A5=20inn-?= =?UTF-8?q?=20og=20utflytting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paw-pdl-client/src/main/resources/hentPerson.graphql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index df17549e..c97ed5b3 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -29,13 +29,13 @@ query($ident: ID!, $historisk: Boolean) { landkode } } - innflyttingTilNorge { + innflyttingTilNorge(historikk: $historisk) { folkeregistermetadata { gyldighetstidspunkt ajourholdstidspunkt } } - utflyttingFraNorge { + utflyttingFraNorge(historikk: $historisk) { utflyttingsdato folkeregistermetadata { gyldighetstidspunkt From 7150096f905d73850e4b3d23e6e5ce5f315e0a46 Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 6 Jun 2024 08:14:28 +0200 Subject: [PATCH 52/64] Legger ved historikk flagg i opphold og folkeregistrerpersonstatus --- paw-pdl-client/src/main/resources/hentPerson.graphql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index c97ed5b3..501b1457 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -4,7 +4,7 @@ query($ident: ID!, $historisk: Boolean) { foedselsdato foedselsaar } - opphold { + opphold(historikk: $historisk) { oppholdFra oppholdTil type @@ -29,13 +29,13 @@ query($ident: ID!, $historisk: Boolean) { landkode } } - innflyttingTilNorge(historikk: $historisk) { + innflyttingTilNorge { folkeregistermetadata { gyldighetstidspunkt ajourholdstidspunkt } } - utflyttingFraNorge(historikk: $historisk) { + utflyttingFraNorge { utflyttingsdato folkeregistermetadata { gyldighetstidspunkt From 45cc58b450429e07d70b41618836a063625e766a Mon Sep 17 00:00:00 2001 From: Jonas Enge Date: Thu, 6 Jun 2024 08:14:40 +0200 Subject: [PATCH 53/64] Legger ved historikk flagg i opphold og folkeregistrerpersonstatus --- paw-pdl-client/src/main/resources/hentPerson.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index 501b1457..cf59e723 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -9,7 +9,7 @@ query($ident: ID!, $historisk: Boolean) { oppholdTil type } - folkeregisterpersonstatus { + folkeregisterpersonstatus(historikk: $historisk) { forenkletStatus } bostedsadresse(historikk: $historisk) { From 1df5a953edf6320bb9186b3f806ac71b7675e2f3 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Mon, 10 Jun 2024 06:35:54 +0200 Subject: [PATCH 54/64] La til metadata for opphold til folkregstatus i hentPerson --- .../src/main/resources/hentPerson.graphql | 14 ++++++++++++ .../test/resources/hentPerson-response.json | 22 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index cf59e723..9c8da1d8 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -8,9 +8,23 @@ query($ident: ID!, $historisk: Boolean) { oppholdFra oppholdTil type + metadata { + endringer { + type + registrert + kilde + } + } } folkeregisterpersonstatus(historikk: $historisk) { forenkletStatus + metadata { + endringer { + type + registrert + kilde + } + } } bostedsadresse(historikk: $historisk) { angittFlyttedato diff --git a/paw-pdl-client/src/test/resources/hentPerson-response.json b/paw-pdl-client/src/test/resources/hentPerson-response.json index 885efeba..9d24cb83 100644 --- a/paw-pdl-client/src/test/resources/hentPerson-response.json +++ b/paw-pdl-client/src/test/resources/hentPerson-response.json @@ -11,12 +11,30 @@ { "oppholdFra": "2010-01-20", "oppholdTil": "2022-01-20", - "type": "PERMANENT" + "type": "PERMANENT", + "metadata": { + "endringer": [ + { + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + } + ] + } } ], "folkeregisterpersonstatus": [ { - "forenkletStatus": "bosattEtterFolkeregisterloven" + "forenkletStatus": "bosattEtterFolkeregisterloven", + "metadata": { + "endringer": [ + { + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + } + ] + } } ], "bostedsadresse": [ From ca5aa0efe9a383b017a3484b10dcea7d725331ec Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Mon, 24 Jun 2024 13:54:00 +0200 Subject: [PATCH 55/64] La til statsborgerskap i hentPerson --- paw-pdl-client/src/main/resources/hentPerson.graphql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/paw-pdl-client/src/main/resources/hentPerson.graphql index 9c8da1d8..96d883e5 100644 --- a/paw-pdl-client/src/main/resources/hentPerson.graphql +++ b/paw-pdl-client/src/main/resources/hentPerson.graphql @@ -4,6 +4,16 @@ query($ident: ID!, $historisk: Boolean) { foedselsdato foedselsaar } + statsborgerskap(historikk: $historisk) { + land + metadata { + endringer { + type + registrert + kilde + } + } + } opphold(historikk: $historisk) { oppholdFra oppholdTil From 91d3b8adbf408d813581a6c0c47a7a7a20fa4504 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Mon, 24 Jun 2024 14:04:14 +0200 Subject: [PATCH 56/64] Oppdaterte test json for hentPerson --- .../src/test/resources/hentPerson-response.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/paw-pdl-client/src/test/resources/hentPerson-response.json b/paw-pdl-client/src/test/resources/hentPerson-response.json index 9d24cb83..11ca6176 100644 --- a/paw-pdl-client/src/test/resources/hentPerson-response.json +++ b/paw-pdl-client/src/test/resources/hentPerson-response.json @@ -1,6 +1,18 @@ { "data": { "hentPerson": { + "statsborgerskap": [ + { + "land": "NOR", + "metadata": { + "endringer": [{ + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + }] + } + } + ], "foedsel": [ { "foedselsdato": "1986-11-26", From f9f4079198a3ba304f7b8a2379dfdee9a52e2280 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Thu, 4 Jul 2024 06:39:50 +0200 Subject: [PATCH 57/64] Oppdaterte avhengigheter --- paw-pdl-client/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties index ea20881b..307c3638 100644 --- a/paw-pdl-client/gradle.properties +++ b/paw-pdl-client/gradle.properties @@ -5,10 +5,10 @@ kotlin.code.style=official # Plugin versions kotlinVersion=1.9.23 kotlinterVersion=4.2.0 -graphQLKotlinVersion=7.0.2 +graphQLKotlinVersion=7.1.1 # Dependency versions coroutinesVersion=1.6.4 kotlinSerializationVersion=1.6.3 -ktorVersion=2.3.9 +ktorVersion=2.3.12 mockkVersion=1.13.10 From e804fd1e55bbcfcbb06a1feb676ed331fae8450c Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Thu, 4 Jul 2024 06:47:49 +0200 Subject: [PATCH 58/64] Oppdaterte avhengigheter --- paw-aareg-client/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties index 691adc62..a63b0e25 100644 --- a/paw-aareg-client/gradle.properties +++ b/paw-aareg-client/gradle.properties @@ -6,9 +6,9 @@ kotlin.code.style=official kotlinVersion=1.7.10 kotlinterVersion=3.12.0 -ktorVersion=2.2.4 +ktorVersion=2.3.12 mockkVersion=1.12.7 kotlinSerializationVersion=1.4.0 junitJupiterVersion=5.9.0 -slf4jVersion=2.0.4 +slf4jVersion=2.0.13 sonarqubeVersion=3.5.0.2730 \ No newline at end of file From 34cfdd20a6dc519965e35a346888277212dfcf3f Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Thu, 4 Jul 2024 07:02:47 +0200 Subject: [PATCH 59/64] Fikset kotlin versjonskonflikt --- paw-aareg-client/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties index a63b0e25..18cf6ce9 100644 --- a/paw-aareg-client/gradle.properties +++ b/paw-aareg-client/gradle.properties @@ -3,7 +3,7 @@ version=1.0-SNAPSHOT kotlin.code.style=official # Plugin versions -kotlinVersion=1.7.10 +kotlinVersion=1.9.21 kotlinterVersion=3.12.0 ktorVersion=2.3.12 From 08042c29353735902deef1c60e3d854fd65f813d Mon Sep 17 00:00:00 2001 From: robertkittilsen Date: Thu, 8 Aug 2024 11:12:33 +0200 Subject: [PATCH 60/64] Legger til HentPersonBolk --- .../kotlin/no/nav/paw/pdl/HentPersonBolk.kt | 39 ++++++++++ .../src/main/resources/hentPersonBolk.graphql | 74 ++++++++++++++++++ .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 10 +++ .../resources/hentPersonBolk-response.json | 75 +++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt create mode 100644 paw-pdl-client/src/main/resources/hentPersonBolk.graphql create mode 100644 paw-pdl-client/src/test/resources/hentPersonBolk-response.json diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt new file mode 100644 index 00000000..82b88cf0 --- /dev/null +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt @@ -0,0 +1,39 @@ +package no.nav.paw.pdl + +import no.nav.paw.pdl.graphql.generated.HentPersonBolk +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.HentPersonBolkResult + +suspend fun PdlClient.hentPersonBolk( + ident: List, + callId: String?, + traceparent: String? = null, + navConsumerId: String?, + historisk: Boolean = false, + behandlingsnummer: String, +): List? { + val query = + HentPersonBolk( + HentPersonBolk.Variables(ident, historisk), + ) + + logger.trace("Henter 'hentPerson' fra PDL") + + val respons = + execute( + query = query, + callId = callId, + navConsumerId = navConsumerId, + traceparent = traceparent, + behandlingsnummer = behandlingsnummer, + ) + + respons.errors?.let { + throw PdlException("'hentPerson' feilet", it) + } + + logger.trace("Hentet 'hentPerson' fra PDL") + + return respons + .data + ?.hentPersonBolk +} diff --git a/paw-pdl-client/src/main/resources/hentPersonBolk.graphql b/paw-pdl-client/src/main/resources/hentPersonBolk.graphql new file mode 100644 index 00000000..7f50882c --- /dev/null +++ b/paw-pdl-client/src/main/resources/hentPersonBolk.graphql @@ -0,0 +1,74 @@ +query($identer: [ID!]!, $historisk: Boolean) { + hentPersonBolk(identer: $identer) { + ident + person { + foedsel { + foedselsdato + foedselsaar + } + statsborgerskap(historikk: $historisk) { + land + metadata { + endringer { + type + registrert + kilde + } + } + } + opphold(historikk: $historisk) { + oppholdFra + oppholdTil + type + metadata { + endringer { + type + registrert + kilde + } + } + } + folkeregisterpersonstatus(historikk: $historisk) { + forenkletStatus + metadata { + endringer { + type + registrert + kilde + } + } + } + bostedsadresse(historikk: $historisk) { + angittFlyttedato + gyldigFraOgMed + gyldigTilOgMed + vegadresse { + kommunenummer + } + matrikkeladresse { + kommunenummer + } + ukjentBosted { + bostedskommune + } + utenlandskAdresse { + landkode + } + } + innflyttingTilNorge { + folkeregistermetadata { + gyldighetstidspunkt + ajourholdstidspunkt + } + } + utflyttingFraNorge { + utflyttingsdato + folkeregistermetadata { + gyldighetstidspunkt + ajourholdstidspunkt + } + } + } + code + } +} diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 785775ae..2b7fbc7c 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -66,6 +66,16 @@ class PdlClientTest { assertEquals(forventet, resultat!!.opphold.first().type) } + @Test + fun `Forventer gyldig respons fra hentPersonBolk`() { + val respons = readResource("hentPersonBolk-response.json") + val pdlClient = mockPdlClient(respons) + + val resultat = runBlocking { pdlClient.hentPersonBolk(listOf("2649500819544"), callId, null, navConsumerId, false, "B123") } + val forventet = Oppholdstillatelse.PERMANENT + assertEquals(forventet, resultat!!.first().person!!.opphold.first().type) + } + @Test fun `Forventer gyldig respons fra hentForenkletStatus`() { val respons = readResource("hentForenkletStatus-response.json") diff --git a/paw-pdl-client/src/test/resources/hentPersonBolk-response.json b/paw-pdl-client/src/test/resources/hentPersonBolk-response.json new file mode 100644 index 00000000..815e2f77 --- /dev/null +++ b/paw-pdl-client/src/test/resources/hentPersonBolk-response.json @@ -0,0 +1,75 @@ +{ + "data": { + "hentPersonBolk": [ + { + "ident": "2649500819544", + "person": { + "statsborgerskap": [ + { + "land": "NOR", + "metadata": { + "endringer": [{ + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + }] + } + } + ], + "foedsel": [ + { + "foedselsdato": "1986-11-26", + "foedselsaar": "1986" + } + ], + "opphold": [ + { + "oppholdFra": "2010-01-20", + "oppholdTil": "2022-01-20", + "type": "PERMANENT", + "metadata": { + "endringer": [ + { + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + } + ] + } + } + ], + "folkeregisterpersonstatus": [ + { + "forenkletStatus": "bosattEtterFolkeregisterloven", + "metadata": { + "endringer": [ + { + "type:": "OPPRETT", + "registrert": "2010-01-20", + "kilde": "FOLKEREGISTERET" + } + ] + } + } + ], + "bostedsadresse": [ + { + "angittFlyttedato": "2010-01-20", + "gyldigFraOgMed": "2010-01-20", + "gyldigTilOgMed": "2022-01-20", + "vegadresse": { + "kommunenummer": "0301" + }, + "matrikkeladresse": null, + "ukjentBosted": null, + "utenlandskAdresse": null + } + ], + "innflyttingTilNorge": [], + "utflyttingFraNorge": [] + }, + "code": "ok" + } + ] + } +} \ No newline at end of file From 536a07e59bed8550a60e844d8f4b7d7aeb288310 Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 18 Oct 2024 06:32:49 +0200 Subject: [PATCH 61/64] =?UTF-8?q?La=20til=20historikk=20param=20p=C3=A5=20?= =?UTF-8?q?hentIdenter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 10 ++++++++-- .../src/main/resources/hentIdenter.graphql | 4 ++-- .../test/kotlin/no/nav/paw/pdl/PdlClientTest.kt | 17 +++++++++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt index 955a3489..18bbb7eb 100644 --- a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt +++ b/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt @@ -10,17 +10,23 @@ suspend fun PdlClient.hentAktorId( navConsumerId: String?, behandlingsnummer: String, ): String? = - hentIdenter(ident, callId, navConsumerId, behandlingsnummer) + hentIdenter( + ident = ident, + callId = callId, + navConsumerId = navConsumerId, + behandlingsnummer = behandlingsnummer, + ) ?.firstOrNull { it.gruppe == IdentGruppe.AKTORID } ?.ident suspend fun PdlClient.hentIdenter( ident: String, + historikk: Boolean = false, callId: String?, navConsumerId: String?, behandlingsnummer: String, ): List? { - val query = HentIdenter(HentIdenter.Variables(ident)) + val query = HentIdenter(HentIdenter.Variables(ident = ident, historisk = historikk)) logger.info("Henter 'hentIdenter' fra PDL") diff --git a/paw-pdl-client/src/main/resources/hentIdenter.graphql b/paw-pdl-client/src/main/resources/hentIdenter.graphql index 1c9a9b3d..25ab35a8 100644 --- a/paw-pdl-client/src/main/resources/hentIdenter.graphql +++ b/paw-pdl-client/src/main/resources/hentIdenter.graphql @@ -1,5 +1,5 @@ -query($ident: ID!) { - hentIdenter(ident: $ident) { +query($ident: ID!, $historisk: Boolean) { + hentIdenter(ident: $ident, historikk: $historisk) { identer { ident gruppe diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 2b7fbc7c..67c3a3e7 100644 --- a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -30,7 +30,12 @@ class PdlClientTest { assertFailsWith( block = { runBlocking { - pdlClient.hentIdenter("2649500819544", callId, navConsumerId, "B123") + pdlClient.hentIdenter( + ident = "2649500819544", + callId = callId, + navConsumerId = navConsumerId, + behandlingsnummer = "B123", + ) } }, ) @@ -41,7 +46,15 @@ class PdlClientTest { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentIdenter("2649500819544", callId, navConsumerId, "B123") } + val resultat = + runBlocking { + pdlClient.hentIdenter( + ident = "2649500819544", + callId = callId, + navConsumerId = navConsumerId, + behandlingsnummer = "B123", + ) + } val forventet = "09127821914" assertEquals(forventet, resultat!!.first().ident) } From c5009babbf43025c10a63f8cec3c55daa33d132d Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 25 Oct 2024 07:31:48 +0200 Subject: [PATCH 62/64] Klargjort for flytting til monorepo --- .github/workflows/paw-aareg-client.yml | 31 --- .github/workflows/paw-pdl-client.yml | 31 --- .gitignore | 31 --- .../aareg-client}/README.md | 0 .../aareg-client}/build.gradle.kts | 0 .../kotlin/no/nav/paw/aareg/AaregClient.kt | 0 .../kotlin/no/nav/paw/aareg/Arbeidsforhold.kt | 0 .../no/nav/paw/aareg/LocalDateSerializer.kt | 0 .../nav/paw/aareg/LocalDateTimeSerializer.kt | 0 .../src/main/kotlin/no/nav/paw/aareg/Utils.kt | 0 .../no/nav/paw/aareg/AaregClientTest.kt | 0 .../test/kotlin/no/nav/paw/aareg/MockUtils.kt | 0 .../test/resources/aareg-arbeidsforhold.json | 0 .../src/test/resources/error.json | 0 {paw-pdl-client => lib/pdl-client}/README.md | 0 .../pdl-client}/build.gradle.kts | 0 .../main/kotlin/no/nav/paw/pdl/HentFoedsel.kt | 0 .../no/nav/paw/pdl/HentForenkletStatus.kt | 0 .../no/nav/paw/pdl/HentForenkletStatusBolk.kt | 0 .../main/kotlin/no/nav/paw/pdl/HentIdenter.kt | 0 .../main/kotlin/no/nav/paw/pdl/HentOpphold.kt | 0 .../main/kotlin/no/nav/paw/pdl/HentPerson.kt | 0 .../kotlin/no/nav/paw/pdl/HentPersonBolk.kt | 0 .../main/kotlin/no/nav/paw/pdl/PdlClient.kt | 0 .../src/main/resources/.graphqlconfig | 0 .../src/main/resources/hentFoedsel.graphql | 0 .../resources/hentForenkletStatus.graphql | 0 .../resources/hentForenkletStatusBolk.graphql | 0 .../src/main/resources/hentIdenter.graphql | 0 .../src/main/resources/hentOpphold.graphql | 0 .../src/main/resources/hentPerson.graphql | 0 .../src/main/resources/hentPersonBolk.graphql | 0 .../src/main/resources/pdl-schema.graphql | 0 .../test/kotlin/no/nav/paw/MockPdlClient.kt | 0 .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 0 .../src/test/resources/error-response.json | 0 .../hentForenkletStatus-response.json | 0 .../hentForenkletStatusBolk-response.json | 0 .../resources/hentFullPerson-response.json | 0 .../test/resources/hentIdenter-response.json | 0 .../test/resources/hentOpphold-response.json | 0 .../test/resources/hentPerson-response.json | 0 .../resources/hentPersonBolk-response.json | 0 paw-aareg-client/.gitignore | 31 --- paw-aareg-client/gradle.properties | 14 - .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - paw-aareg-client/gradlew | 234 ---------------- paw-aareg-client/gradlew.bat | 89 ------- paw-aareg-client/settings.gradle.kts | 15 -- paw-pdl-client/.editorconfig | 14 - paw-pdl-client/.gitignore | 31 --- paw-pdl-client/gradle.properties | 14 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - paw-pdl-client/gradlew | 249 ------------------ paw-pdl-client/gradlew.bat | 92 ------- paw-pdl-client/settings.gradle.kts | 15 -- 58 files changed, 903 deletions(-) delete mode 100644 .github/workflows/paw-aareg-client.yml delete mode 100644 .github/workflows/paw-pdl-client.yml delete mode 100644 .gitignore rename {paw-aareg-client => lib/aareg-client}/README.md (100%) rename {paw-aareg-client => lib/aareg-client}/build.gradle.kts (100%) rename {paw-aareg-client => lib/aareg-client}/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/main/kotlin/no/nav/paw/aareg/Utils.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt (100%) rename {paw-aareg-client => lib/aareg-client}/src/test/resources/aareg-arbeidsforhold.json (100%) rename {paw-aareg-client => lib/aareg-client}/src/test/resources/error.json (100%) rename {paw-pdl-client => lib/pdl-client}/README.md (100%) rename {paw-pdl-client => lib/pdl-client}/build.gradle.kts (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/.graphqlconfig (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentFoedsel.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentForenkletStatus.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentForenkletStatusBolk.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentIdenter.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentOpphold.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentPerson.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/hentPersonBolk.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/main/resources/pdl-schema.graphql (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/kotlin/no/nav/paw/MockPdlClient.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/error-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentForenkletStatus-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentForenkletStatusBolk-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentFullPerson-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentIdenter-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentOpphold-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentPerson-response.json (100%) rename {paw-pdl-client => lib/pdl-client}/src/test/resources/hentPersonBolk-response.json (100%) delete mode 100644 paw-aareg-client/.gitignore delete mode 100644 paw-aareg-client/gradle.properties delete mode 100644 paw-aareg-client/gradle/wrapper/gradle-wrapper.jar delete mode 100644 paw-aareg-client/gradle/wrapper/gradle-wrapper.properties delete mode 100755 paw-aareg-client/gradlew delete mode 100644 paw-aareg-client/gradlew.bat delete mode 100644 paw-aareg-client/settings.gradle.kts delete mode 100644 paw-pdl-client/.editorconfig delete mode 100644 paw-pdl-client/.gitignore delete mode 100644 paw-pdl-client/gradle.properties delete mode 100644 paw-pdl-client/gradle/wrapper/gradle-wrapper.jar delete mode 100644 paw-pdl-client/gradle/wrapper/gradle-wrapper.properties delete mode 100755 paw-pdl-client/gradlew delete mode 100644 paw-pdl-client/gradlew.bat delete mode 100644 paw-pdl-client/settings.gradle.kts diff --git a/.github/workflows/paw-aareg-client.yml b/.github/workflows/paw-aareg-client.yml deleted file mode 100644 index 9a08ceea..00000000 --- a/.github/workflows/paw-aareg-client.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: paw-aareg-client - -on: - push: - branches: - - main - paths: - - 'paw-aareg-client/**' - -jobs: - build: - name: Build and push - runs-on: ubuntu-latest - permissions: - packages: write - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: temurin - cache: gradle - - - name: Verify Gradle wrapper checksum - uses: gradle/wrapper-validation-action@v1 - - - name: Build with Gradle and Publish artifact - working-directory: ./paw-aareg-client - run: ./gradlew -Pversion=$(date +'%y.%m.%d').${{ github.run_number }}-${{ github.run_attempt }} build test publish - env: - ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/paw-pdl-client.yml b/.github/workflows/paw-pdl-client.yml deleted file mode 100644 index 2e291cf9..00000000 --- a/.github/workflows/paw-pdl-client.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: paw-pdl-client - -on: - push: - branches: - - main - paths: - - 'paw-pdl-client/**' - -jobs: - build: - name: Build and push - runs-on: ubuntu-latest - permissions: - packages: write - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: temurin - cache: gradle - - - name: Verify Gradle wrapper checksum - uses: gradle/wrapper-validation-action@v1 - - - name: Build with Gradle and Publish artifact - working-directory: ./paw-pdl-client - run: ./gradlew -Pversion=$(date +'%y.%m.%d').${{ github.run_number }}-${{ github.run_attempt }} build test publish - env: - ORG_GRADLE_PROJECT_githubPassword: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index dd6e2101..00000000 --- a/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log - -# IDEA & Gradle -**/.gradle -/.idea -/out -/lib -**/build -*.iml -*.ipr -*.iws - -# Package Files # -*.jar -!gradle-wrapper.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -#mac files -**/.DS_Store diff --git a/paw-aareg-client/README.md b/lib/aareg-client/README.md similarity index 100% rename from paw-aareg-client/README.md rename to lib/aareg-client/README.md diff --git a/paw-aareg-client/build.gradle.kts b/lib/aareg-client/build.gradle.kts similarity index 100% rename from paw-aareg-client/build.gradle.kts rename to lib/aareg-client/build.gradle.kts diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt b/lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt similarity index 100% rename from paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt rename to lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/AaregClient.kt diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt b/lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt similarity index 100% rename from paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt rename to lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/Arbeidsforhold.kt diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt b/lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt similarity index 100% rename from paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt rename to lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateSerializer.kt diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt b/lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt similarity index 100% rename from paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt rename to lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/LocalDateTimeSerializer.kt diff --git a/paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt b/lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt similarity index 100% rename from paw-aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt rename to lib/aareg-client/src/main/kotlin/no/nav/paw/aareg/Utils.kt diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt similarity index 100% rename from paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt rename to lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt diff --git a/paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt b/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt similarity index 100% rename from paw-aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt rename to lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/MockUtils.kt diff --git a/paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json b/lib/aareg-client/src/test/resources/aareg-arbeidsforhold.json similarity index 100% rename from paw-aareg-client/src/test/resources/aareg-arbeidsforhold.json rename to lib/aareg-client/src/test/resources/aareg-arbeidsforhold.json diff --git a/paw-aareg-client/src/test/resources/error.json b/lib/aareg-client/src/test/resources/error.json similarity index 100% rename from paw-aareg-client/src/test/resources/error.json rename to lib/aareg-client/src/test/resources/error.json diff --git a/paw-pdl-client/README.md b/lib/pdl-client/README.md similarity index 100% rename from paw-pdl-client/README.md rename to lib/pdl-client/README.md diff --git a/paw-pdl-client/build.gradle.kts b/lib/pdl-client/build.gradle.kts similarity index 100% rename from paw-pdl-client/build.gradle.kts rename to lib/pdl-client/build.gradle.kts diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentFoedsel.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatus.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentForenkletStatusBolk.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentIdenter.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentOpphold.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPerson.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/HentPersonBolk.kt diff --git a/paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt b/lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt similarity index 100% rename from paw-pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt rename to lib/pdl-client/src/main/kotlin/no/nav/paw/pdl/PdlClient.kt diff --git a/paw-pdl-client/src/main/resources/.graphqlconfig b/lib/pdl-client/src/main/resources/.graphqlconfig similarity index 100% rename from paw-pdl-client/src/main/resources/.graphqlconfig rename to lib/pdl-client/src/main/resources/.graphqlconfig diff --git a/paw-pdl-client/src/main/resources/hentFoedsel.graphql b/lib/pdl-client/src/main/resources/hentFoedsel.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentFoedsel.graphql rename to lib/pdl-client/src/main/resources/hentFoedsel.graphql diff --git a/paw-pdl-client/src/main/resources/hentForenkletStatus.graphql b/lib/pdl-client/src/main/resources/hentForenkletStatus.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentForenkletStatus.graphql rename to lib/pdl-client/src/main/resources/hentForenkletStatus.graphql diff --git a/paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql b/lib/pdl-client/src/main/resources/hentForenkletStatusBolk.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentForenkletStatusBolk.graphql rename to lib/pdl-client/src/main/resources/hentForenkletStatusBolk.graphql diff --git a/paw-pdl-client/src/main/resources/hentIdenter.graphql b/lib/pdl-client/src/main/resources/hentIdenter.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentIdenter.graphql rename to lib/pdl-client/src/main/resources/hentIdenter.graphql diff --git a/paw-pdl-client/src/main/resources/hentOpphold.graphql b/lib/pdl-client/src/main/resources/hentOpphold.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentOpphold.graphql rename to lib/pdl-client/src/main/resources/hentOpphold.graphql diff --git a/paw-pdl-client/src/main/resources/hentPerson.graphql b/lib/pdl-client/src/main/resources/hentPerson.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentPerson.graphql rename to lib/pdl-client/src/main/resources/hentPerson.graphql diff --git a/paw-pdl-client/src/main/resources/hentPersonBolk.graphql b/lib/pdl-client/src/main/resources/hentPersonBolk.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/hentPersonBolk.graphql rename to lib/pdl-client/src/main/resources/hentPersonBolk.graphql diff --git a/paw-pdl-client/src/main/resources/pdl-schema.graphql b/lib/pdl-client/src/main/resources/pdl-schema.graphql similarity index 100% rename from paw-pdl-client/src/main/resources/pdl-schema.graphql rename to lib/pdl-client/src/main/resources/pdl-schema.graphql diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/lib/pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt similarity index 100% rename from paw-pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt rename to lib/pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt diff --git a/paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt similarity index 100% rename from paw-pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt rename to lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt diff --git a/paw-pdl-client/src/test/resources/error-response.json b/lib/pdl-client/src/test/resources/error-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/error-response.json rename to lib/pdl-client/src/test/resources/error-response.json diff --git a/paw-pdl-client/src/test/resources/hentForenkletStatus-response.json b/lib/pdl-client/src/test/resources/hentForenkletStatus-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentForenkletStatus-response.json rename to lib/pdl-client/src/test/resources/hentForenkletStatus-response.json diff --git a/paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json b/lib/pdl-client/src/test/resources/hentForenkletStatusBolk-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentForenkletStatusBolk-response.json rename to lib/pdl-client/src/test/resources/hentForenkletStatusBolk-response.json diff --git a/paw-pdl-client/src/test/resources/hentFullPerson-response.json b/lib/pdl-client/src/test/resources/hentFullPerson-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentFullPerson-response.json rename to lib/pdl-client/src/test/resources/hentFullPerson-response.json diff --git a/paw-pdl-client/src/test/resources/hentIdenter-response.json b/lib/pdl-client/src/test/resources/hentIdenter-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentIdenter-response.json rename to lib/pdl-client/src/test/resources/hentIdenter-response.json diff --git a/paw-pdl-client/src/test/resources/hentOpphold-response.json b/lib/pdl-client/src/test/resources/hentOpphold-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentOpphold-response.json rename to lib/pdl-client/src/test/resources/hentOpphold-response.json diff --git a/paw-pdl-client/src/test/resources/hentPerson-response.json b/lib/pdl-client/src/test/resources/hentPerson-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentPerson-response.json rename to lib/pdl-client/src/test/resources/hentPerson-response.json diff --git a/paw-pdl-client/src/test/resources/hentPersonBolk-response.json b/lib/pdl-client/src/test/resources/hentPersonBolk-response.json similarity index 100% rename from paw-pdl-client/src/test/resources/hentPersonBolk-response.json rename to lib/pdl-client/src/test/resources/hentPersonBolk-response.json diff --git a/paw-aareg-client/.gitignore b/paw-aareg-client/.gitignore deleted file mode 100644 index 241e4dfe..00000000 --- a/paw-aareg-client/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log - -# IDEA & Gradle -/.gradle -/.idea -/out -/lib -/build -*.iml -*.ipr -*.iws - -# Package Files # -*.jar -!gradle-wrapper.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -#mac files -**/.DS_Store diff --git a/paw-aareg-client/gradle.properties b/paw-aareg-client/gradle.properties deleted file mode 100644 index 18cf6ce9..00000000 --- a/paw-aareg-client/gradle.properties +++ /dev/null @@ -1,14 +0,0 @@ -version=1.0-SNAPSHOT - -kotlin.code.style=official - -# Plugin versions -kotlinVersion=1.9.21 -kotlinterVersion=3.12.0 - -ktorVersion=2.3.12 -mockkVersion=1.12.7 -kotlinSerializationVersion=1.4.0 -junitJupiterVersion=5.9.0 -slf4jVersion=2.0.13 -sonarqubeVersion=3.5.0.2730 \ No newline at end of file diff --git a/paw-aareg-client/gradle/wrapper/gradle-wrapper.jar b/paw-aareg-client/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties b/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 41dfb879..00000000 --- a/paw-aareg-client/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/paw-aareg-client/gradlew b/paw-aareg-client/gradlew deleted file mode 100755 index 1b6c7873..00000000 --- a/paw-aareg-client/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/paw-aareg-client/gradlew.bat b/paw-aareg-client/gradlew.bat deleted file mode 100644 index 107acd32..00000000 --- a/paw-aareg-client/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/paw-aareg-client/settings.gradle.kts b/paw-aareg-client/settings.gradle.kts deleted file mode 100644 index 70824e10..00000000 --- a/paw-aareg-client/settings.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -rootProject.name = "aareg-client" - -pluginManagement { - val kotlinVersion: String by settings - val kotlinterVersion: String by settings - val sonarqubeVersion: String by settings - - plugins { - kotlin("jvm") version kotlinVersion - kotlin("plugin.serialization") version kotlinVersion - id("org.jmailen.kotlinter") version kotlinterVersion - id("maven-publish") - id("org.sonarqube") version sonarqubeVersion - } -} diff --git a/paw-pdl-client/.editorconfig b/paw-pdl-client/.editorconfig deleted file mode 100644 index feef31a4..00000000 --- a/paw-pdl-client/.editorconfig +++ /dev/null @@ -1,14 +0,0 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# editorconfig.org - -root = true - -# Kotlin -[**.{kt,kts}] -charset = utf-8 -indent_style = space -indent_size = 4 -trim_trailing_whitespace=true -insert_final_newline = true -max_line_length = 160 diff --git a/paw-pdl-client/.gitignore b/paw-pdl-client/.gitignore deleted file mode 100644 index 241e4dfe..00000000 --- a/paw-pdl-client/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log - -# IDEA & Gradle -/.gradle -/.idea -/out -/lib -/build -*.iml -*.ipr -*.iws - -# Package Files # -*.jar -!gradle-wrapper.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -#mac files -**/.DS_Store diff --git a/paw-pdl-client/gradle.properties b/paw-pdl-client/gradle.properties deleted file mode 100644 index 307c3638..00000000 --- a/paw-pdl-client/gradle.properties +++ /dev/null @@ -1,14 +0,0 @@ -version=1.0-SNAPSHOT - -kotlin.code.style=official - -# Plugin versions -kotlinVersion=1.9.23 -kotlinterVersion=4.2.0 -graphQLKotlinVersion=7.1.1 - -# Dependency versions -coroutinesVersion=1.6.4 -kotlinSerializationVersion=1.6.3 -ktorVersion=2.3.12 -mockkVersion=1.13.10 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar b/paw-pdl-client/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties b/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a80b22ce..00000000 --- a/paw-pdl-client/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/paw-pdl-client/gradlew b/paw-pdl-client/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/paw-pdl-client/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/paw-pdl-client/gradlew.bat b/paw-pdl-client/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/paw-pdl-client/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/paw-pdl-client/settings.gradle.kts b/paw-pdl-client/settings.gradle.kts deleted file mode 100644 index ea54d589..00000000 --- a/paw-pdl-client/settings.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -rootProject.name = "pdl-client" - -pluginManagement { - val kotlinVersion: String by settings - val kotlinterVersion: String by settings - val graphQLKotlinVersion: String by settings - - plugins { - kotlin("jvm") version kotlinVersion - kotlin("plugin.serialization") version kotlinVersion - id("org.jmailen.kotlinter") version kotlinterVersion - id("com.expediagroup.graphql") version graphQLKotlinVersion - id("maven-publish") - } -} From 3b594a2b34ccd63c7b4d9a898515b802e8e457ca Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 25 Oct 2024 11:32:05 +0200 Subject: [PATCH 63/64] Oppdatert etter flytting av kotlin-clients --- .../api-start-stopp-perioder/build.gradle.kts | 6 +- apps/bekreftelse-api/build.gradle.kts | 2 +- apps/bekreftelse-tjeneste/build.gradle.kts | 2 +- apps/bekreftelse-utgang/build.gradle.kts | 2 +- apps/hendelselogg-backup/build.gradle.kts | 5 +- gradle/libs.versions.toml | 13 +- lib/aareg-client/build.gradle.kts | 77 ++-------- .../no/nav/paw/aareg/AaregClientTest.kt | 41 +----- lib/pdl-client/build.gradle.kts | 81 +++-------- .../no/nav/paw/{ => pdl}/MockPdlClient.kt | 3 +- .../kotlin/no/nav/paw/pdl/PdlClientTest.kt | 131 +++++++++++------- settings.gradle.kts | 4 + 12 files changed, 140 insertions(+), 227 deletions(-) rename lib/pdl-client/src/test/kotlin/no/nav/paw/{ => pdl}/MockPdlClient.kt (92%) diff --git a/apps/api-start-stopp-perioder/build.gradle.kts b/apps/api-start-stopp-perioder/build.gradle.kts index 53c7fd3d..12db9db9 100644 --- a/apps/api-start-stopp-perioder/build.gradle.kts +++ b/apps/api-start-stopp-perioder/build.gradle.kts @@ -93,8 +93,8 @@ jib { environment = mapOf( "IMAGE_WITH_VERSION" to "${image ?: project.name}:${project.version}", "OTEL_INSTRUMENTATION_METHODS_INCLUDE" to ("io.ktor.server.routing.Routing[interceptor,executeResult];" + - "io.ktor.server.netty.NettyApplicationCallHandler[handleRequest,exceptionCaught];") + - "io.ktor.serialization.jackson.JacksonConverter[deserialize,serializeNullable]" + "io.ktor.server.netty.NettyApplicationCallHandler[handleRequest,exceptionCaught];") + + "io.ktor.serialization.jackson.JacksonConverter[deserialize,serializeNullable]" ) jvmFlags = listOf("-XX:ActiveProcessorCount=4", "-XX:+UseZGC", "-XX:+ZGenerational") } @@ -107,7 +107,7 @@ mapOf( "${layout.projectDirectory}/src/main/resources/openapi/opplysninger.yaml" to "${generatedCodePackageName}.opplysningermottatt", "${layout.projectDirectory}/src/main/resources/openapi/startstopp.yaml" to "${generatedCodePackageName}.startstopp" ).map { (openApiDocFile, pkgName) -> - val taskName = "generate${pkgName.capitalized()}" + val taskName = "generate${pkgName.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }}" tasks.register(taskName, GenerateTask::class) { generatorName.set("kotlin-server") library = "ktor" diff --git a/apps/bekreftelse-api/build.gradle.kts b/apps/bekreftelse-api/build.gradle.kts index d9bfb148..5167a589 100644 --- a/apps/bekreftelse-api/build.gradle.kts +++ b/apps/bekreftelse-api/build.gradle.kts @@ -35,7 +35,7 @@ dependencies { // Serialization implementation(libs.ktor.serialization.jackson) - implementation(libs.ktor.serialization.json) + implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.jackson.datatypeJsr310) // Authentication diff --git a/apps/bekreftelse-tjeneste/build.gradle.kts b/apps/bekreftelse-tjeneste/build.gradle.kts index 46209f64..2df5503c 100644 --- a/apps/bekreftelse-tjeneste/build.gradle.kts +++ b/apps/bekreftelse-tjeneste/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { // Serialization implementation(libs.ktor.serialization.jackson) - implementation(libs.ktor.serialization.json) + implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.jackson.datatypeJsr310) // Tooling diff --git a/apps/bekreftelse-utgang/build.gradle.kts b/apps/bekreftelse-utgang/build.gradle.kts index 184dbf02..17e810f8 100644 --- a/apps/bekreftelse-utgang/build.gradle.kts +++ b/apps/bekreftelse-utgang/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { // Serialization implementation(libs.ktor.serialization.jackson) - implementation(libs.ktor.serialization.json) + implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.jackson.datatypeJsr310) // Tooling diff --git a/apps/hendelselogg-backup/build.gradle.kts b/apps/hendelselogg-backup/build.gradle.kts index 5c07e06a..9dafa297 100644 --- a/apps/hendelselogg-backup/build.gradle.kts +++ b/apps/hendelselogg-backup/build.gradle.kts @@ -1,4 +1,3 @@ -import org.gradle.configurationcache.extensions.capitalized import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask @@ -107,7 +106,7 @@ val generatedCodeOutputDir = "${layout.buildDirectory.get()}/generated/" mapOf( "${layout.projectDirectory}/src/main/resources/openapi/Brukerstoette.yaml" to "${generatedCodePackageName}.brukerstoette" ).map { (openApiDocFile, pkgName) -> - val taskName = "generate${pkgName.capitalized()}" + val taskName = "generate${pkgName.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }}" tasks.register(taskName, GenerateTask::class) { generatorName.set("kotlin-server") library = "ktor" @@ -142,7 +141,7 @@ mapOf( mapOf( "${layout.projectDirectory}/src/main/resources/openapi/oppslags-api.yaml" to "${generatedCodePackageName}.oppslagsapi" ).map { (openApiDocFile, pkgName) -> - val taskName = "generate${pkgName.capitalized()}" + val taskName = "generate${pkgName.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }}" tasks.register(taskName, GenerateTask::class) { generatorName.set("kotlin") library = "jvm-ktor" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index de4edb13..06f0d234 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,14 @@ [versions] pawPdlClientVersion = "24.10.18.41-1" pawAaregClientVersion = "24.07.04.18-1" +noNavSecurityVersion = "5.0.5" +noNavCommonVersion = "3.2024.05.23_05.46-2b29fa343e8e" arbeidssokerregisteretVersion = "1.9348086045.48-1" bekreftelseSchemaVersion = "24.10.21.12-1" arrowVersion = "1.2.4" arrowJacksonIntegrationVersion = "0.14.1" -noNavCommonVersion = "3.2024.05.23_05.46-2b29fa343e8e" -noNavSecurityVersion = "5.0.5" comSksamuelHopliteVersion = "2.8.2" +graphqlClientVersion = "7.1.1" orgApacheKafkaVersion = "3.7.0" ioConfluentKafkaVersion = "7.7.1" orgApacheAvroVersion = "1.12.0" @@ -27,6 +28,8 @@ coroutinesVersion = "1.9.0" postgresDriverVersion = "42.7.4" flywayVersion = "10.20.0" hikariVersion = "6.0.0" +kotlinxCoroutinesVersion = "1.8.1" +kotlinxSerializationJsonVersion = "1.7.3" ktorVersion = "2.3.12" [libraries] @@ -36,6 +39,8 @@ arrow-core-serialization = { group = "io.arrow-kt", name = "arrow-core-serializa arrow-integration-jackson = { group = "io.arrow-kt", name = "arrow-integrations-jackson-module", version.ref = "arrowJacksonIntegrationVersion" } logbackClassic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackVersion" } logstashLogbackEncoder = { group = "net.logstash.logback", name = "logstash-logback-encoder", version.ref = "logstashVersion" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesVersion" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJsonVersion" } ktor-client-contentNegotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktorVersion" } ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktorVersion" } ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktorVersion" } @@ -57,7 +62,7 @@ ktor-server-testJvm = { group = "io.ktor", name = "ktor-server-tests-jvm", versi ktor-serialization-core = { group = "io.ktor", name = "ktor-serialization", version.ref = "ktorVersion" } ktor-serialization-jvm = { group = "io.ktor", name = "ktor-serialization-jvm", version.ref = "ktorVersion" } ktor-serialization-jackson = { group = "io.ktor", name = "ktor-serialization-jackson", version.ref = "ktorVersion" } -ktor-serialization-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktorVersion" } +ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktorVersion" } opentelemetry-api = { group = "io.opentelemetry", name = "opentelemetry-api", version.ref = "otelTargetSdkVersion" } opentelemetry-ktor = { group = "io.opentelemetry.instrumentation", name = "opentelemetry-ktor-2.0", version.ref = "otelInstrumentationKtorVersion" } opentelemetry-annotations = { group = "io.opentelemetry.instrumentation", name = "opentelemetry-instrumentation-annotations", version.ref = "otelInstrumentationVersion" } @@ -80,6 +85,8 @@ nav-common-log = { group = "no.nav.common", name = "log", version.ref = "noNavCo nav-common-auditLog = { group = "no.nav.common", name = "audit-log", version.ref = "noNavCommonVersion" } nav-security-tokenValidationKtorV2 = { group = "no.nav.security", name = "token-validation-ktor-v2", version.ref = "noNavSecurityVersion" } nav-security-tokenClientCore = { group = "no.nav.security", name = "token-client-core", version.ref = "noNavSecurityVersion" } +graphql-client = { group = "com.expediagroup", name = "graphql-kotlin-client", version.ref = "graphqlClientVersion" } +graphql-ktor-client = { group = "com.expediagroup", name = "graphql-kotlin-ktor-client", version.ref = "graphqlClientVersion" } hoplite-core = { group = "com.sksamuel.hoplite", name = "hoplite-core", version.ref = "comSksamuelHopliteVersion" } hoplite-toml = { group = "com.sksamuel.hoplite", name = "hoplite-toml", version.ref = "comSksamuelHopliteVersion" } hoplite-yaml = { group = "com.sksamuel.hoplite", name = "hoplite-yaml", version.ref = "comSksamuelHopliteVersion" } diff --git a/lib/aareg-client/build.gradle.kts b/lib/aareg-client/build.gradle.kts index c2f92199..69f076e3 100644 --- a/lib/aareg-client/build.gradle.kts +++ b/lib/aareg-client/build.gradle.kts @@ -1,77 +1,28 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { kotlin("jvm") kotlin("plugin.serialization") - id("org.jmailen.kotlinter") - id("maven-publish") - java -} - -group = "no.nav.paw" - -tasks { - withType { - kotlinOptions.jvmTarget = "11" - } - test { - useJUnitPlatform() - } } +val jvmMajorVersion: String by project -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 +dependencies { + api(libs.kotlinx.serialization.json) - withSourcesJar() -} + implementation(libs.ktor.client.contentNegotiation) + implementation(libs.ktor.client.okhttp) + implementation(libs.ktor.serialization.kotlinx.json) + implementation(libs.ktor.client.logging) -repositories { - mavenCentral() - mavenNav("*") + testImplementation(libs.bundles.testLibsWithUnitTesting) + testImplementation(libs.ktor.client.mock) } -publishing { - publications { - create("mavenJava") { - from(components["java"]) - } - } - repositories { - mavenNav("paw-kotlin-clients") +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(jvmMajorVersion)) } } -dependencies { - val ktorVersion: String by project - val mockkVersion: String by project - val kotlinSerializationVersion: String by project - val junitJupiterVersion: String by project - val slf4jVersion: String by project - - api("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") - - implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") - implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("io.ktor:ktor-client-okhttp:$ktorVersion") - implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") - implementation("io.ktor:ktor-client-logging:$ktorVersion") - - testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion") - testImplementation("io.ktor:ktor-client-mock:$ktorVersion") - testImplementation("io.mockk:mockk:$mockkVersion") - testImplementation("org.slf4j:slf4j-simple:$slf4jVersion") -} - -fun RepositoryHandler.mavenNav(repo: String): MavenArtifactRepository { - val githubPassword: String by project - - return maven { - setUrl("https://maven.pkg.github.com/navikt/$repo") - credentials { - username = "x-access-token" - password = githubPassword - } - } +tasks.withType().configureEach { + useJUnitPlatform() } diff --git a/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt b/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt index fe56a82a..cab5633d 100644 --- a/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt +++ b/lib/aareg-client/src/test/kotlin/no/nav/paw/aareg/AaregClientTest.kt @@ -1,48 +1,21 @@ package no.nav.paw.aareg +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.collections.shouldContain import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -class AaregClientTest { +class AaregClientTest : FreeSpec({ /* API Description: https://navikt.github.io/aareg/tjenester/integrasjon/api/ */ - @Test - fun `Returnerer gyldig objekt når alt er oK`() { + "Returnerer gyldig objekt når alt er ok" { val response = runBlocking { mockAaregClient(MockResponse.arbeidsforhold) .hentArbeidsforhold("ident", "call-id") } - assertTrue(response.any { it.arbeidsgiver.organisasjonsnummer == "896929119" }) + + response.map { it.arbeidsgiver.organisasjonsnummer } shouldContain "896929119" } -// -// @Test -// fun test_OK_svar_Med_Uventet_JSON() { -// val response = runBlocking { -// mockAaregClient(MockResponse.error) -// .hentArbeidsforhold("hei", "54-56 That's My Number") -// } -// val empty = emptyList() -// assertEquals(empty, response) -// } -// -// @Test -// fun test_Server_Error() { -// val response = runBlocking { -// mockAaregClient("blablabla", HttpStatusCode.InternalServerError) -// .hentArbeidsforhold("hei", "123456") -// } -// val empty = emptyList() -// assertEquals(empty, response) -// } -// -// @Test -// fun realDeal() { -// val client = AaregClient(url = "blah") { "tja" } -// val response = runBlocking { client.hentArbeidsforhold("hei", "Number 2") } -// assertEquals(emptyList(), response) -// } -} +}) diff --git a/lib/pdl-client/build.gradle.kts b/lib/pdl-client/build.gradle.kts index ff6baaa4..8d8945b3 100644 --- a/lib/pdl-client/build.gradle.kts +++ b/lib/pdl-client/build.gradle.kts @@ -1,28 +1,23 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -group = "no.nav.paw" - plugins { kotlin("jvm") kotlin("plugin.serialization") id("com.expediagroup.graphql") - id("org.jmailen.kotlinter") - id("maven-publish") } -tasks { - withType { - kotlinOptions.jvmTarget = "21" - } - test { - useJUnitPlatform() - } - lintKotlinMain { - exclude("no/nav/paw/pdl/graphql/generated/**/*.kt") - } - formatKotlinMain { - exclude("no/nav/paw/pdl/graphql/generated/**/*.kt") - } +val jvmMajorVersion: String by project + +dependencies { + api(libs.kotlinx.serialization.json) + + implementation(libs.ktor.client.contentNegotiation) + implementation(libs.ktor.client.okhttp) + implementation(libs.ktor.serialization.kotlinx.json) + implementation(libs.ktor.client.logging) + api(libs.graphql.ktor.client) + + testImplementation(libs.bundles.testLibsWithUnitTesting) + testImplementation(libs.ktor.client.mock) + testImplementation(libs.kotlinx.coroutines.core) } java { @@ -32,21 +27,6 @@ java { } } -repositories { - mavenCentral() - mavenNav("*") -} - -publishing { - publications { - create("mavenJava") { - from(components["java"]) - } - } - repositories { - mavenNav("paw-kotlin-clients") - } -} graphql { client { @@ -57,35 +37,6 @@ graphql { } } -dependencies { - val coroutinesVersion: String by project - val kotlinSerializationVersion: String by project - val ktorVersion: String by project - val mockkVersion: String by project - val graphQLKotlinVersion: String by project - - api("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") - - implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") - implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("io.ktor:ktor-client-okhttp:$ktorVersion") - implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") - api("com.expediagroup:graphql-kotlin-ktor-client:$graphQLKotlinVersion") - - testImplementation("io.ktor:ktor-client-mock:$ktorVersion") - testImplementation("io.mockk:mockk:$mockkVersion") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") - testImplementation(kotlin("test")) -} - -fun RepositoryHandler.mavenNav(repo: String): MavenArtifactRepository { - val githubPassword: String by project - - return maven { - setUrl("https://maven.pkg.github.com/navikt/$repo") - credentials { - username = "x-access-token" - password = githubPassword - } - } +tasks.withType().configureEach { + useJUnitPlatform() } diff --git a/lib/pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt b/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/MockPdlClient.kt similarity index 92% rename from lib/pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt rename to lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/MockPdlClient.kt index 81cc189d..3a02813e 100644 --- a/lib/pdl-client/src/test/kotlin/no/nav/paw/MockPdlClient.kt +++ b/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/MockPdlClient.kt @@ -1,4 +1,4 @@ -package no.nav.paw +package no.nav.paw.pdl import io.ktor.client.HttpClient import io.ktor.client.engine.mock.MockEngine @@ -7,7 +7,6 @@ import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.HttpStatusCode import io.ktor.http.headersOf -import no.nav.paw.pdl.PdlClient fun mockPdlClient(content: String): PdlClient { val mockEngine = diff --git a/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt b/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt index 67c3a3e7..7725b0b7 100644 --- a/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt +++ b/lib/pdl-client/src/test/kotlin/no/nav/paw/pdl/PdlClientTest.kt @@ -1,33 +1,35 @@ package no.nav.paw.pdl +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.shouldBe import kotlinx.coroutines.runBlocking -import no.nav.paw.mockPdlClient import no.nav.paw.pdl.graphql.generated.enums.Oppholdstillatelse -import java.util.UUID -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertTrue - -class PdlClientTest { - private val callId = UUID.randomUUID().toString() - private val navConsumerId = "nav-consumer-id" - - @Test - fun `Forventer gyldig respons fra hentAktorId`() { +import java.util.* + +class PdlClientTest : FreeSpec({ + + val callId = UUID.randomUUID().toString() + val navConsumerId = "nav-consumer-id" + + "Forventer gyldig respons fra hentAktorId" { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentAktorId("2649500819544", callId, navConsumerId, "B123") } + val resultat = runBlocking { + pdlClient.hentAktorId("2649500819544", callId, navConsumerId, "B123") + } val forventet = "2649500819544" - assertEquals(forventet, resultat) + + resultat shouldBe forventet } - @Test - fun `Forventer feilmelding fra hentIdenter`() { + "Forventer feilmelding fra hentIdenter" { val respons = readResource("error-response.json") val pdlClient = mockPdlClient(respons) - assertFailsWith( + + shouldThrow( block = { runBlocking { pdlClient.hentIdenter( @@ -41,73 +43,100 @@ class PdlClientTest { ) } - @Test - fun `Forventer gyldig respons fra hentIdenter`() { + "Forventer gyldig respons fra hentIdenter" { val respons = readResource("hentIdenter-response.json") val pdlClient = mockPdlClient(respons) - val resultat = - runBlocking { - pdlClient.hentIdenter( - ident = "2649500819544", - callId = callId, - navConsumerId = navConsumerId, - behandlingsnummer = "B123", - ) - } + val resultat = runBlocking { + pdlClient.hentIdenter( + ident = "2649500819544", + callId = callId, + navConsumerId = navConsumerId, + behandlingsnummer = "B123", + ) + } val forventet = "09127821914" - assertEquals(forventet, resultat!!.first().ident) + + resultat!!.first().ident shouldBe forventet } - @Test - fun `Forventer gyldig respons fra hentOpphold`() { + "Forventer gyldig respons fra hentOpphold" { val respons = readResource("hentOpphold-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentOpphold("2649500819544", callId, navConsumerId, "B123") } + val resultat = runBlocking { + pdlClient.hentOpphold("2649500819544", callId, navConsumerId, "B123") + } val forventet = Oppholdstillatelse.PERMANENT - assertEquals(forventet, resultat!!.first().type) + + resultat!!.first().type shouldBe forventet } - @Test - fun `Forventer gyldig respons fra hentPerson`() { + "Forventer gyldig respons fra hentPerson" { val respons = readResource("hentPerson-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentPerson("2649500819544", callId, null, navConsumerId, behandlingsnummer = "B123") } + val resultat = runBlocking { + pdlClient.hentPerson( + "2649500819544", + callId, + null, + navConsumerId, + behandlingsnummer = "B123" + ) + } val forventet = Oppholdstillatelse.PERMANENT - assertEquals(forventet, resultat!!.opphold.first().type) + + resultat!!.opphold.first().type shouldBe forventet } - @Test - fun `Forventer gyldig respons fra hentPersonBolk`() { + "Forventer gyldig respons fra hentPersonBolk" { val respons = readResource("hentPersonBolk-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentPersonBolk(listOf("2649500819544"), callId, null, navConsumerId, false, "B123") } + val resultat = runBlocking { + pdlClient.hentPersonBolk( + listOf("2649500819544"), + callId, + null, + navConsumerId, + false, + "B123" + ) + } val forventet = Oppholdstillatelse.PERMANENT - assertEquals(forventet, resultat!!.first().person!!.opphold.first().type) + + resultat!!.first().person!!.opphold.first().type shouldBe forventet } - @Test - fun `Forventer gyldig respons fra hentForenkletStatus`() { + "Forventer gyldig respons fra hentForenkletStatus" { val respons = readResource("hentForenkletStatus-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentForenkletStatus("2649500819544", callId, null, navConsumerId, "B123") } + val resultat = + runBlocking { pdlClient.hentForenkletStatus("2649500819544", callId, null, navConsumerId, "B123") } val forventet = "bosattEtterFolkeregisterloven" - assertTrue { resultat!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } + + resultat!!.folkeregisterpersonstatus.map { it.forenkletStatus } shouldContain forventet } - @Test - fun `Forventer gyldig respons fra hentForenkletStatusBolk`() { + "Forventer gyldig respons fra hentForenkletStatusBolk" { val respons = readResource("hentForenkletStatusBolk-response.json") val pdlClient = mockPdlClient(respons) - val resultat = runBlocking { pdlClient.hentForenkletStatusBolk(listOf("2649500819544"), callId, null, navConsumerId, "B123") } + val resultat = runBlocking { + pdlClient.hentForenkletStatusBolk( + listOf("2649500819544"), + callId, + null, + navConsumerId, + "B123" + ) + } val forventet = "bosattEtterFolkeregisterloven" - assertTrue { resultat!!.first().person!!.folkeregisterpersonstatus.any { it.forenkletStatus == forventet } } + + resultat!!.first().person!!.folkeregisterpersonstatus.map { it.forenkletStatus } shouldContain forventet } -} +}) private fun readResource(filename: String) = ClassLoader.getSystemResource(filename).readText() diff --git a/settings.gradle.kts b/settings.gradle.kts index 35e9e66f..d01decaf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,9 +1,11 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" kotlin("jvm") version "2.0.21" apply false + kotlin("plugin.serialization") version "2.0.21" apply false id("com.google.cloud.tools.jib") version "3.4.4" apply false id("org.openapi.generator") version "7.9.0" apply false id("com.github.davidmc24.gradle.plugin.avro") version "1.9.1" apply false + id("com.expediagroup.graphql") version "7.1.1" apply false } rootProject.name = "paw-arbeidssoekerregisteret-monorepo-intern" @@ -14,6 +16,8 @@ include( "lib:kafka", "lib:kafka-streams", "lib:kafka-key-generator-client", + "lib:pdl-client", + "lib:aareg-client", "test:test-data-lib", "test:kafka-streams-test-functions", "domain:bekreftelse-interne-hendelser", From dbb40989fef646a456f5855b83a8faf851849814 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 25 Oct 2024 12:59:03 +0200 Subject: [PATCH 64/64] =?UTF-8?q?Oppdaterte=20apps=20til=20=C3=A5=20bruke?= =?UTF-8?q?=20nye=20client-libs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api-start-stopp-perioder/build.gradle.kts | 4 +--- .../nav/paw/bekreftelse/api/model/AccessToken.kt | 16 +++++----------- .../api/plugins/custom/KafkaConsumerPlugin.kt | 1 + apps/kafka-key-generator/build.gradle.kts | 2 +- apps/utgang-pdl/build.gradle.kts | 6 +++--- domain/arbeidssoeker-regler/build.gradle.kts | 4 +--- gradle/libs.versions.toml | 4 ---- 7 files changed, 12 insertions(+), 25 deletions(-) diff --git a/apps/api-start-stopp-perioder/build.gradle.kts b/apps/api-start-stopp-perioder/build.gradle.kts index 12db9db9..1cdcd08a 100644 --- a/apps/api-start-stopp-perioder/build.gradle.kts +++ b/apps/api-start-stopp-perioder/build.gradle.kts @@ -1,6 +1,4 @@ -import org.gradle.configurationcache.extensions.capitalized import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask plugins { @@ -23,6 +21,7 @@ dependencies { implementation(project(":lib:kafka")) implementation(project(":lib:hoplite-config")) implementation(project(":lib:kafka-key-generator-client")) + implementation(project(":lib:pdl-client")) implementation(project(":domain:arbeidssoeker-regler")) implementation(libs.bundles.ktorServerWithNettyAndMicrometer) implementation(libs.micrometer.registryPrometheus) @@ -36,7 +35,6 @@ dependencies { implementation(libs.nav.common.auditLog) implementation(libs.nav.common.log) implementation(libs.poao.tilgangClient) - implementation(libs.paw.pdl.client) implementation(libs.logbackClassic) implementation(libs.logstashLogbackEncoder) implementation(libs.kafka.clients) diff --git a/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/model/AccessToken.kt b/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/model/AccessToken.kt index 1c0cbc23..21e4d0cf 100644 --- a/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/model/AccessToken.kt +++ b/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/model/AccessToken.kt @@ -1,9 +1,6 @@ package no.nav.paw.bekreftelse.api.model import no.nav.paw.bekreftelse.api.exception.UgyldigBearerTokenException -import no.nav.paw.bekreftelse.api.model.ResolveToken.AzureToken -import no.nav.paw.bekreftelse.api.model.ResolveToken.IdPortenToken -import no.nav.paw.bekreftelse.api.model.ResolveToken.TokenXToken import no.nav.security.token.support.core.context.TokenValidationContext import no.nav.security.token.support.core.jwt.JwtToken import java.util.* @@ -39,14 +36,11 @@ data object OID : Claim("oid", UUID::fromString) data object Name : Claim("name", { it }) data object NavIdent : Claim("NAVident", { it }) -private sealed class ResolveToken( - val issuer: Issuer, - val claims: List> -) { - data object IdPortenToken : ResolveToken(IdPorten, listOf(PID)) - data object TokenXToken : ResolveToken(TokenX, listOf(PID)) - data object AzureToken : ResolveToken(Azure, listOf(OID, Name, NavIdent)) -} +sealed class ResolveToken(val issuer: Issuer, val claims: List>) + +data object IdPortenToken : ResolveToken(IdPorten, listOf(PID)) +data object TokenXToken : ResolveToken(TokenX, listOf(PID)) +data object AzureToken : ResolveToken(Azure, listOf(OID, Name, NavIdent)) private val validTokens: List = listOf(IdPortenToken, TokenXToken, AzureToken) diff --git a/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/plugins/custom/KafkaConsumerPlugin.kt b/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/plugins/custom/KafkaConsumerPlugin.kt index 6e7c9583..499f33e7 100644 --- a/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/plugins/custom/KafkaConsumerPlugin.kt +++ b/apps/bekreftelse-api/src/main/kotlin/no/nav/paw/bekreftelse/api/plugins/custom/KafkaConsumerPlugin.kt @@ -64,6 +64,7 @@ val KafkaConsumerPlugin: ApplicationPlugin = application.log.info("Stopper Kafka Consumer") pollingFlag.set(false) consumeJob?.cancel() + consumer.unsubscribe() consumer.close(shutDownTimeout) } diff --git a/apps/kafka-key-generator/build.gradle.kts b/apps/kafka-key-generator/build.gradle.kts index c72fccaa..1b8cd089 100644 --- a/apps/kafka-key-generator/build.gradle.kts +++ b/apps/kafka-key-generator/build.gradle.kts @@ -13,7 +13,7 @@ val jvmMajorVersion: String by project dependencies { // PAW implementation(project(":lib:hoplite-config")) - implementation(libs.paw.pdl.client) + implementation(project(":lib:pdl-client")) // NAV implementation(libs.nav.common.log) diff --git a/apps/utgang-pdl/build.gradle.kts b/apps/utgang-pdl/build.gradle.kts index 43849d55..df0a953a 100644 --- a/apps/utgang-pdl/build.gradle.kts +++ b/apps/utgang-pdl/build.gradle.kts @@ -20,15 +20,15 @@ dependencies { implementation(project(":domain:arbeidssoekerregisteret-kotlin")) implementation(project(":domain:arbeidssoeker-regler")) - implementation(project(":lib:kafka-key-generator-client")) + implementation(project(":lib:hoplite-config")) implementation(project(":lib:kafka")) implementation(project(":lib:kafka-streams")) - implementation(project(":lib:hoplite-config")) + implementation(project(":lib:kafka-key-generator-client")) + implementation(project(":lib:pdl-client")) api(libs.arrow.core.core) implementation(libs.kafka.streams.core) - implementation(libs.paw.pdl.client) implementation(libs.bundles.ktorServerWithNettyAndMicrometer) implementation(libs.micrometer.registryPrometheus) diff --git a/domain/arbeidssoeker-regler/build.gradle.kts b/domain/arbeidssoeker-regler/build.gradle.kts index ff3acf54..d2ae55f6 100644 --- a/domain/arbeidssoeker-regler/build.gradle.kts +++ b/domain/arbeidssoeker-regler/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { kotlin("jvm") id("org.openapi.generator") @@ -11,8 +9,8 @@ val baseImage: String by project val jvmMajorVersion: String by project dependencies { + implementation(project(":lib:pdl-client")) implementation(project(":domain:interne-hendelser")) - implementation(libs.paw.pdl.client) api(libs.micrometer.registryPrometheus) api(libs.arrow.core.core) testImplementation(libs.ktor.server.testJvm) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 06f0d234..6ab64a9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,4 @@ [versions] -pawPdlClientVersion = "24.10.18.41-1" -pawAaregClientVersion = "24.07.04.18-1" noNavSecurityVersion = "5.0.5" noNavCommonVersion = "3.2024.05.23_05.46-2b29fa343e8e" arbeidssokerregisteretVersion = "1.9348086045.48-1" @@ -68,8 +66,6 @@ opentelemetry-ktor = { group = "io.opentelemetry.instrumentation", name = "opent opentelemetry-annotations = { group = "io.opentelemetry.instrumentation", name = "opentelemetry-instrumentation-annotations", version.ref = "otelInstrumentationVersion" } micrometerCore = { group = "io.micrometer", name = "micrometer-core", version.ref = "micrometerVersion" } micrometer-registryPrometheus = { group = "io.micrometer", name = "micrometer-registry-prometheus", version.ref = "micrometerVersion" } -paw-pdl-client = { group = "no.nav.paw", name = "pdl-client", version.ref = "pawPdlClientVersion" } -paw-aareg-client = { group = "no.nav.paw", name = "aareg-client", version.ref = "pawAaregClientVersion" } paw-schema-main = { group = "no.nav.paw.arbeidssokerregisteret.api", name = "main-avro-schema", version.ref = "arbeidssokerregisteretVersion" } kafka-clients = { group = "org.apache.kafka", name = "kafka-clients", version.ref = "orgApacheKafkaVersion" } kafka-streams-core = { group = "org.apache.kafka", name = "kafka-streams", version.ref = "orgApacheKafkaVersion" }