From 2d35f978d4f825041d113a36baff1a06fc05af9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristen=20H=C3=A6rum?= Date: Tue, 29 Oct 2024 12:58:58 +0100 Subject: [PATCH] Bugfix/levende arbeidsforhold ansettelse (#3655) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor AnsettelseService to remove manual threading. #deploy-levende-arbeidsforhold-ansettelse Removed the explicit use of Threads and handling interruptions. Streamlined the service execution and added error logging for better maintainability and debugging. * Increase pending acquire timeout in AaregConsumer #deploy-levende-arbeidsforhold-ansettelse Extended the pending acquire timeout from 300 seconds to 3000 seconds for AaregConsumer connections. This change aims to reduce connection acquisition failures during high latency periods. * Increase proxy timeouts in PDL Proxy config #deploy-pdl-proxy Extended the `nginx.ingress.kubernetes.io/proxy-read-timeout` and `proxy-send-timeout` annotations from 600 to 2400 seconds. This change aims to accommodate longer processing times required by the application. * Introduce delay in processing elements #deploy-levende-arbeidsforhold-ansettelse Added a delay of one minute between processing each element within the 'opprettAnsettelse' method to prevent overwhelming external services. This change aims to enhance system stability and prevent any rate-limiting issues. * This code diff introduces a significant change by migrating the application from a traditional Spring MVC architecture to a reactive Spring WebFlux architecture. This change is evident in the following modifications: **1. Reactive Dependencies:** - Removal of `spring-boot-starter-data-jpa` and addition of `spring-boot-starter-data-r2dbc` indicate a shift from blocking JPA to reactive R2DBC for database interactions. - Inclusion of `org.postgresql:r2dbc-postgresql` and `io.r2dbc:r2dbc-h2` provides drivers for reactive database connections. **2. Reactive Repositories:** - Repositories like `ParameterRepository`, `AnsettelseLoggRepository`, and `LoggRepository` now extend reactive interfaces like `ReactiveCrudRepository` and `ReactiveSortingRepository`. - Methods in these repositories now return reactive types like `Flux` and `Mono` instead of `List` and `Optional`. **3. Reactive Services:** - Service methods in `LoggService`, `ArbeidsforholdService`, `KodeverkService`, `AnsettelseLoggService`, and `ParameterService` are updated to return reactive types (`Flux`, `Mono`). - Usage of reactive operators like `flatMap`, `map`, and `collectList` is introduced for asynchronous data processing. **4. Reactive Controllers:** - Controllers like `ParameterController` and `LoggController` now return reactive types (`Flux`, `Mono`) from their endpoint methods. **5. Security Configuration:** - The `SecurityConfig` class is updated to use `EnableWebFluxSecurity` and `EnableReactiveMethodSecurity` annotations, indicating a shift to reactive security configurations. - The `springSecurityFilterChain` method now configures a `SecurityWebFilterChain` for reactive web requests. **6. Other Changes:** - Introduction of `NavHeaders` class for managing custom headers. - Update to OpenApiConfig to support reactive endpoints. - Removal of unused dependencies and code related to the previous Spring MVC architecture. **Impact:** This migration to a reactive architecture brings several benefits: - **Improved Performance and Scalability:** Reactive applications can handle more requests with fewer resources compared to traditional blocking applications. - **Non-Blocking Operations:** Asynchronous operations prevent threads from being blocked, leading to better resource utilization. - **Enhanced Responsiveness:** Reactive applications can respond to user requests faster, even under heavy load. **Considerations:** - Developers need to be familiar with reactive programming concepts and libraries like Reactor to work with this updated codebase. - Testing strategies need to be adapted for reactive components. - Existing code that interacts with the application might need adjustments to handle reactive types. This migration represents a significant architectural shift that can lead to a more performant and scalable application. * Add error handling and logging updates Included a new JsonNode for errors in PdlPersonDTO and added Jackson codecs in PdlConsumer. Enhanced logging in SokPersonCommand for debugging purposes. * Update and optimize logging repository and services #deploy-levende-arbeidsfoehold-ansettelse Refactor LoggRepository to use Mono for count and remove unnecessary vault dependencies. Added delay in ArbeidsforholdService to manage requests better and set restart policy in docker-compose. Introduced PageableHandlerMethodArgumentResolver for custom pageable handling and adjusted entity timestamp types. * Deploy #deploy-levende-arbeidsforhold-ansettelse * Switch to R2DBC for datasource configuration #deploy-testnav-levende-arbeidsforhold-ansettelse Updated the datasource configuration to use the R2DBC URL instead of the JDBC URL for PostgreSQL. Also, included username and password properties to align with the new configuration requirements. This change aims to improve non-blocking database interaction. * Deploy #deploy-levende-arbeidsforhold-ansettelse * Update logger encoder class for prod profile #deploy-levende-arbeidsforhold-ansettelse Changed the encoder class in the prod profile from `no.nav.testnav.libs.servletcore.logging.TestnavLogbackEncoder` to `no.nav.testnav.libs.reactivecore.logging.TestnavLogbackEncoder`. This ensures logs are managed by the appropriate logging framework for reactive applications. * Add r2dbc datasource configuration to application-prod.yml #deploy-levende-arbeidsforhold-ansettelse This change includes the addition of `r2dbc` configuration parameters for URL, username, and password in the `application-prod.yml` file. This ensures that the application has the necessary parameters to connect to the database using R2DBC. * Switch datasource URL from r2dbc to jdbc in prod config. #deploy-levende-arbeidsforhold-ansettelse Updated the datasource URL in the production configuration file to use JDBC instead of R2DBC. This change ensures compatibility and proper connectivity for database operations in the production environment. * Add R2DBC username and password to production config #deploy-levende-arbeidsforhold-ansettelse Updated the `application-prod.yml` to include necessary credentials for the R2DBC connection. This change ensures proper authentication and secure access to the PostgreSQL database. * Add environment variables from secret #deploy-levende-arbeidsforhold-ansettelse This commit updates the config.yml file to include environment variables sourced from the specified secret. This change is necessary for managing sensitive information securely in the application. It ensures that the application can access necessary credentials without hardcoding them into the configuration file. * Update datasource to r2dbc and reorganize configuration #deploy-levende-arbeidsforhold-ansettelse Replaced "datasource" with "r2dbc" for consistency and updated Flyway configurations to separate DB and R2DBC settings. These changes improve clarity and maintenance of configuration files. * Switch spring datasource to flyway in test config #deploy-levende-arbeidsforhold-ansettelse Updated the application.yaml to replace the spring datasource configuration with a flyway configuration for the test environment. This change is intended to streamline database migrations during testing. * Add SSL certificate to database URLs in production config #deploy-levende-arbeidsforhold-ansettelse Updated the database URLs in the production configuration file to include the SSL certificate parameter. This change ensures secure communication with the database using SSL certificates. * Update database URLs in production config #deploy-levende-arbeidsforhold-ansettelse Simplified the database URLs in `application-prod.yml` by using a single environment variable for each URL. This change reduces redundancy and simplifies the configuration management. * Update Flyway URL to use JDBC environment variable #deploy-levende-arbeidsforhold-ansettelse The Flyway URL configuration in the production YAML file now references the correct JDBC URL environment variable. This aligns the configuration with the expected environment setup and fixes potential issues with database migrations. * Update database configuration for production environment #deploy-levende-arbeidsforhold-ansettelse Modified the R2DBC URL to include host, port, and database name, and added username and password fields. This ensures all necessary connection details are properly configured for production. * Enable R2DBC repositories and update DB config #deploy-levende-arbeidsforhold-ansettelse Enabled R2DBC repositories in the Spring data configuration. Adjusted the R2DBC URL by removing the database name from the URL and added a separate 'name' field for the database. This improves clarity and consistency in database configuration settings. * Enable WebFlux and remove unnecessary R2DBC and envFrom settings #deploy-levende-arbeidsforhold-ansettelse Enabled WebFlux in the application configuration for reactive web support. Removed redundant R2DBC repository settings and obsolete environment variables, streamlining the configuration files. * Update dependencies in build and settings gradle files #deploy-levende-arbeidsforhold-ansettelse Removed unused 'database' and 'HikariCP' dependencies. Added 'spring-boot-starter-security' to enhance security features. These changes streamline the project dependencies and improve maintenance. * Switch to OAuth2 resource server dependency #deploy-levende-arbeidsforhold-ansettelse This change replaces the OAuth2 client dependency with the OAuth2 resource server dependency in build.gradle. This adjustment is necessary to align with the security requirements for handling resource server functionalities in the application. * Add PostgreSQL connection factory for production profile #deploy-levende-arbeidsforhold-ansettelse Introduced a new bean to configure a PostgreSQL connection factory when the 'prod' profile is active. This setup utilizes environment variables for connection details. * Add profile annotation and update health check paths #deploy-levende-arbeidsforhold-ansettelse Moved the @Profile("dev") annotation to the class level to streamline configuration. Updated liveness and readiness probe paths and delays in config.yml for better alignment with the new health endpoints. * Remove production database config and refine R2DBC setup #deploy-levende-arbeidsforhold-ansettelse Eliminated hardcoded production database connection settings. Enabled auto-configuration for R2DBC auditing and repositories. Adjusted application-dev.yml for cleaner configuration. * Add database connection pool validation query #deploy-levende-arbeidsforhold-ansettelse Added a validation query to the database connection pool configuration in the application-prod.yml file. This ensures the connection's health is checked by running a simple query, enhancing reliability. * Reorganize dependencies in build.gradle #deploy-levende-arbeidsforhold-ansettelse Move r2dbc-postgresql and r2dbc-h2 implementations for better structure and readability. Adjust runtimeOnly for h2 dependency to ensure proper runtime behavior. * Remove H2 console and runtime dependency #deploy-levende-arbeidsforhold-ansettelse Disabled the H2 console and removed the corresponding runtime dependency from build.gradle. This change simplifies the configuration and reduces unnecessary dependencies. * Refactor R2DBC configuration for dynamic database setup #deploy-levende-arbeidsforhold-ansettelse Updated R2DBC settings in YAML files to support dynamic database configuration. Introduced ConnectionFactory bean in ApplicationConfig to dynamically configure connection-related parameters. Added new configuration settings for both production and development environments. * Add protocol support for R2DBC configuration #deploy-levende-arbeidsforhold-ansettelse Introduced protocol field in R2DBC configuration to enhance flexibility. Adjusted configurations to conditionally include host and protocol options if they are present. Updated application configuration files to use the new protocol setting. * Switch to Spring's flyway and r2dbc configuration Add protocol support for R2DBC configuration #deploy-levende-arbeidsforhold-ansettelse Replaced custom R2DBC configurations with Spring's built-in settings in application YAML files and annotated out manual configuration in Java. This streamlines database connectivity and simplifies future maintenance. * Update database connection URL in application-prod.yml #deploy-levende-arbeidsforhold-ansettelse Changed the R2DBC URL to include specific PostgreSQL connection parameters. This ensures the database connection is properly configured with the required host, port, database name, and SSL settings. * Update DB URL to use environment variable placeholders #deploy-levende-arbeidsforhold-ansettelse Replaced hardcoded SSL path values in the database URL with corresponding environment variable placeholders. This change enhances security and flexibility by centralizing the configuration. * Set root logging level to DEBUG in logback configuration #deploy-levende-arbeidsforhold-ansettelse This change modifies the root logging level from INFO to DEBUG in the `logback-spring.xml` file. This adjustment enables more detailed logging output for better debugging during development or troubleshooting. * Change root log level to INFO Updated the root logging level from DEBUG to INFO in logback-spring.xml to reduce log verbosity in production. This will help in focusing on important informational messages and errors. * Update database configuration in application-prod.yml #deploy-levende-arbeidsforhold-ansettelse Refactored the R2DBC URL structure, separating credentials and SSL properties for clarity. This change improves maintainability and aligns with best practices for secure database connections. * Update database URL and comment out SSL properties #deploy-levende-arbeidsforhold-ansettelse Changed database URL to a fixed IP address and commented out the SSL properties. This modification may impact secure connections and should be reviewed prior to production deployment. * Remove connection pool configuration #deploy-levende-arbeidsforhold-ansettelse This change removes the connection pooling from the R2DBC URL in the production application configuration file. It ensures a direct connection to the PostgreSQL database without using a pool. * Update database connection settings in production config Remove connection pool configuration #deploy-levende-arbeidsforhold-ansettelse Changed the R2DBC URL to include connection pooling and enabled SSL properties with environment-specific variables. This enhances security and connection management for the production database. * Enable SSL debugging and enforce SSL verification #deploy-levende-arbeidsforhold-ansettelse Added SSL debugging options to JAVA_OPTS for better diagnostics. Changed the SSL mode to VERIFY_FULL in the production configuration to enforce stricter SSL verification. * Update SSL properties in application-prod.yml #deploy-levende-arbeidsforhold-ansettelse Replaced hard-coded SSL values with environment variables for better configuration flexibility. Adjusted `sslmode` and `sslkey` properties to use respective environment variables. * Disable Flyway database migration in production #deploy-levende-arbeidsforhold-ansettelse Commented out Flyway URL, username, and password configuration in application-prod.yml. Added a new property to disable Flyway migrations in the production environment. * Constructing JDBC URL in same manner as R2dbc URL, for testing. * Fixed typo in Flyway URL. #deploy-levende-arbeidsforhold-ansettelse * Added dependency on r2dbc-postgresql. #deploy-levende-arbeidsforhold-ansettelse * Moved from pool defined in URL (handled by R2DBC) and pool defined in config (handled by Spring). #deploy-levende-arbeidsforhold-ansettelse * - Changed dependencies based on a new Spring Init module w/R2DBC and PostgreSQL. - Added full URL with params for R2DBC. - Removed pool config. - Commented out ShortenedThrowableConverter (for now). #deploy-levende-arbeidsforhold-ansettelse * - Setting spring.r2dbc.pool.enabled=false (for now). #deploy-levende-arbeidsforhold-ansettelse * - Setting spring.data.r2dbc.repositories.enabled=true (for now). #deploy-levende-arbeidsforhold-ansettelse * - Attempting to remove H2 (for now). - Removed pool and repository config (no effect). - Stack trace no longer cut at 480 chars (for now). - Enabled debug mode to check bean resolution. #deploy-levende-arbeidsforhold-ansettelse * - Disabled test (for now; caused by disabling H2). #deploy-levende-arbeidsforhold-ansettelse * - Attempting to manually create a R2dbcEntityTemplate bean. #deploy-levende-arbeidsforhold-ansettelse * - Turning off debug. - Attempting to name bean. #deploy-levende-arbeidsforhold-ansettelse * Tester bruk av com.google.cloud.sql:r2dbc-postgres. #deploy-levende-arbeidsforhold-service * Endret til R2dbcRepository (som extends tidligere). * - Prøver endret format på filreferanser. - Fjerner com.google.cloud.sql:cloud-sql-connector-r2dbc-postgres. #deploy-levende-arbeidsforhold-ansettelse * - Lager nå en eksplisitt ConnectionFactory bean basert på konfigurert URL i spring.r2dbc.url. - Flytter @EnableR2dbc* til @SpringBootApplication, for oversikt. - Retter config for test (annet format URL for R2dbc mot H2). - Context-testen dobbeltsjekker at vi får en R2dbcEntityTemplate bean (fra AbstractR2dbcConfiguration). - Lagt til io.r2dbc:r2dbc-h2 som test dependency. - Erstattet org.postgresql:r2dbc-postgresql med io.r2dbc:r2dbc-postgresql som runtime dependency. #deploy-levende-arbeidsforhold-ansettelse * - Lager nå en eksplisitt bean R2dbcEntityTemplate. #deploy-levende-arbeidsforhold-ansettelse * - Endret fra io.r2dbc:r2dbc-postgresql til org.postgresql:r2dbc-postgresql, som faktisk virker. - Fjernet file:// prefix etter å ha verifisert at kode slår opp og leser inn fra filer på angitt navn. - Fjernet R2dbcConfiguration, siden den ikke trengs for verken prod eller test med org.postgresql:r2dbc-postgresql. #deploy-levende-arbeidsforhold-ansettelse * - Utvider TestnavLogbackEncoder til å ta config maxStackTraceLength (default som før). - Endrer logging midlertidig pga. testing. #deploy-levende-arbeidsforhold-ansettelse * - Rettet logging, med unlimited stack trace. #deploy-levende-arbeidsforhold-ansettelse * - Logger nå causes rekursivt om ønskelig (default off, som før). #deploy-levende-arbeidsforhold-ansettelse * Logger kun no.nav.testnav i stack trace. #deploy-levende-arbeidsforhold-ansettelse * - Prøver PK8 private key (rammeverket kan ikke lese format på PEM). - Slår av stack trace elements i loggen. #deploy-levende-arbeidsforhold-ansettelse * - Lager URL ut fra config. #deploy-levende-arbeidsforhold-ansettelse * - Fjerner sslCert og sslKey. #deploy-levende-arbeidsforhold-ansettelse * - Legger til sslCert uten sslKey. #deploy-levende-arbeidsforhold-ansettelse * - Tester uten ssl i properties, men med både sslCert og sslKey og tomt sslPassword. - Lagt til test på om sslCert-fil faktisk finnes. #deploy-levende-arbeidsforhold-ansettelse * - Health actuator viser detaljer. - Fjerner sslKey til fordel for testkode. #deploy-levende-arbeidsforhold-ansettelse * - Rettet manglende config for test. #deploy-levende-arbeidsforhold-ansettelse * - Alle spring.r2dbc.properties nå som URL-parametre. - Tester (for syns skyld) manuel load av PK8. #deploy-levende-arbeidsforhold-ansettelse * - La til manglende config for test (ikke brukt). #deploy-levende-arbeidsforhold-ansettelse * - Lagt til user og password i URL. #deploy-levende-arbeidsforhold-ansettelse * - Lagt til test-config for sjekk av filer. #deploy-levende-arbeidsforhold-ansettelse * - Fjernet feil dependency. #deploy-levende-arbeidsforhold-ansettelse * - Lagt til init-script som konverterer til PKCS#8-format. -Reverterer config til å bruke spring.r2dbc.properties, for lesbarhet. - Flytter application wide config til applikasjonsklassen og fjerner testkode i ApplicationConfig. #deploy-levende-arbeidsforhold-ansettelse * - Slår av SSL debugging. - Opprydding. #deploy-levende-arbeidsforhold-ansettelse * - Cleanup imports. - Presisering av format ved konvertering. * feature/configurable-logging-causes (#3663) - Kan nå konfigurere eller slå av lengde før stack trace trunkeres. Default til 480 hvis ikke satt (som før, men legger nå på " (truncated)..." i tillegg). - Kan nå legge til causes på stack trace. Default til false hvis ikke satt (som før). - Kan nå filtrere på elementer i stack trace. Default til alle hvis ikke satt (som før). * Introduce ArbeidsforholdResponseDTO for detailed responses #deploy-levende-arbeidsforhold-ansettelse Replaces HttpStatusCode with ArbeidsforholdResponseDTO to capture both status and detailed error messages. Refactors all related methods and classes to support this change, improving error handling and logging. * - Mindre framtidig forvirring; vi konverterer til en PKCS#8 (pk8) private key lagret på formatet PEM. * Remove sort order from API call in NyansettelserPage.tsx #deploy-test-front #deploy-frontend The sort order parameter 'id,DESC' was removed from the useLevendeArbeidsforholdLogg API call. This change simplifies the function call and relies on the API's default sorting behavior. * Implement retry logic for ansettPerson method #deploy-levende-arbeidsforhold-ansettelse Adds retry mechanism to handle failures when attempting to create new employment records, with up to 3 retries. Introduces AtomicInteger for tracking retry attempts and refactors the logic to ensure robust error handling and logging. --------- Co-authored-by: Cato Olsen Co-authored-by: Cato Olsen --- .../99-dolly-convert-to-pk8.sh | 6 + .../Dockerfile | 3 +- .../build.gradle | 45 ++------ .../config.yml | 14 +-- .../settings.gradle | 5 +- ...deArbeidsforholdAnsettelseApplication.java | 18 +++ .../config/ApplicationConfig.java | 18 --- .../config/OpenApiConfig.java | 25 +++-- .../config/SecurityConfig.java | 41 ++++--- .../config/WebConfig.java | 15 +++ .../consumers/AaregConsumer.java | 13 +-- .../consumers/KodeverkServiceConsumer.java | 6 +- .../consumers/PdlConsumer.java | 14 +++ .../aareg/HentArbeidsforholdCommand.java | 6 +- .../aareg/OpprettArbeidsforholdCommand.java | 22 +++- .../command/pdl/SokPersonCommand.java | 2 - .../controller/LoggController.java | 17 ++- .../controller/ParameterController.java | 13 +-- .../domain/NavHeaders.java | 9 ++ .../domain/dto/ArbeidsforholdResponseDTO.java | 18 +++ .../domain/dto/PdlPersonDTO.java | 3 + .../entity/AnsettelseLogg.java | 50 +++++---- .../entity/JobbParameter.java | 35 ++++-- .../repository/AnsettelseLoggRepository.java | 12 +- .../repository/LoggRepository.java | 13 ++- .../repository/ParameterRepository.java | 10 +- .../service/AnsettelseLoggService.java | 9 +- .../service/AnsettelseService.java | 104 ++++++++++-------- .../service/ArbeidsforholdService.java | 27 +++-- .../service/KodeverkService.java | 5 +- .../service/LoggService.java | 20 ++-- .../service/ParameterService.java | 33 +++--- .../service/PdlService.java | 8 +- ...PageableHandlerMethodArgumentResolver.java | 63 +++++++++++ .../src/main/resources/application-dev.yml | 44 ++++---- .../src/main/resources/application-prod.yml | 22 ++-- .../src/main/resources/application.yml | 3 +- .../resources/db/dev/h2-default-config.sql | 11 +- .../db/migration/V1.2.0__ModifyPrimaryKey.sql | 6 + .../src/main/resources/logback-spring.xml | 17 +-- .../main/resources/pdl/pdl-api-schema.graphql | 10 +- ...eidsforholdAnsettelseApplicationTests.java | 38 ++++++- .../src/test/resources/application-test.yml | 5 + docs/compose.yaml | 10 ++ .../config/LocalVaultConfig.java | 2 - .../config/SecurityConfig.java | 3 +- .../src/main/resources/application-local.yml | 9 +- libs/servlet-insecure-security/build.gradle | 1 - proxies/pdl-proxy/config.yml | 4 +- 49 files changed, 560 insertions(+), 327 deletions(-) create mode 100644 apps/levende-arbeidsforhold-ansettelse/99-dolly-convert-to-pk8.sh delete mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/ApplicationConfig.java create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/WebConfig.java create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/NavHeaders.java create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/ArbeidsforholdResponseDTO.java create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/utility/PageableHandlerMethodArgumentResolver.java create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/migration/V1.2.0__ModifyPrimaryKey.sql create mode 100644 apps/levende-arbeidsforhold-ansettelse/src/test/resources/application-test.yml diff --git a/apps/levende-arbeidsforhold-ansettelse/99-dolly-convert-to-pk8.sh b/apps/levende-arbeidsforhold-ansettelse/99-dolly-convert-to-pk8.sh new file mode 100644 index 00000000000..49cfce0b64e --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/99-dolly-convert-to-pk8.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +# +# Converts NAIS provided key.pem to PKCS#8 PEM format, which can be used by R2dbc. +# +openssl pkey -in /var/run/secrets/nais.io/sqlcertificate/key.pem -out /tmp/pk8.pem \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/Dockerfile b/apps/levende-arbeidsforhold-ansettelse/Dockerfile index dd8161548f8..da2ab16eeb7 100644 --- a/apps/levende-arbeidsforhold-ansettelse/Dockerfile +++ b/apps/levende-arbeidsforhold-ansettelse/Dockerfile @@ -3,6 +3,7 @@ LABEL maintainer="Team Dolly" ENV JAVA_OPTS="-Dspring.profiles.active=prod" -ADD /build/libs/app.jar /app/app.jar +COPY 99-dolly-convert-to-pk8.sh /init-scripts/ +COPY /build/libs/app.jar /app/ EXPOSE 8080 \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/build.gradle b/apps/levende-arbeidsforhold-ansettelse/build.gradle index 90dcde18837..e0037afe5c5 100644 --- a/apps/levende-arbeidsforhold-ansettelse/build.gradle +++ b/apps/levende-arbeidsforhold-ansettelse/build.gradle @@ -2,57 +2,36 @@ plugins { id "dolly-apps" } -test { - useJUnitPlatform() -} - sonarqube { properties { - property "sonar.dynamicAnalysis", "reuseReports" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.java.coveragePlugin", "jacoco" - property "sonar.language", "java" - property "sonar.token", System.getenv("SONAR_TOKEN") - property "sonar.organization", "navikt" - property "sonar.project.monorepo.enabled", true property "sonar.projectKey", "testnav-levende-arbeidsforhold-ansettelse" property "sonar.projectName", "testnav-levende-arbeidsforhold-ansettelse" - property "sonar.sourceEncoding", "UTF-8" } } - dependencies { implementation "no.nav.testnav.libs:data-transfer-objects" implementation "no.nav.testnav.libs:data-transfer-search-objects" - implementation "no.nav.testnav.libs:database" implementation "no.nav.testnav.libs:reactive-core" implementation "no.nav.testnav.libs:security-core" - implementation "no.nav.testnav.libs:servlet-core" + implementation "no.nav.testnav.libs:reactive-security" implementation "no.nav.testnav.libs:servlet-insecure-security" implementation "no.nav.testnav.libs:vault" - implementation "org.springframework.boot:spring-boot-starter-oauth2-client" - implementation "org.springframework.boot:spring-boot-starter-data-jpa" + implementation "org.springframework.boot:spring-boot-starter-data-r2dbc" + implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server" + implementation "org.springframework.boot:spring-boot-starter-security" - implementation "org.springframework.cloud:spring-cloud-starter-vault-config" + implementation "org.flywaydb:flyway-core" + implementation "org.flywaydb:flyway-database-postgresql" - implementation "org.postgresql:postgresql:42.7.3" + runtimeOnly "org.postgresql:postgresql" + runtimeOnly "org.postgresql:r2dbc-postgresql" implementation "io.micrometer:micrometer-registry-prometheus" - implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0" - implementation "io.swagger.core.v3:swagger-annotations-jakarta:2.2.21" - - implementation "org.hibernate.validator:hibernate-validator" - - testImplementation "org.springframework.boot:spring-boot-starter-test" - testImplementation "org.springframework.cloud:spring-cloud-contract-wiremock" - - implementation "org.projectlombok:lombok" - annotationProcessor "org.projectlombok:lombok" - testAnnotationProcessor "org.projectlombok:lombok" - - implementation "com.zaxxer:HikariCP" - implementation "com.h2database:h2" + implementation "org.springdoc:springdoc-openapi-starter-webflux-ui:$versions.springdoc" + implementation "io.swagger.core.v3:swagger-annotations-jakarta:$versions.swagger" + + testRuntimeOnly "io.r2dbc:r2dbc-h2" } diff --git a/apps/levende-arbeidsforhold-ansettelse/config.yml b/apps/levende-arbeidsforhold-ansettelse/config.yml index 6d779e98ed4..4c3f2ab68c7 100644 --- a/apps/levende-arbeidsforhold-ansettelse/config.yml +++ b/apps/levende-arbeidsforhold-ansettelse/config.yml @@ -28,11 +28,6 @@ spec: allowAllUsers: true enabled: true tenant: nav.no - liveness: - path: /internal/isAlive - initialDelay: 4 - periodSeconds: 5 - failureThreshold: 500 observability: logging: destinations: @@ -40,11 +35,12 @@ spec: autoInstrumentation: enabled: true runtime: java + liveness: + initialDelay: 45 + path: /internal/health/liveness readiness: - path: /internal/isReady - initialDelay: 4 - periodSeconds: 5 - failureThreshold: 500 + initialDelay: 45 + path: /internal/health/readiness prometheus: enabled: true path: /internal/metrics diff --git a/apps/levende-arbeidsforhold-ansettelse/settings.gradle b/apps/levende-arbeidsforhold-ansettelse/settings.gradle index 7c8a740fb8c..bb179528ada 100644 --- a/apps/levende-arbeidsforhold-ansettelse/settings.gradle +++ b/apps/levende-arbeidsforhold-ansettelse/settings.gradle @@ -4,13 +4,12 @@ plugins { rootProject.name = 'levende-arbeidsforhold-ansettelse' -includeBuild '../../libs/security-core' -includeBuild '../../libs/servlet-core' +includeBuild '../../libs/reactive-security' includeBuild '../../libs/reactive-core' +includeBuild '../../libs/security-core' includeBuild '../../libs/servlet-insecure-security' includeBuild '../../libs/data-transfer-objects' includeBuild '../../libs/data-transfer-search-objects' -includeBuild '../../libs/database' includeBuild '../../libs/vault' develocity { diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplication.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplication.java index af85ef82344..42c3411a5ef 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplication.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplication.java @@ -1,12 +1,30 @@ package no.nav.testnav.levendearbeidsforholdansettelse; +import no.nav.testnav.libs.reactivecore.config.CoreConfig; +import no.nav.testnav.libs.reactivesecurity.config.SecureOAuth2ServerToServerConfiguration; +import no.nav.testnav.libs.standalone.servletsecurity.config.InsecureJwtServerToServerConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; +import org.springframework.data.r2dbc.config.EnableR2dbcAuditing; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.web.reactive.config.EnableWebFlux; @SpringBootApplication +@EnableAsync +@EnableR2dbcAuditing +@EnableR2dbcRepositories +@EnableWebFlux +@Import({ + CoreConfig.class, + SecureOAuth2ServerToServerConfiguration.class, + InsecureJwtServerToServerConfiguration.class +}) public class LevendeArbeidsforholdAnsettelseApplication { public static void main(String[] args) { SpringApplication.run(LevendeArbeidsforholdAnsettelseApplication.class, args); } + } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/ApplicationConfig.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/ApplicationConfig.java deleted file mode 100644 index cdfc25cd18a..00000000000 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/ApplicationConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package no.nav.testnav.levendearbeidsforholdansettelse.config; - -import no.nav.testnav.libs.servletcore.config.ApplicationCoreConfig; -import no.nav.testnav.libs.standalone.servletsecurity.config.InsecureJwtServerToServerConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.scheduling.annotation.EnableAsync; - -@Configuration -@Import({ - ApplicationCoreConfig.class, - InsecureJwtServerToServerConfiguration.class -}) -@EnableAsync -public class ApplicationConfig { - -} - diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/OpenApiConfig.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/OpenApiConfig.java index 366834bcc32..863b0003ff2 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/OpenApiConfig.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/OpenApiConfig.java @@ -7,16 +7,19 @@ import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; -import no.nav.testnav.libs.servletcore.config.ApplicationProperties; +import no.nav.testnav.libs.reactivecore.config.ApplicationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.http.HttpHeaders; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; import java.util.Arrays; @Configuration -public class OpenApiConfig implements WebMvcConfigurer { +public class OpenApiConfig implements WebFilter { @Bean public OpenAPI openApi(ApplicationProperties applicationProperties) { @@ -26,7 +29,7 @@ public OpenAPI openApi(ApplicationProperties applicationProperties) { .scheme("bearer") .bearerFormat("JWT") .in(SecurityScheme.In.HEADER) - .name("Authorization") + .name(HttpHeaders.AUTHORIZATION) )) .addSecurityItem( new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write"))) @@ -48,7 +51,15 @@ public OpenAPI openApi(ApplicationProperties applicationProperties) { } @Override - public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/swagger").setViewName("redirect:/swagger-ui.html"); + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + if (exchange.getRequest().getURI().getPath().equals("/swagger")) { + return chain + .filter(exchange.mutate() + .request(exchange.getRequest() + .mutate().path("/swagger-ui.html").build()) + .build()); + } + + return chain.filter(exchange); } } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/SecurityConfig.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/SecurityConfig.java index 0f287cc8b54..9cbb0b2b1ba 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/SecurityConfig.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/SecurityConfig.java @@ -1,26 +1,28 @@ package no.nav.testnav.levendearbeidsforholdansettelse.config; +import lombok.RequiredArgsConstructor; +import no.nav.testnav.libs.reactivesecurity.manager.JwtReactiveAuthenticationManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.Customizer; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; -@EnableWebSecurity @Configuration +@EnableWebFluxSecurity +@EnableReactiveMethodSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final JwtReactiveAuthenticationManager jwtReactiveAuthenticationManager; + @Bean @SuppressWarnings("java:S4502") - public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { - - httpSecurity.sessionManagement(sessionConfig -> sessionConfig.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests(authorizeConfig -> authorizeConfig.requestMatchers( + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity httpSecurity) { + return httpSecurity + .csrf(ServerHttpSecurity.CsrfSpec::disable) + .authorizeExchange(authorizeConfig -> authorizeConfig.pathMatchers( "/internal/**", "/webjars/**", "/swagger-resources/**", @@ -31,13 +33,8 @@ public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Excepti "/swagger-ui.html", "/h2/**", "/member/**") - .permitAll() - .requestMatchers("/api/**") - .fullyAuthenticated()) - .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) - .oauth2ResourceServer(oauth2RSConfig -> oauth2RSConfig.jwt(Customizer.withDefaults())); - - return httpSecurity.build(); + .permitAll().anyExchange().authenticated()) + .oauth2ResourceServer(oauth2RSConfig -> oauth2RSConfig.jwt(jwtSpec -> jwtSpec.authenticationManager(jwtReactiveAuthenticationManager))) + .build(); } -} - +} \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/WebConfig.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/WebConfig.java new file mode 100644 index 00000000000..e228460b2fc --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/config/WebConfig.java @@ -0,0 +1,15 @@ +package no.nav.testnav.levendearbeidsforholdansettelse.config; + +import no.nav.testnav.levendearbeidsforholdansettelse.utility.PageableHandlerMethodArgumentResolver; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.config.WebFluxConfigurer; +import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; + +@Configuration +public class WebConfig implements WebFluxConfigurer { + + @Override + public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { + configurer.addCustomResolver(new PageableHandlerMethodArgumentResolver()); + } +} diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/AaregConsumer.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/AaregConsumer.java index e921868112a..cd7b85d1df4 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/AaregConsumer.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/AaregConsumer.java @@ -1,16 +1,13 @@ package no.nav.testnav.levendearbeidsforholdansettelse.consumers; -import io.netty.channel.ChannelOption; -import io.netty.channel.epoll.EpollChannelOption; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.levendearbeidsforholdansettelse.config.Consumers; import no.nav.testnav.levendearbeidsforholdansettelse.consumers.command.aareg.HentArbeidsforholdCommand; import no.nav.testnav.levendearbeidsforholdansettelse.consumers.command.aareg.OpprettArbeidsforholdCommand; +import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ArbeidsforholdResponseDTO; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsforhold; import no.nav.testnav.libs.securitycore.domain.ServerProperties; import no.nav.testnav.libs.standalone.servletsecurity.exchange.TokenExchange; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.ResponseEntity; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; @@ -44,7 +41,7 @@ public AaregConsumer( .create(ConnectionProvider.builder("AaregConsumer") .maxConnections(1) .pendingAcquireMaxCount(10000) - .pendingAcquireTimeout(Duration.ofSeconds(300)) + .pendingAcquireTimeout(Duration.ofSeconds(3000)) .build()) )) .build(); @@ -56,10 +53,10 @@ public Flux hentArbeidsforhold(String ident) { .flatMapMany(token -> new HentArbeidsforholdCommand(webClient, token.getTokenValue(), ident).call())); } - public Flux opprettArbeidsforhold(Arbeidsforhold requests) { + public Flux opprettArbeidsforhold(Arbeidsforhold requests) { return Flux.from(tokenExchange.exchange(serverProperties) - .flatMap(token -> new OpprettArbeidsforholdCommand(webClient, requests, token.getTokenValue()).call()) - .map(ResponseEntity::getStatusCode)); + .flatMap(token -> new OpprettArbeidsforholdCommand(webClient, + requests, token.getTokenValue()).call())); } } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/KodeverkServiceConsumer.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/KodeverkServiceConsumer.java index 263800d4851..6bfb34c37fb 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/KodeverkServiceConsumer.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/KodeverkServiceConsumer.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; @@ -39,12 +40,11 @@ public KodeverkServiceConsumer( objectMapper = new ObjectMapper(); } - public List hentKodeverk(String kodeverk) { + public Mono> hentKodeverk(String kodeverk) { return tokenExchange.exchange(serverProperties) .flatMap(token -> new KodeverkServiceCommand(webClient, token.getTokenValue(), kodeverk, objectMapper).call()) .map(Map::keySet) - .map(ArrayList::new) - .block(); + .map(ArrayList::new); } } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/PdlConsumer.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/PdlConsumer.java index 6c63af3560d..6f27d1a9398 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/PdlConsumer.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/PdlConsumer.java @@ -1,5 +1,6 @@ package no.nav.testnav.levendearbeidsforholdansettelse.consumers; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import lombok.val; import no.nav.testnav.levendearbeidsforholdansettelse.config.Consumers; @@ -11,8 +12,12 @@ import no.nav.testnav.libs.securitycore.domain.ServerProperties; import no.nav.testnav.libs.standalone.servletsecurity.exchange.TokenExchange; import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.http.codec.json.Jackson2JsonDecoder; +import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; import reactor.netty.http.client.HttpClient; @@ -37,12 +42,21 @@ public class PdlConsumer { public PdlConsumer( TokenExchange tokenService, Consumers consumers, + ObjectMapper objectMapper, WebClient.Builder webClientBuilder) { serverProperties = consumers.getPdlProxy(); this.tokenService = tokenService; webClient = webClientBuilder .baseUrl(serverProperties.getUrl()) + .exchangeStrategies(ExchangeStrategies.builder() + .codecs(config -> { + config.defaultCodecs() + .jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON)); + config.defaultCodecs() + .jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON)); + }) + .build()) .clientConnector( new ReactorClientHttpConnector( HttpClient diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/HentArbeidsforholdCommand.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/HentArbeidsforholdCommand.java index 1d5fb53956a..7ab9b5920f1 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/HentArbeidsforholdCommand.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/HentArbeidsforholdCommand.java @@ -2,9 +2,9 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.levendearbeidsforholdansettelse.domain.NavHeaders; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsforhold; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; -import no.nav.testnav.libs.servletcore.headers.NavHeaders; import org.springframework.http.HttpHeaders; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class HentArbeidsforholdCommand implements Callable> { - private static final String miljoe = "q2"; + private static final String MILJOE = "q2"; private static final String NAV_PERSON_IDENT = "Nav-Personident"; private static final String CONSUMER = "Dolly"; @@ -45,7 +45,7 @@ public Flux call() { .queryParam("arbeidsforholdtype", "forenkletOppgjoersordning", "frilanserOppdragstakerHonorarPersonerMm", "maritimtArbeidsforhold", "ordinaertArbeidsforhold") - .build(miljoe)) + .build(MILJOE)) .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) .header(NAV_PERSON_IDENT, ident) .header(NavHeaders.NAV_CONSUMER_ID, CONSUMER) diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/OpprettArbeidsforholdCommand.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/OpprettArbeidsforholdCommand.java index 76edef8cfb4..5e8c2414da2 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/OpprettArbeidsforholdCommand.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/aareg/OpprettArbeidsforholdCommand.java @@ -2,20 +2,24 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ArbeidsforholdResponseDTO; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsforhold; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import reactor.util.retry.Retry; import java.time.Duration; import java.util.concurrent.Callable; + +import static io.netty.handler.codec.http.HttpResponseStatus.CREATED; + @Slf4j @RequiredArgsConstructor -public class OpprettArbeidsforholdCommand implements Callable>> { +public class OpprettArbeidsforholdCommand implements Callable> { private final String navArbeidsforholdKilde = "Dolly-automatisk-ansettelse" ; private final String miljoe = "q2"; @@ -25,7 +29,7 @@ public class OpprettArbeidsforholdCommand implements Callable> call() { + public Mono call() { return webClient.post() .uri(builder -> builder.path("/{miljoe}/api/v1/arbeidsforhold") @@ -35,9 +39,17 @@ public Mono> call() { .header("Nav-Arbeidsforhold-Kildereferanse", navArbeidsforholdKilde) .bodyValue(requests) .retrieve() - .toBodilessEntity() + .bodyToMono(String.class) + .map(payload -> ArbeidsforholdResponseDTO.builder() + .statusCode(HttpStatusCode.valueOf(CREATED.code())) + .payload(payload) + .build()) .retryWhen(Retry.backoff(3, Duration.ofSeconds(5)) .filter(WebClientFilter::is5xxException)) - .doOnError(WebClientFilter::logErrorMessage); + .doOnError(WebClientFilter::logErrorMessage) + .onErrorResume(error -> Mono.just(ArbeidsforholdResponseDTO.builder() + .statusCode(WebClientFilter.getStatus(error)) + .feilmelding(WebClientFilter.getMessage(error)) + .build())); } } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/pdl/SokPersonCommand.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/pdl/SokPersonCommand.java index c8e8aff85b2..2d52ec25141 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/pdl/SokPersonCommand.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/consumers/command/pdl/SokPersonCommand.java @@ -1,7 +1,6 @@ package no.nav.testnav.levendearbeidsforholdansettelse.consumers.command.pdl; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.PdlPersonDTO; import no.nav.testnav.levendearbeidsforholdansettelse.domain.pdl.GraphqlVariables; import no.nav.testnav.levendearbeidsforholdansettelse.provider.PdlMiljoer; @@ -25,7 +24,6 @@ import static no.nav.testnav.levendearbeidsforholdansettelse.domain.pdl.CommonKeysAndUtils.HEADER_NAV_CONSUMER_ID; import static org.springframework.http.HttpHeaders.AUTHORIZATION; -@Slf4j @RequiredArgsConstructor public class SokPersonCommand implements Callable> { diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/LoggController.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/LoggController.java index 3e369388a0d..1d67f42ced9 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/LoggController.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/LoggController.java @@ -5,13 +5,15 @@ import no.nav.testnav.levendearbeidsforholdansettelse.entity.AnsettelseLogg; import no.nav.testnav.levendearbeidsforholdansettelse.service.LoggService; import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @RestController @RequestMapping("/api/v1/logg") @@ -22,21 +24,24 @@ public class LoggController { @GetMapping @Operation(description = "Henter logger i hht forespørsel") - public Page getAnsettelser(Pageable pageable) { + public Mono> getAnsettelser(@RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size, + @RequestParam(defaultValue = "id") String... sort) { + var pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, sort)); return loggService.getAnsettelseLogg(pageable); } @GetMapping("/ident/{ident}") @Operation(description = "Henter logg i hht forespørsel") - public List getIdent(@PathVariable String ident) { + public Flux getIdent(@PathVariable String ident) { return loggService.getIdent(ident); } @GetMapping("/organisasjon/{orgnummer}") @Operation(description = "Henter logg i hht forespørsel") - public List getOrganisasjon(@PathVariable String orgnummer) { + public Flux getOrganisasjon(@PathVariable String orgnummer) { return loggService.getOrgnummer(orgnummer); } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/ParameterController.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/ParameterController.java index 1e0692cc0ab..eb92a65f120 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/ParameterController.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/controller/ParameterController.java @@ -5,8 +5,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ParameterDTO; +import no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameter; import no.nav.testnav.levendearbeidsforholdansettelse.service.ParameterService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -15,8 +15,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @Slf4j @RestController @@ -24,7 +24,6 @@ @RequiredArgsConstructor public class ParameterController { - @Autowired private final ParameterService parameterService; /** @@ -33,7 +32,7 @@ public class ParameterController { */ @GetMapping @Operation(description = "Henter alle parametre for oppretting av arbeidsforhold") - public List hentAlleParametere() { + public Flux hentAlleParametere() { return parameterService.hentAlleParametere(); } @@ -46,8 +45,8 @@ public List hentAlleParametere() { @PutMapping("/{parameternavn}") @Operation(description = "Legg inn ny verdi på en parameter") @ResponseStatus(HttpStatus.OK) - public void oppdatereVerdier(@PathVariable("parameternavn") String parameternavn, @RequestBody String verdi){ + public Mono oppdatereVerdier(@PathVariable("parameternavn") String parameternavn, @RequestBody String verdi){ - parameterService.updateVerdi(parameternavn, verdi); + return parameterService.updateVerdi(parameternavn, verdi); } } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/NavHeaders.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/NavHeaders.java new file mode 100644 index 00000000000..f58ac8da888 --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/NavHeaders.java @@ -0,0 +1,9 @@ +package no.nav.testnav.levendearbeidsforholdansettelse.domain; + +public class NavHeaders { + private NavHeaders() { + } + + public static final String NAV_CALL_ID = "Nav-Call-Id"; + public static final String NAV_CONSUMER_ID = "Nav-Consumer-Id"; +} \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/ArbeidsforholdResponseDTO.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/ArbeidsforholdResponseDTO.java new file mode 100644 index 00000000000..5e582372bb5 --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/ArbeidsforholdResponseDTO.java @@ -0,0 +1,18 @@ +package no.nav.testnav.levendearbeidsforholdansettelse.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.http.HttpStatusCode; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArbeidsforholdResponseDTO { + + private HttpStatusCode statusCode; + private String payload; + private String feilmelding; +} diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/PdlPersonDTO.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/PdlPersonDTO.java index f07c3fddfd5..a6207a63704 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/PdlPersonDTO.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/domain/dto/PdlPersonDTO.java @@ -1,5 +1,6 @@ package no.nav.testnav.levendearbeidsforholdansettelse.domain.dto; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -20,6 +21,8 @@ @AllArgsConstructor public class PdlPersonDTO { + private JsonNode errors; + private Data data; public enum Gruppe {AKTORID, FOLKEREGISTERIDENT, NPID} diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/AnsettelseLogg.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/AnsettelseLogg.java index a7bb270114e..363a592c87b 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/AnsettelseLogg.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/AnsettelseLogg.java @@ -1,63 +1,61 @@ package no.nav.testnav.levendearbeidsforholdansettelse.entity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; -import java.math.BigDecimal; import java.time.LocalDate; -import java.time.OffsetDateTime; +import java.time.LocalDateTime; @Data @Builder @NoArgsConstructor @AllArgsConstructor -@Entity @Table(name = "ansettelse_logg") -public class AnsettelseLogg { +public class AnsettelseLogg implements Persistable { + + @Transient + private boolean isNew; + @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") - @SequenceGenerator(name = "seq", sequenceName = "ansettelse_logg_id_seq", allocationSize = 1) - @Column(name = "id", nullable = false) + @NotNull + @Column("id") private Integer id; @Size(max = 255) @NotNull - @Column(name = "organisasjonsnummer", nullable = false) + @Column("organisasjonsnummer") private String organisasjonsnummer; @Size(max = 255) @NotNull - @Column(name = "folkeregisterident", nullable = false) + @Column("folkeregisterident") private String folkeregisterident; @NotNull - @Column(name = "timestamp", nullable = false) - private OffsetDateTime timestamp; + @Column("timestamp") + private LocalDateTime timestamp; @NotNull - @Column(name = "ansattfra", nullable = false) + @Column("ansattfra") private LocalDate ansattfra; @Size(max = 255) - @Column(name = "arbeidsforhold_type") + @Column("arbeidsforhold_type") private String arbeidsforholdType; - @Column(name = "stillingsprosent") + @Column("stillingsprosent") private Integer stillingsprosent; @Override @@ -73,4 +71,10 @@ public boolean equals(Object o) { public int hashCode() { return new HashCodeBuilder(17, 37).append(getId()).append(getOrganisasjonsnummer()).append(getFolkeregisterident()).append(getTimestamp()).append(getAnsattfra()).append(getArbeidsforholdType()).append(getStillingsprosent()).toHashCode(); } + + @Override + @JsonIgnore + public boolean isNew() { + return isNew; + } } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/JobbParameter.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/JobbParameter.java index f83a7253fc2..ae87f7e5b36 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/JobbParameter.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/entity/JobbParameter.java @@ -1,35 +1,39 @@ package no.nav.testnav.levendearbeidsforholdansettelse.entity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import lombok.Data; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; @Data -@Entity @Table(name = "jobb_parameter") -public class JobbParameter { +public class JobbParameter implements Persistable { + + @Transient + private boolean isNew; @Id @Size(max = 255) - @Column(name = "navn", nullable = false) + @Column("navn") private String navn; @Size(max = 255) @NotNull - @Column(name = "tekst", nullable = false) + @Column("tekst") private String tekst; @Size(max = 255) - @Column(name = "verdi") + @Column("verdi") private String verdi; - @Column(name = "verdier") + @Column("verdier") private String verdier; @Override @@ -45,4 +49,15 @@ public boolean equals(Object o) { public int hashCode() { return new HashCodeBuilder(17, 37).append(getNavn()).append(getTekst()).append(getVerdi()).append(getVerdier()).toHashCode(); } + + @Override + public String getId() { + return navn; + } + + @Override + @JsonIgnore + public boolean isNew() { + return isNew; + } } \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/AnsettelseLoggRepository.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/AnsettelseLoggRepository.java index b1407856edb..4a2043b2492 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/AnsettelseLoggRepository.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/AnsettelseLoggRepository.java @@ -1,12 +1,14 @@ package no.nav.testnav.levendearbeidsforholdansettelse.repository; import no.nav.testnav.levendearbeidsforholdansettelse.entity.AnsettelseLogg; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; -import java.util.List; +@Repository +public interface AnsettelseLoggRepository extends R2dbcRepository { -public interface AnsettelseLoggRepository extends CrudRepository { + Flux findByFolkeregisterident(String ident); + Flux findByOrganisasjonsnummer(String orgnummer); - List findByFolkeregisterident(String ident); - List findByOrganisasjonsnummer(String orgnummer); } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/LoggRepository.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/LoggRepository.java index 0159dc3608b..0a404194fef 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/LoggRepository.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/LoggRepository.java @@ -1,7 +1,16 @@ package no.nav.testnav.levendearbeidsforholdansettelse.repository; import no.nav.testnav.levendearbeidsforholdansettelse.entity.AnsettelseLogg; -import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.domain.Pageable; +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Repository +public interface LoggRepository extends R2dbcRepository { + + Flux findAllBy(Pageable pageable); + Mono countAllBy(); -public interface LoggRepository extends PagingAndSortingRepository { } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/ParameterRepository.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/ParameterRepository.java index a4e5d29920e..ee237eff1e9 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/ParameterRepository.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/repository/ParameterRepository.java @@ -1,11 +1,9 @@ package no.nav.testnav.levendearbeidsforholdansettelse.repository; import no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameter; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.stereotype.Repository; -import java.util.List; - -public interface ParameterRepository extends CrudRepository { - - List findAll(); +@Repository +public interface ParameterRepository extends R2dbcRepository { } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseLoggService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseLoggService.java index f5c59ad428f..abee69b3366 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseLoggService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseLoggService.java @@ -6,9 +6,10 @@ import no.nav.testnav.levendearbeidsforholdansettelse.entity.AnsettelseLogg; import no.nav.testnav.levendearbeidsforholdansettelse.repository.AnsettelseLoggRepository; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; import java.time.LocalDate; -import java.time.OffsetDateTime; +import java.time.LocalDateTime; import java.util.Map; import static no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameterNavn.ARBEIDSFORHOLD_TYPE; @@ -26,15 +27,17 @@ public class AnsettelseLoggService { /** * Funksjonen som lagrer ansettelsen i db + * * @param kanAnsette inneholder ident og orgnummer * @param parametere Stillingsprosent og arbeidsavtalarbeidsforholdType til personen. */ - public AnsettelseLogg lagreAnsettelse(KanAnsettesDTO kanAnsette, Map parametere){ + public Mono lagreAnsettelse(KanAnsettesDTO kanAnsette, Map parametere) { return ansettelseLoggRepository.save(AnsettelseLogg.builder() + .isNew(true) .folkeregisterident(kanAnsette.getIdent()) .organisasjonsnummer(kanAnsette.getOrgnummer()) - .timestamp(OffsetDateTime.now()) + .timestamp(LocalDateTime.now()) .arbeidsforholdType(parametere.get(ARBEIDSFORHOLD_TYPE.value)) .stillingsprosent(Integer.parseInt(parametere.get(STILLINGSPROSENT.value))) .ansattfra(LocalDate.now()) diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseService.java index fc7319c60f7..9c522152ff9 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/AnsettelseService.java @@ -5,6 +5,7 @@ import no.nav.testnav.levendearbeidsforholdansettelse.consumers.TenorConsumer; import no.nav.testnav.levendearbeidsforholdansettelse.domain.DatoIntervall; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ArbeidsforholdDTO; +import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ArbeidsforholdResponseDTO; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.KanAnsettesDTO; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.OrganisasjonResponseDTO; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.PdlPersonDTO; @@ -14,15 +15,15 @@ import no.nav.testnav.levendearbeidsforholdansettelse.utility.SannsynlighetVelger; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsavtale; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsforhold; -import org.springframework.http.HttpStatusCode; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; +import java.security.SecureRandom; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; @@ -30,6 +31,7 @@ import static no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameterNavn.ANTALL_PERSONER; import static no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameterNavn.ARBEIDSFORHOLD_TYPE; import static no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameterNavn.STILLINGSPROSENT; +import static org.apache.commons.lang3.BooleanUtils.isTrue; import static org.apache.commons.lang3.StringUtils.isNumeric; @Slf4j @@ -37,6 +39,9 @@ @RequiredArgsConstructor public class AnsettelseService { + private static final Random RANDOM = new SecureRandom(); + private static final Integer ANTALL_RETRIES = 3; + private final PdlService pdlService; private final TenorConsumer tenorConsumer; private final ArbeidsforholdService arbeidsforholdService; @@ -47,42 +52,26 @@ public class AnsettelseService { @Async public void runAnsettelseService() { - Thread thread = new Thread(this::ansettelseService); - thread.start(); - try { - thread.join(3_500_000); //Timeout etter 3000 sekunder - if (thread.isAlive()) { - thread.interrupt(); - log.info("Timeout occurred"); - } - } catch (InterruptedException e) { - log.info("Timet ut"); - } - } - - @Transactional - public void ansettelseService() { - var startTime = System.currentTimeMillis(); //Henter parametere fra db - var parametere = parameterService.hentParametere(); - log.info("Startet oppretting av {} personer i {} organisasjoner", parametere.get("antallPersoner"), - parametere.get("antallOrganisasjoner")); + var parametere = parameterService.hentParametere() + .doOnNext(param -> + log.info("Startet oppretting av {} personer i {} organisasjoner", + param.get("antallPersoner"), + param.get("antallOrganisasjoner"))); //Henter yrkeskoder for å gi tilfeldige yrker var yrkeskoder = kodeverkService.hentKodeverkValues(KodeverkNavn.YRKER.value); - if (yrkeskoder.isEmpty()) { - return; - } //Initialiserer liste over alderspenn og liste med tidligste og seneste gyldig dato for ansttelse var datoIntervaller = SannsynlighetVelger.getDatointervaller(); //Kjører ansettelse per org - Flux.range(0, (int) getParameterValue(parametere, ANTALL_ORGANISASJONER)) - .flatMap(count -> tenorConsumer.hentOrganisasjon()) - .flatMap(organisasjon -> sjekkOgSendinnArbeidsforhold(organisasjon, parametere, yrkeskoder, datoIntervaller)) + Flux.zip(parametere, yrkeskoder) + .flatMap(tuple -> Flux.range(0, (int) getParameterValue(tuple.getT1(), ANTALL_ORGANISASJONER)) + .flatMap(count -> tenorConsumer.hentOrganisasjon()) + .flatMap(organisasjon -> sjekkOgSendinnArbeidsforhold(organisasjon, tuple.getT1(), tuple.getT2(), datoIntervaller))) .collectList() .subscribe(status -> log.info("Oppretting ferdig, antall ansettelser {}, medgått tid {} sekunder", status.size(), (System.currentTimeMillis() - startTime) / 1000)); @@ -91,22 +80,45 @@ public void ansettelseService() { private Flux sjekkOgSendinnArbeidsforhold(OrganisasjonResponseDTO organisasjon, Map parametere, List yrkeskoder, List datointervaller) { - return Flux.fromIterable(getFordeling(parametere).entrySet()) + return Flux.fromIterable(getFordeling(parametere).entrySet()) + .limitRate(1) .flatMap(intervall -> Flux.range(0, intervall.getValue()) - .flatMap(index -> getPersonSomKanAnsettes((int) getParameterValue(parametere, STILLINGSPROSENT), - datointervaller.get(intervall.getKey()), organisasjon) - .flatMap(kanAnsettes -> ansettPerson(kanAnsettes, hentTilfeldigYrkeskode(yrkeskoder), parametere) - .doOnNext(status -> log.info("Opprettet arbeidsforhold orgnummer {}, ident {}, status {}", - kanAnsettes.getOrgnummer(), kanAnsettes.getIdent(), status)) - .map(status -> - ansettelseLoggService.lagreAnsettelse(kanAnsettes, parametere))))); + .flatMap(index -> hentOgAnsett(organisasjon, parametere, + hentTilfeldigYrkeskode(yrkeskoder), + datointervaller.get(intervall.getKey()), new AtomicInteger(ANTALL_RETRIES)))); + } + + private Flux hentOgAnsett(OrganisasjonResponseDTO organisasjon, + Map parametere, + String yrkeskode, DatoIntervall datointervall, AtomicInteger retries) { + + if (retries.get() == 0) { + return Flux.empty(); + } + + return getPersonSomKanAnsettes((int) getParameterValue(parametere, STILLINGSPROSENT), + datointervall, organisasjon) + .flatMap(kanAnsettes -> ansettPerson(kanAnsettes, yrkeskode, parametere) + .flatMap(response -> { + if (response.getStatusCode().is2xxSuccessful()) { + log.info("Opprettet arbeidsforhold orgnummer {}, ident {}, status {}", + kanAnsettes.getOrgnummer(), kanAnsettes.getIdent(), response.getStatusCode()); + return ansettelseLoggService.lagreAnsettelse(kanAnsettes, parametere); + } else { + log.error("Oppretting mot AAREG feilet, orgnummer {}, ident {} med feilmelding {} ", + kanAnsettes.getOrgnummer(), kanAnsettes.getIdent(), response.getFeilmelding()); + return hentOgAnsett(organisasjon, parametere, + yrkeskode, + datointervall, new AtomicInteger(retries.decrementAndGet())); + } + })); } private Flux getPersonSomKanAnsettes(Integer stillingsprosent, DatoIntervall intervall, OrganisasjonResponseDTO organisasjon) { return getArbeidsforhold(intervall, organisasjon.getPostnummer()) - .map(arbeidsforhold1 -> Flux.fromIterable(arbeidsforhold1.getArbeidsforhold()) + .flatMap(arbeidsforhold1 -> Flux.fromIterable(arbeidsforhold1.getArbeidsforhold()) .map(Arbeidsforhold::getArbeidsavtaler) .flatMap(Flux::fromIterable) .filter(arbeidsavtale -> nonNull(arbeidsavtale.getBruksperiode()) && @@ -116,7 +128,7 @@ private Flux getPersonSomKanAnsettes(Integer stillingsprosent, D .reduce(0, (a, b) -> (int) (a + b)) .map(sum -> sum + stillingsprosent <= 100) .map(done -> { - if (done) { + if (isTrue(done)) { return Flux.just(KanAnsettesDTO.builder() .ident(arbeidsforhold1.getIdent()) .orgnummer(organisasjon.getOrgnummer()) @@ -127,13 +139,17 @@ private Flux getPersonSomKanAnsettes(Integer stillingsprosent, D return getPersonSomKanAnsettes(stillingsprosent, intervall, organisasjon); } })) - .flatMap(Flux::from) .flatMap(Flux::from); } private Flux getArbeidsforhold(DatoIntervall datoIntervall, String postnummer) { return pdlService.getPerson(datoIntervall, postnummer) + .doOnNext(person -> log.info("Hentet person fra PDL med ident {}", + person.getFolkeregisteridentifikator().stream() + .filter(PdlPersonDTO.Person.Folkeregisteridentifikator::isIBRUK) + .map(PdlPersonDTO.Person.Folkeregisteridentifikator::getIdentifikasjonsnummer) + .findFirst().orElse(null))) .flatMap(person -> Flux.fromIterable(person.getFolkeregisteridentifikator()) .filter(PdlPersonDTO.Person.Folkeregisteridentifikator::isIBRUK) .map(PdlPersonDTO.Person.Folkeregisteridentifikator::getIdentifikasjonsnummer)) @@ -145,8 +161,8 @@ private Flux getArbeidsforhold(DatoIntervall datoIntervall, S .build())); } - private Flux ansettPerson(KanAnsettesDTO arbeidsforhold, String yrke, - Map parametere) { + private Flux ansettPerson(KanAnsettesDTO arbeidsforhold, String yrke, + Map parametere) { return arbeidsforholdService.opprettArbeidsforhold(arbeidsforhold, yrke, (String) getParameterValue(parametere, ARBEIDSFORHOLD_TYPE), @@ -160,13 +176,9 @@ private static int getAntallAnsettelserIHverOrg(Map parametere) (int) getParameterValue(parametere, ANTALL_ORGANISASJONER); } - private int tilfeldigTall(int max) { - Random random = new Random(); - return random.nextInt(max); - } - private String hentTilfeldigYrkeskode(List yrkeskoder) { - return yrkeskoder.get(tilfeldigTall(yrkeskoder.size())); + + return yrkeskoder.get(RANDOM.nextInt(yrkeskoder.size())); } private static Object getParameterValue(Map parametere, JobbParameterNavn parameterNavn) { diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ArbeidsforholdService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ArbeidsforholdService.java index 66b479053cc..1c843b4d62b 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ArbeidsforholdService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ArbeidsforholdService.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.levendearbeidsforholdansettelse.consumers.AaregConsumer; +import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ArbeidsforholdResponseDTO; import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.KanAnsettesDTO; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Ansettelsesperiode; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Arbeidsforhold; @@ -10,13 +11,11 @@ import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Organisasjon; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Periode; import no.nav.testnav.libs.dto.levendearbeidsforhold.v1.Person; -import org.springframework.http.HttpStatusCode; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import java.math.BigDecimal; import java.math.RoundingMode; -import java.time.Duration; import java.time.LocalDate; import java.util.List; @@ -25,10 +24,10 @@ @RequiredArgsConstructor public class ArbeidsforholdService { - private static final String arbeidstakerType = "Person"; - private static final String arbeidsgiverType = "Organisasjon"; - private static final String arbeidstidsordning = "ikkeSkift"; - private static final String ansettelsesform = "fast"; + private static final String ARBEIDSTAKER_TYPE = "Person"; + private static final String ARBEIDSGIVER_TYPE = "Organisasjon"; + private static final String ARBEIDSTIDSORDNING = "ikkeSkift"; + private static final String ANSETTELSESFORM = "fast"; private static final double TIMER_HUNDRE_PROSENT = 37.5; private static final int HUNDRE_PROSENT = 100; @@ -51,11 +50,11 @@ public Flux getArbeidsforhold(String ident) { * @param stillingsprosent Stillinsprosenten arbeidsforholdet skal ha * @return HttpStatusCode basert på resultatet av spørringen */ - public Flux opprettArbeidsforhold(KanAnsettesDTO kanAnsettes, String yrke, - String arbeidsforholdstype, Integer stillingsprosent) { + public Flux opprettArbeidsforhold(KanAnsettesDTO kanAnsettes, String yrke, + String arbeidsforholdstype, Integer stillingsprosent) { - return aaregConsumer.opprettArbeidsforhold(lagArbeidsforhold(kanAnsettes, yrke, arbeidsforholdstype, stillingsprosent)) - .delayElements(Duration.ofSeconds(1)); + return aaregConsumer.opprettArbeidsforhold(lagArbeidsforhold(kanAnsettes, + yrke, arbeidsforholdstype, stillingsprosent)); } /** @@ -75,11 +74,11 @@ private Arbeidsforhold lagArbeidsforhold(KanAnsettesDTO kanAnsettes, String yrke .arbeidsforholdId(Integer.toString(kanAnsettes.getAntallEksisterendeArbeidsforhold() + 1)) .arbeidstaker(Person.builder() .offentligIdent(kanAnsettes.getIdent()) - .type(arbeidstakerType) + .type(ARBEIDSTAKER_TYPE) .build()) .arbeidsgiver(Organisasjon.builder() .organisasjonsnummer(kanAnsettes.getOrgnummer()) - .type(arbeidsgiverType) + .type(ARBEIDSGIVER_TYPE) .build()) .type(arbeidsforholdType) .ansettelsesperiode(Ansettelsesperiode.builder() @@ -89,10 +88,10 @@ private Arbeidsforhold lagArbeidsforhold(KanAnsettesDTO kanAnsettes, String yrke .build()) .arbeidsavtaler(List.of(OrdinaerArbeidsavtale.builder() .antallTimerPrUke(antallTimerPrUke) - .arbeidstidsordning(arbeidstidsordning) + .arbeidstidsordning(ARBEIDSTIDSORDNING) .stillingsprosent(stillingsprosent) .yrke(yrke) - .ansettelsesform(ansettelsesform) + .ansettelsesform(ANSETTELSESFORM) .sistStillingsendring(LocalDate.now()) .build())) .build(); diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/KodeverkService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/KodeverkService.java index 82344771753..204361d88c0 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/KodeverkService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/KodeverkService.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import no.nav.testnav.levendearbeidsforholdansettelse.consumers.KodeverkServiceConsumer; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; import java.util.List; @@ -21,8 +22,8 @@ public class KodeverkService { * @param kodeverk String som er navnet på kodeverket. * @return En liste av String som er kodene. */ - public List hentKodeverkValues(String kodeverk){ + public Mono> hentKodeverkValues(String kodeverk){ + return kodeverkServiceConsumer.hentKodeverk(kodeverk); } - } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/LoggService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/LoggService.java index 1e6a225f1f4..720c7b6fc97 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/LoggService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/LoggService.java @@ -5,11 +5,11 @@ import no.nav.testnav.levendearbeidsforholdansettelse.repository.AnsettelseLoggRepository; import no.nav.testnav.levendearbeidsforholdansettelse.repository.LoggRepository; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @Service @RequiredArgsConstructor @@ -18,20 +18,20 @@ public class LoggService { private final LoggRepository loggRepository; private final AnsettelseLoggRepository ansettelseLoggRepository; - @Transactional(readOnly = true) - public Page getAnsettelseLogg(Pageable pageable) { + public Mono> getAnsettelseLogg(Pageable pageable) { - return loggRepository.findAll(pageable); + return loggRepository.findAllBy(pageable) + .collectList() + .zipWith(loggRepository.countAllBy()) + .map(tuple -> new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())); } - @Transactional(readOnly = true) - public List getIdent(String ident) { + public Flux getIdent(String ident) { return ansettelseLoggRepository.findByFolkeregisterident(ident); } - @Transactional(readOnly = true) - public List getOrgnummer(String orgnummer) { + public Flux getOrgnummer(String orgnummer) { return ansettelseLoggRepository.findByOrganisasjonsnummer(orgnummer); } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ParameterService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ParameterService.java index 2dee53e4cfd..50118cc9eb7 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ParameterService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/ParameterService.java @@ -5,13 +5,11 @@ import no.nav.testnav.levendearbeidsforholdansettelse.domain.dto.ParameterDTO; import no.nav.testnav.levendearbeidsforholdansettelse.entity.JobbParameter; import no.nav.testnav.levendearbeidsforholdansettelse.repository.ParameterRepository; -import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.server.ResponseStatusException; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -30,16 +28,15 @@ public class ParameterService { * * @return Returnerer en liste av JobbParameterObjektene til alle parameterne */ - public List hentAlleParametere() { + public Flux hentAlleParametere() { - return parameterRepository.findAll().stream() + return parameterRepository.findAll() .map(parameter -> ParameterDTO.builder() .navn(parameter.getNavn()) .tekst(parameter.getTekst()) .verdi(parameter.getVerdi()) .verdier(Arrays.asList(parameter.getVerdier().split(","))) - .build()) - .toList(); + .build()); } /** @@ -47,9 +44,9 @@ public List hentAlleParametere() { * * @return ett map av JobbParameter navnet og verdier */ - public Map hentParametere() { + public Mono> hentParametere() { - return parameterRepository.findAll().stream() + return parameterRepository.findAll() .collect(Collectors.toMap(JobbParameter::getNavn, JobbParameter::getVerdi)); } @@ -60,14 +57,14 @@ public Map hentParametere() { * @param verdi ny verdi for parameter */ - @Transactional - public void updateVerdi(String parameternavn, String verdi) { + public Mono updateVerdi(String parameternavn, String verdi) { - parameterRepository.findById(parameternavn) - .ifPresentOrElse(parameter -> parameter.setVerdi(verdi), - () -> { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, - "Parameter med navn %s ble ikke funnet".formatted(parameternavn)); - }); + return parameterRepository.findById(parameternavn) + .map(parameter -> { + parameter.setVerdi(verdi); + return parameter; + } + ) + .flatMap(parameterRepository::save); } } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/PdlService.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/PdlService.java index 5c671b8c5b4..01c94ece9f0 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/PdlService.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/service/PdlService.java @@ -23,6 +23,7 @@ public class PdlService { private static final Random RANDOM = new SecureRandom(); + private static final String CONTAINS = "contains"; private final PdlConsumer pdlConsumer; @@ -38,6 +39,7 @@ public Flux getPerson(DatoIntervall datoIntervall, String p return pdlConsumer.getSokPerson(lagSokPersonPaging(1), lagSokPersonCriteria(datoIntervall, postnummer), PdlMiljoer.Q2) + .filter(data -> nonNull(data.getData())) .map(PdlPersonDTO::getData) .filter(data -> nonNull(data.getSokPerson())) .map(PdlPersonDTO.Data::getSokPerson) @@ -71,17 +73,17 @@ private GraphqlVariables.Criteria lagSokPersonCriteria(DatoIntervall intervall, GraphqlVariables.Filter testnorge = GraphqlVariables.Filter.builder() .fieldName("tags") - .searchRule(Map.of("contains", "TESTNORGE")) + .searchRule(Map.of(CONTAINS, "TESTNORGE")) .build(); GraphqlVariables.Filter dolly = GraphqlVariables.Filter.builder() .fieldName("tags") - .searchRule(Map.of("contains", "DOLLY")) + .searchRule(Map.of(CONTAINS, "DOLLY")) .build(); GraphqlVariables.Filter arenasynt = GraphqlVariables.Filter.builder() .fieldName("tags") - .searchRule(Map.of("contains", "ARENASYNT")) + .searchRule(Map.of(CONTAINS, "ARENASYNT")) .build(); var or = Map.of("or", List.of(filterBostedPostnr, filterOppholdPostnr)); diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/utility/PageableHandlerMethodArgumentResolver.java b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/utility/PageableHandlerMethodArgumentResolver.java new file mode 100644 index 00000000000..3e2f14ef144 --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/java/no/nav/testnav/levendearbeidsforholdansettelse/utility/PageableHandlerMethodArgumentResolver.java @@ -0,0 +1,63 @@ +package no.nav.testnav.levendearbeidsforholdansettelse.utility; + +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.web.reactive.BindingContext; +import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.List; + +import static java.util.Objects.nonNull; + +public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { + + private static final String DEFAULT_PAGE = "0"; + private static final String DEFAULT_SIZE = "10"; + private static final Integer MAX_SIZE = 50; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return Pageable.class.equals(parameter.getParameterType()); + } + + @Override + public Mono resolveArgument(MethodParameter methodParameter, + BindingContext bindingContext, + ServerWebExchange serverWebExchange) { + + var pageValues = serverWebExchange.getRequest() + .getQueryParams() + .getOrDefault("page", List.of(DEFAULT_PAGE)); + var sizeValues = serverWebExchange.getRequest() + .getQueryParams() + .getOrDefault("size", List.of(DEFAULT_SIZE)); + + var page = pageValues.getFirst(); + + var sortParam = serverWebExchange.getRequest() + .getQueryParams().getFirst("sort"); + + var sort = Sort.unsorted(); + + if (nonNull(sortParam)) { + var parts = sortParam.split(","); + if (parts.length == 2) { + var property = parts[0]; + var direction = Sort.Direction.fromString(parts[1]); + sort = Sort.by(direction, property); + } + } + + return Mono.just( + PageRequest.of( + Integer.parseInt(page), + Math.min(Integer.parseInt(sizeValues.getFirst()), + MAX_SIZE), sort + ) + ); + } +} \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-dev.yml b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-dev.yml index 44846a38ac7..8e05042d920 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-dev.yml +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-dev.yml @@ -1,27 +1,33 @@ spring: - h2: - console: - enabled: true - path: /h2 - datasource: - url: jdbc:h2:mem:testdb - username: sa + flyway: + # InMemmory database + url: jdbc:postgresql://localhost:5432/testnav-levende-arbeidsforhold + user: ${NAV_USERNAME} password: - driverClassName: org.h2.Driver - sql: - init: - mode: always - data-locations: classpath:/db/dev/h2-default-config.sql + r2dbc: + url: r2dbc:postgresql://localhost:5432/testnav-levende-arbeidsforhold + username: ${NAV_USERNAME} + password: +# sql: +# init: +# mode: always +# data-locations: classpath:/db/dev/h2-default-config.sql + +# main: +# allow-bean-definition-overriding: true +# +#config: +# r2dbc: +# driver: h2 +# protocol: mem +# port: 5432 +# database: testdb +# username: sa +# password: consumers: testnav-kodeverk-service: url: https://testnav-kodeverk-service.intern.dev.nav.no - name: testnav-kodeverk-service - cluster: dev-gcp - namespace: dolly testnav-tenor-search-service: - url: https://testnav-tenor-search-service.intern.dev.nav.no - name: testnav-tenor-search-service - cluster: dev-gcp - namespace: dolly \ No newline at end of file + url: https://testnav-tenor-search-service.intern.dev.nav.no \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-prod.yml b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-prod.yml index 38ddcad04da..67030d4ac12 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-prod.yml +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application-prod.yml @@ -1,12 +1,14 @@ spring: - datasource: - url: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_JDBC_URL} - driverClassName: org.postgresql.Driver - hikari: - maximum-pool-size: 3 - minimum-idle: 0 - jpa: - database: POSTGRESQL + r2dbc: + url: r2dbc:postgresql://${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_HOST}:${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_PORT}/${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_DATABASE} + username: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_USERNAME} + password: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_PASSWORD} properties: - hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect \ No newline at end of file + sslCert: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_SSLCERT} + sslKey: /tmp/pk8.pem # See Dockerfile and 99-dolly-convert-to-pk8.sh. + sslMode: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_SSLMODE} + sslRootCert: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_SSLROOTCERT} + flyway: + url: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_JDBC_URL} + user: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_USERNAME} + password: ${NAIS_DATABASE_TESTNAV_LEVENDE_ARBEIDSFORHOLD_TESTNAV_LEVENDE_ARBEIDSFORHOLD_PASSWORD} diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application.yml b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application.yml index b1858ad73ad..f04dd806222 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application.yml +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/application.yml @@ -35,8 +35,9 @@ management: path-mapping: prometheus: metrics endpoint: - prometheus.enabled: true + health.show-details: always heapdump.enabled: true + prometheus.enabled: true prometheus: metrics: export: diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/dev/h2-default-config.sql b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/dev/h2-default-config.sql index 1f3f24c6599..8dcdec671ff 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/dev/h2-default-config.sql +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/dev/h2-default-config.sql @@ -1,8 +1,9 @@ -- Default verdier for kjøring med H2 -insert into jobb_parameter values('stillingsprosent','Stillingsprosent','80','20,30,40,50,60,70,80,90,100'); -insert into jobb_parameter values('intervall','Intervall for neste kjøring (timer)','1','1,5,12,24,168'); -insert into jobb_parameter values('antallOrganisasjoner','Antall Organisasjoner','1','1,5,10,15,20,25,30,35,40,45,50'); -insert into jobb_parameter values('antallPersoner','Antall Personer','1','1,10,15,20,25,30,35,40,45,50,1001'); -insert into jobb_parameter values('arbeidsforholdType','Arbeidsforhold Type','ordinaertArbeidsforhold','forenkletOppgjoersordning,frilanserOppdragstakerHonorarPersonerMm,maritimtArbeidsforhold,ordinaertArbeidsforhold'); +insert into jobb_parameter(navn, tekst, verdi, verdier) values('stillingsprosent','Stillingsprosent','80','20,30,40,50,60,70,80,90,100'); +insert into jobb_parameter(navn, tekst, verdi, verdier) values('intervall','Intervall for neste kjøring (timer)','1','1,5,12,24,168'); +insert into jobb_parameter(navn, tekst, verdi, verdier) values('antallOrganisasjoner','Antall Organisasjoner','1','1,5,10,15,20,25,30,35,40,45,50'); +insert into jobb_parameter(navn, tekst, verdi, verdier) values('antallPersoner','Antall Personer','1','1,10,15,20,25,30,35,40,45,50,1001'); +insert into jobb_parameter(navn, tekst, verdi, verdier) values('arbeidsforholdType','Arbeidsforhold Type','ordinaertArbeidsforhold','forenkletOppgjoersordning,frilanserOppdragstakerHonorarPersonerMm,maritimtArbeidsforhold,ordinaertArbeidsforhold'); + commit; \ No newline at end of file diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/migration/V1.2.0__ModifyPrimaryKey.sql b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/migration/V1.2.0__ModifyPrimaryKey.sql new file mode 100644 index 00000000000..9db5c6b644f --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/db/migration/V1.2.0__ModifyPrimaryKey.sql @@ -0,0 +1,6 @@ +----------------------------------- +-- M O D I F Y I N D E C I E S -- +----------------------------------- + +ALTER TABLE ansettelse_logg +ALTER COLUMN id SET DEFAULT NEXTVAL('ansettelse_logg_id_seq'); diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/logback-spring.xml b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/logback-spring.xml index 5f39b7c7b9b..7feaa817ab0 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/logback-spring.xml +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/logback-spring.xml @@ -2,19 +2,10 @@ - - - true - - 10280 - 20 - ^sun\.reflect\..*\.invoke - ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke - java\.util\.concurrent\..* - org\.apache\.catalina\..* - org\.apache\.coyote\..* - org\.apache\.tomcat\..* - + + -1 + true + - diff --git a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/pdl/pdl-api-schema.graphql b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/pdl/pdl-api-schema.graphql index d0209854938..db34cec7313 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/main/resources/pdl/pdl-api-schema.graphql +++ b/apps/levende-arbeidsforhold-ansettelse/src/main/resources/pdl/pdl-api-schema.graphql @@ -432,6 +432,11 @@ type Navn { originaltNavn: OriginaltNavn } +type Navspersonidentifikator { + identifikasjonsnummer: String! + metadata: Metadata! +} + type Opphold { folkeregistermetadata: Folkeregistermetadata! metadata: Metadata! @@ -479,6 +484,7 @@ type Person { kontaktadresse(historikk: Boolean = false): [Kontaktadresse!]! kontaktinformasjonForDoedsbo(historikk: Boolean = false): [KontaktinformasjonForDoedsbo!]! navn(historikk: Boolean = false): [Navn!]! + navspersonidentifikator(historikk: Boolean = false): [Navspersonidentifikator!]! opphold(historikk: Boolean = false): [Opphold!]! oppholdsadresse(historikk: Boolean = false): [Oppholdsadresse!]! rettsligHandleevne(historikk: Boolean = false): [RettsligHandleevne!]! @@ -893,7 +899,7 @@ input SearchRule { " Begrenser treff til kun de hvor felt har input verdi" equals: String " Sjekker om feltet finnes / at det ikke har en null verdi." - exists: String + exists: Boolean """ Søk fra og med (se fromExcluding for bare fra men ikke med) @@ -915,7 +921,7 @@ input SearchRule { " Filtrerer bort treff hvor felt inneholder input verdi" notEquals: String " Søk som gir tilfeldig poengsum til hvert treff (kun ment til generering av testdata)" - random: String + random: Float " Regex søk for spesielle situasjoner (Dette er en treg opprasjon og bør ikke brukes)" regex: String " Gir treff når opgitt feltstarter med opgitt verdi." diff --git a/apps/levende-arbeidsforhold-ansettelse/src/test/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplicationTests.java b/apps/levende-arbeidsforhold-ansettelse/src/test/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplicationTests.java index 569b084d2ac..f0251a8e160 100644 --- a/apps/levende-arbeidsforhold-ansettelse/src/test/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplicationTests.java +++ b/apps/levende-arbeidsforhold-ansettelse/src/test/java/no/nav/testnav/levendearbeidsforholdansettelse/LevendeArbeidsforholdAnsettelseApplicationTests.java @@ -1,19 +1,55 @@ package no.nav.testnav.levendearbeidsforholdansettelse; +import io.netty.handler.ssl.SslContextBuilder; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.test.context.ActiveProfiles; + +import java.io.File; +import java.io.FileInputStream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.fail; @SpringBootTest +@ActiveProfiles("test") class LevendeArbeidsforholdAnsettelseApplicationTests { @MockBean + @SuppressWarnings("unused") public ReactiveJwtDecoder jwtDecoder; + @Autowired + private R2dbcEntityTemplate template; + @Test - @SuppressWarnings("java:S2699") void load_app_context() { + assertThat(template) + .isNotNull(); + } + + @Disabled("Useful for checking the format of a SSL key file manually.") + @Test + @SuppressWarnings("java:S2699") + void attemptToLoadSslKeyFile() + throws Exception { + var sslKey = "key.pk8"; + System.err.println("SSL Key File: " + sslKey); + var file = new File(sslKey); + System.out.println("File " + file.getAbsolutePath() + (file.exists() ? " exists" : " not found")); + if (!file.exists()) { + fail(); + } else { + SslContextBuilder + .forClient() + .keyManager(null, new FileInputStream(file), null) + .build(); + } } } diff --git a/apps/levende-arbeidsforhold-ansettelse/src/test/resources/application-test.yml b/apps/levende-arbeidsforhold-ansettelse/src/test/resources/application-test.yml new file mode 100644 index 00000000000..00672563fc5 --- /dev/null +++ b/apps/levende-arbeidsforhold-ansettelse/src/test/resources/application-test.yml @@ -0,0 +1,5 @@ +spring: + r2dbc: + url: r2dbc:h2:mem:///~/db/testdb + username: sa + password: \ No newline at end of file diff --git a/docs/compose.yaml b/docs/compose.yaml index c957309a956..02a8dafd3c2 100644 --- a/docs/compose.yaml +++ b/docs/compose.yaml @@ -27,4 +27,14 @@ services: - POSTGRES_HOST_AUTH_METHOD=trust ports: - "5434:5432" + restart: always + + postgres-levende-arbeidforhold: + container_name: postgres-levende-arbeidforhold-test + image: postgres:latest + environment: + - POSTGRES_DB=postgres-levende-arbeidforhold-test + - POSTGRES_HOST_AUTH_METHOD=trust + ports: + - "5435:5432" restart: always \ No newline at end of file diff --git a/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/LocalVaultConfig.java b/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/LocalVaultConfig.java index afcd86c9291..ba9ff220d64 100644 --- a/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/LocalVaultConfig.java +++ b/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/LocalVaultConfig.java @@ -3,10 +3,8 @@ import no.nav.testnav.libs.vault.AbstractLocalVaultConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import org.springframework.vault.annotation.VaultPropertySource; @Configuration @Profile("local") -@VaultPropertySource(value = "azuread/prod/creds/team-dolly-lokal-app", ignoreSecretNotFound = false) public class LocalVaultConfig extends AbstractLocalVaultConfiguration { } \ No newline at end of file diff --git a/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/SecurityConfig.java b/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/SecurityConfig.java index 616aebdc994..80bde93dfc0 100644 --- a/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/SecurityConfig.java +++ b/examples/reactive-rest-example/src/main/java/no/nav/testnav/examples/reactiverestexample/config/SecurityConfig.java @@ -33,7 +33,8 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity httpS "/swagger-ui/**", "/swagger", "/error", - "/swagger-ui.html" + "/h2/**", + "/member/**" ).permitAll().anyExchange().authenticated()) .oauth2ResourceServer(oauth2RSConfig -> oauth2RSConfig.jwt(jwtSpec -> jwtSpec.authenticationManager(jwtReactiveAuthenticationManager))) .build(); diff --git a/examples/reactive-rest-example/src/main/resources/application-local.yml b/examples/reactive-rest-example/src/main/resources/application-local.yml index 94f1ea3900a..403f11ba4ba 100644 --- a/examples/reactive-rest-example/src/main/resources/application-local.yml +++ b/examples/reactive-rest-example/src/main/resources/application-local.yml @@ -1,10 +1,17 @@ +TOKEN_X_ISSUER: nada + spring: application: # Override name name: reactive-rest-example-local + h2: + console: + enabled: true + path: /h2 flyway: # InMemmory database url: jdbc:h2:mem:testdb username: sa - password: \ No newline at end of file + password: + driverClassName: org.h2.Driver \ No newline at end of file diff --git a/libs/servlet-insecure-security/build.gradle b/libs/servlet-insecure-security/build.gradle index 21a166d7a93..d212cb034ad 100644 --- a/libs/servlet-insecure-security/build.gradle +++ b/libs/servlet-insecure-security/build.gradle @@ -16,6 +16,5 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' } \ No newline at end of file diff --git a/proxies/pdl-proxy/config.yml b/proxies/pdl-proxy/config.yml index a044b13b15d..b5a88f48086 100644 --- a/proxies/pdl-proxy/config.yml +++ b/proxies/pdl-proxy/config.yml @@ -19,8 +19,8 @@ metadata: labels: team: dolly annotations: - nginx.ingress.kubernetes.io/proxy-read-timeout: "600" - nginx.ingress.kubernetes.io/proxy-send-timeout: "600" + nginx.ingress.kubernetes.io/proxy-read-timeout: "2400" + nginx.ingress.kubernetes.io/proxy-send-timeout: "2400" spec: image: "{{image}}" port: 8080