diff --git a/.nais/app-dev.yml b/.nais/app-dev.yml index 9da1a27..6a200b0 100644 --- a/.nais/app-dev.yml +++ b/.nais/app-dev.yml @@ -33,6 +33,13 @@ spec: application: enabled: true allowAllUsers: true + claims: + extra: + - NAVident + groups: + - id: "8bb0ee13-49cd-4e75-8c3d-a13420c8b376" + - id: "12353679-aa80-4e59-bb47-95e727bfe85c" + - id: "b60d74dd-fcf7-4c53-a50b-7b20f51804a1" resources: limits: memory: 256Mi diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3eb5734..ebdfc88 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,13 +1,13 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - kotlin("jvm") version "1.9.24" - id("io.ktor.plugin") version "2.3.10" + kotlin("jvm") version "2.0.0" + id("io.ktor.plugin") version "2.3.11" } val aapLibVersion = "5.0.15" val ktorVersion = "2.3.11" -val exposedVersion = "0.50.1" +val exposedVersion = "0.51.1" application { mainClass.set("oppgavestyring.AppKt") @@ -15,6 +15,8 @@ application { dependencies { implementation("com.github.navikt.aap-libs:ktor-auth:$aapLibVersion") + implementation("io.ktor:ktor-server-auth:$ktorVersion") + implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion") implementation("io.ktor:ktor-server-core:$ktorVersion") implementation("io.ktor:ktor-server-netty:$ktorVersion") implementation("io.ktor:ktor-server-metrics-micrometer:$ktorVersion") @@ -28,15 +30,16 @@ dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-logging:$ktorVersion") - implementation(kotlin("reflect")) + // Koin for Kotlin apps + implementation("io.insert-koin:koin-ktor:3.5.6") // persistence implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion") - implementation("org.flywaydb:flyway-core:10.13.0") - implementation("org.flywaydb:flyway-database-postgresql:10.13.0") + implementation("org.flywaydb:flyway-core:10.14.0") + implementation("org.flywaydb:flyway-database-postgresql:10.14.0") implementation("com.zaxxer:HikariCP:5.1.0") runtimeOnly("org.postgresql:postgresql:42.7.3") testImplementation("org.testcontainers:postgresql:1.19.8") @@ -49,9 +52,9 @@ dependencies { testImplementation(kotlin("test")) testImplementation("io.ktor:ktor-server-test-host:$ktorVersion") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.26.0") testImplementation("io.mockk:mockk:1.13.10") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.26.0") } repositories { diff --git a/app/src/main/kotlin/oppgavestyring/App.kt b/app/src/main/kotlin/oppgavestyring/App.kt index 3c7debd..0c72705 100644 --- a/app/src/main/kotlin/oppgavestyring/App.kt +++ b/app/src/main/kotlin/oppgavestyring/App.kt @@ -7,6 +7,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import io.ktor.http.* import io.ktor.serialization.jackson.* import io.ktor.server.application.* +import io.ktor.server.auth.* import io.ktor.server.engine.* import io.ktor.server.metrics.micrometer.* import io.ktor.server.netty.* @@ -18,13 +19,13 @@ import io.micrometer.core.instrument.binder.logging.LogbackMetrics import io.micrometer.prometheus.PrometheusConfig import io.micrometer.prometheus.PrometheusMeterRegistry import oppgavestyring.actuators.api.actuators -import oppgavestyring.behandlingsflyt.BehandlingsflytAdapter -import oppgavestyring.behandlingsflyt.behandlingsflyt -import oppgavestyring.config.db.DatabaseSingleton -import oppgavestyring.config.db.DbConfig -import oppgavestyring.oppgave.OppgaveService -import oppgavestyring.oppgave.adapter.Token -import oppgavestyring.oppgave.api.oppgaver +import oppgavestyring.config.koinModule +import oppgavestyring.config.security.AZURE +import oppgavestyring.config.security.authentication +import oppgavestyring.ekstern.behandlingsflyt.behandlingsflyt +import oppgavestyring.intern.filter.filter +import oppgavestyring.intern.oppgave.api.oppgaver +import org.koin.ktor.plugin.Koin import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -36,14 +37,10 @@ fun main() { embeddedServer(Netty, port = 8080, module = Application::server).start(wait = true) } -fun Application.server( - config: Config = Config(), -) { - val prometheus = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) +fun Application.oppgavestyring(config: Config) { - install(MicrometerMetrics) { - registry = prometheus - meterBinders += LogbackMetrics() + install(Koin) { + modules(koinModule) } install(ContentNegotiation) { @@ -67,22 +64,31 @@ fun Application.server( } } - DatabaseSingleton.init(DbConfig()) - DatabaseSingleton.migrate() - - val oppgaveService = OppgaveService() - val behandlingsflytAdapter = BehandlingsflytAdapter(oppgaveService) + authentication(config.azure) routing { - actuators(prometheus) - oppgaver(oppgaveService) - behandlingsflyt(behandlingsflytAdapter) + authenticate(AZURE) { + oppgaver() + filter() + } + behandlingsflyt() + } } -internal fun ApplicationCall.authToken(): Token? { - return request.headers["Authorization"] - ?.split(" ") - ?.get(1) - ?.let { Token(it) } +fun Application.server( + config: Config = Config(), +) { + val prometheus = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + + install(MicrometerMetrics) { + registry = prometheus + meterBinders += LogbackMetrics() + } + + oppgavestyring(config) + + routing { + actuators() + } } diff --git a/app/src/main/kotlin/oppgavestyring/actuators/api/ActuatorsRoute.kt b/app/src/main/kotlin/oppgavestyring/actuators/api/ActuatorsRoute.kt index 7502b1e..c9323ad 100644 --- a/app/src/main/kotlin/oppgavestyring/actuators/api/ActuatorsRoute.kt +++ b/app/src/main/kotlin/oppgavestyring/actuators/api/ActuatorsRoute.kt @@ -5,8 +5,11 @@ import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.micrometer.prometheus.PrometheusMeterRegistry +import org.koin.ktor.ext.inject -fun Route.actuators(prometheus: PrometheusMeterRegistry) { +fun Route.actuators() { + + val prometheus: PrometheusMeterRegistry by inject() route("/actuator") { get("/live") { diff --git a/app/src/main/kotlin/oppgavestyring/config/Koin.kt b/app/src/main/kotlin/oppgavestyring/config/Koin.kt new file mode 100644 index 0000000..ff691e7 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/config/Koin.kt @@ -0,0 +1,18 @@ +package oppgavestyring.config + +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry +import oppgavestyring.config.db.DatabaseConfiguration +import oppgavestyring.config.db.DatabaseManager +import oppgavestyring.ekstern.behandlingsflyt.BehandlingsflytAdapter +import oppgavestyring.intern.oppgave.OppgaveService +import org.koin.dsl.module + +val koinModule = module { + + single { OppgaveService() } + single { BehandlingsflytAdapter(get()) } + single { PrometheusMeterRegistry(PrometheusConfig.DEFAULT) } + single(createdAtStart = true) { DatabaseManager(DatabaseConfiguration()) } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/config/db/DbConfig.kt b/app/src/main/kotlin/oppgavestyring/config/db/DatabaseConfiguration.kt similarity index 94% rename from app/src/main/kotlin/oppgavestyring/config/db/DbConfig.kt rename to app/src/main/kotlin/oppgavestyring/config/db/DatabaseConfiguration.kt index edd3c05..d09f258 100644 --- a/app/src/main/kotlin/oppgavestyring/config/db/DbConfig.kt +++ b/app/src/main/kotlin/oppgavestyring/config/db/DatabaseConfiguration.kt @@ -2,7 +2,7 @@ package oppgavestyring.config.db val DB_CONFIG_PREFIX = "DB_OPPGAVESTYRING" -data class DbConfig( +data class DatabaseConfiguration( val connectionURL: String = System.getenv("${DB_CONFIG_PREFIX}_JDBC_URL") ?: System.getProperty("${DB_CONFIG_PREFIX}_JDBC_URL"), val username: String = System.getenv("${DB_CONFIG_PREFIX}_USERNAME") ?: diff --git a/app/src/main/kotlin/oppgavestyring/config/db/DatabaseSingleton.kt b/app/src/main/kotlin/oppgavestyring/config/db/DatabaseManager.kt similarity index 63% rename from app/src/main/kotlin/oppgavestyring/config/db/DatabaseSingleton.kt rename to app/src/main/kotlin/oppgavestyring/config/db/DatabaseManager.kt index a07f0b3..e40f429 100644 --- a/app/src/main/kotlin/oppgavestyring/config/db/DatabaseSingleton.kt +++ b/app/src/main/kotlin/oppgavestyring/config/db/DatabaseManager.kt @@ -6,27 +6,25 @@ import oppgavestyring.LOG import org.jetbrains.exposed.sql.Database import javax.sql.DataSource -object DatabaseSingleton { +class DatabaseManager(databaseConfig: DatabaseConfiguration) { - var connection: DataSource? = null + val connection: DataSource - fun init(config: DbConfig) { + init { LOG.info("Setting up database connection") - if (connection != null) return - - connection = createHikariDataSource(config) - Database.connect(connection!!) + connection = createHikariDataSource(databaseConfig) + Database.connect(connection) LOG.info("Database connection established") + migrate() } fun migrate() { LOG.info("Migrating database") - require(connection != null) {"Database connection is required"} - connection?.let { Flyway.migrate(it) } + Flyway.migrate(connection) LOG.info("Database connection completed") } - private fun createHikariDataSource(dbConfig: DbConfig) = HikariDataSource(HikariConfig().apply { + private fun createHikariDataSource(dbConfig: DatabaseConfiguration) = HikariDataSource(HikariConfig().apply { driverClassName = dbConfig.driver jdbcUrl = dbConfig.connectionURL username = dbConfig.username diff --git a/app/src/main/kotlin/oppgavestyring/config/security/AdGruppe.kt b/app/src/main/kotlin/oppgavestyring/config/security/AdGruppe.kt new file mode 100644 index 0000000..c21b30d --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/config/security/AdGruppe.kt @@ -0,0 +1,14 @@ +package oppgavestyring.config.security + +import java.util.* + +enum class AdGruppe(private val gruppeId: UUID) { + + SAKSBEHANDLER(UUID.fromString("8bb0ee13-49cd-4e75-8c3d-a13420c8b376")), + VEILEDER(UUID.fromString("12353679-aa80-4e59-bb47-95e727bfe85c")), + AVDELINGSLEDER(UUID.fromString("f0f6cad5-e3c0-4308-99a2-3630ac60174a")); + + companion object { + fun valueOf(gruppeId: UUID) = entries.find { gruppeId == it.gruppeId } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/config/security/AzureADAuthentication.kt b/app/src/main/kotlin/oppgavestyring/config/security/AzureADAuthentication.kt new file mode 100644 index 0000000..204e6cd --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/config/security/AzureADAuthentication.kt @@ -0,0 +1,56 @@ +package oppgavestyring.config.security + +import com.auth0.jwk.JwkProviderBuilder +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* +import io.ktor.server.response.* +import no.nav.aap.ktor.client.auth.azure.AzureConfig +import oppgavestyring.SECURE_LOG +import java.net.URI +import java.util.* +import java.util.concurrent.TimeUnit + +val NAV_IDENT_CLAIM_NAME = "NAVident" + +const val AZURE = "azure" +fun Application.authentication(config: AzureConfig) { + + val jwkProvider = JwkProviderBuilder(URI.create(config.jwksUri).toURL()).cached(10, 24, TimeUnit.HOURS) + .rateLimited(10, 1, TimeUnit.MINUTES).build() + + authentication { + jwt(AZURE) { + verifier(jwkProvider, config.issuer) + challenge { _, _ -> + call.respond(HttpStatusCode.Unauthorized, "AzureAD validering feilet") } + validate { cred -> + val now = Date() + SECURE_LOG.info("Ident of requester: ${cred.getClaim(NAV_IDENT_CLAIM_NAME, String::class)}") + SECURE_LOG.info("Groups of requester: ${cred.getListClaim("groups", String::class)}") + if (config.clientId !in cred.audience) { + SECURE_LOG.warn("AzureAD validering feilet (clientId var ikke i audience: ${cred.audience}") + return@validate null + } + + if (cred.expiresAt?.before(now) == true) { + SECURE_LOG.warn("AzureAD validering feilet (expired at: ${cred.expiresAt})") + return@validate null + } + + if (cred.notBefore?.after(now) == true) { + SECURE_LOG.warn("AzureAD validering feilet (not valid yet, valid from: ${cred.notBefore})") + return@validate null + } + + if (cred.issuedAt?.after(cred.expiresAt ?: return@validate null) == true) { + SECURE_LOG.warn("AzureAD validering feilet (issued after expiration: ${cred.issuedAt} )") + return@validate null + } + + OppgavePrincipal.fromJwt(cred) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/config/security/OppgavePrincipal.kt b/app/src/main/kotlin/oppgavestyring/config/security/OppgavePrincipal.kt new file mode 100644 index 0000000..8353096 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/config/security/OppgavePrincipal.kt @@ -0,0 +1,22 @@ +package oppgavestyring.config.security + +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* +import oppgavestyring.intern.oppgave.NavIdent +import java.util.* + +data class OppgavePrincipal( + val ident: NavIdent, + val grupper: List +): Principal { + companion object { + fun fromJwt(jwt: JWTCredential) = OppgavePrincipal( + NavIdent(jwt.getClaim(NAV_IDENT_CLAIM_NAME, String::class) ?: throw IllegalArgumentException("JWT mangler Ident")), + jwt.getListClaim("groups", UUID::class).map { AdGruppe.valueOf(it) }.filterNotNull() + ) + } + + fun isVeileder() = AdGruppe.VEILEDER in grupper || AdGruppe.AVDELINGSLEDER in grupper + fun isSaksbehandler() = AdGruppe.SAKSBEHANDLER in grupper || AdGruppe.AVDELINGSLEDER in grupper + fun isAvdelingsleder() = AdGruppe.AVDELINGSLEDER in grupper +} diff --git a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapter.kt b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapter.kt similarity index 73% rename from app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapter.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapter.kt index 5a3f5b6..ad6ab80 100644 --- a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapter.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapter.kt @@ -1,8 +1,8 @@ -package oppgavestyring.behandlingsflyt +package oppgavestyring.ekstern.behandlingsflyt -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.BehandlingshistorikkRequest -import oppgavestyring.oppgave.OppgaveService +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.BehandlingshistorikkRequest +import oppgavestyring.intern.oppgave.OppgaveService class BehandlingsflytAdapter( @@ -11,7 +11,8 @@ class BehandlingsflytAdapter( fun mapBehnadlingshistorikkTilOppgaveHendelser( - behanlding: BehandlingshistorikkRequest) { + behanlding: BehandlingshistorikkRequest + ) { oppgaveService.lukkOppgaverPåBehandling(behanlding.referanse) diff --git a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytRoutes.kt b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytRoutes.kt similarity index 70% rename from app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytRoutes.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytRoutes.kt index b78e46d..7e27021 100644 --- a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytRoutes.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytRoutes.kt @@ -1,4 +1,4 @@ -package oppgavestyring.behandlingsflyt +package oppgavestyring.ekstern.behandlingsflyt import io.ktor.http.* import io.ktor.server.application.* @@ -6,10 +6,14 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import oppgavestyring.LOG -import oppgavestyring.behandlingsflyt.dto.BehandlingshistorikkRequest +import oppgavestyring.ekstern.behandlingsflyt.dto.BehandlingshistorikkRequest import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.ktor.ext.inject + +fun Route.behandlingsflyt() { + + val behandlingsflytAdapter: BehandlingsflytAdapter by inject() -fun Route.behandlingsflyt(behandlingsflytAdapter: BehandlingsflytAdapter) { route("/behandling") { post { LOG.info("Mottok saksendring på behandling") diff --git a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/behandlingsflyt.json b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/behandlingsflyt.json similarity index 100% rename from app/src/main/kotlin/oppgavestyring/behandlingsflyt/behandlingsflyt.json rename to app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/behandlingsflyt.json diff --git a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/dto/BehandlingshistorikkRequest.kt b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/dto/BehandlingshistorikkRequest.kt similarity index 97% rename from app/src/main/kotlin/oppgavestyring/behandlingsflyt/dto/BehandlingshistorikkRequest.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/dto/BehandlingshistorikkRequest.kt index b0e01ef..f91a683 100644 --- a/app/src/main/kotlin/oppgavestyring/behandlingsflyt/dto/BehandlingshistorikkRequest.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/behandlingsflyt/dto/BehandlingshistorikkRequest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.behandlingsflyt.dto +package oppgavestyring.ekstern.behandlingsflyt.dto import com.fasterxml.jackson.annotation.JsonIgnore import java.time.LocalDateTime @@ -19,7 +19,8 @@ data class BehandlingshistorikkRequest( @JsonIgnore fun getÅpentAvklaringsbehov() = avklaringsbehov.firstOrNull {it.status == Avklaringsbehovstatus.OPPRETTET || - it.status == Avklaringsbehovstatus.SENDT_TILBAKE_FRA_BESLUTTER} + it.status == Avklaringsbehovstatus.SENDT_TILBAKE_FRA_BESLUTTER + } } enum class Behandlingstype{ diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveGateway.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/OppgaveGateway.kt similarity index 74% rename from app/src/main/kotlin/oppgavestyring/oppgave/OppgaveGateway.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/OppgaveGateway.kt index b7b73ba..0b4e6f3 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveGateway.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/OppgaveGateway.kt @@ -1,6 +1,7 @@ -package oppgavestyring.oppgave +package oppgavestyring.ekstern.oppgaveapi -import oppgavestyring.oppgave.adapter.* +import oppgavestyring.ekstern.oppgaveapi.adapter.* +import oppgavestyring.intern.oppgave.OppgaveId interface OppgaveGateway { suspend fun opprett(token: Token, request: OpprettRequest): Result diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveClient.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveClient.kt similarity index 96% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveClient.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveClient.kt index 92f38b9..df0747b 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveClient.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveClient.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.DeserializationFeature @@ -18,8 +18,8 @@ import kotlinx.coroutines.runBlocking import no.nav.aap.ktor.client.auth.azure.AzureAdTokenProvider import oppgavestyring.Config import oppgavestyring.SECURE_LOG -import oppgavestyring.oppgave.OppgaveGateway -import oppgavestyring.oppgave.OppgaveId +import oppgavestyring.ekstern.oppgaveapi.OppgaveGateway +import oppgavestyring.intern.oppgave.OppgaveId import org.slf4j.LoggerFactory import java.util.* @@ -88,7 +88,8 @@ class OppgaveClient(private val config: Config) : OppgaveGateway { override suspend fun endre( token: Token, oppgaveId: OppgaveId, - request: PatchOppgaveRequest): Result { + request: PatchOppgaveRequest + ): Result { val obo = azure.getOnBehalfOfToken(config.oppgave.scope, token.asString()) diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveRequest.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveRequest.kt similarity index 94% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveRequest.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveRequest.kt index bda8219..f7564be 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OppgaveRequest.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OppgaveRequest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter data class OpprettRequest( val oppgavetype: String, // se kodeverk diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OpprettResponse.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OpprettResponse.kt similarity index 95% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/OpprettResponse.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OpprettResponse.kt index 866c589..1963d31 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/OpprettResponse.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/OpprettResponse.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter data class OpprettResponse( val id: Long, diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/PatchOppgaveRequest.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/PatchOppgaveRequest.kt similarity index 74% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/PatchOppgaveRequest.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/PatchOppgaveRequest.kt index f182c63..23a51fa 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/PatchOppgaveRequest.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/PatchOppgaveRequest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter data class PatchOppgaveRequest( val versjon: Long, diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/Prioritet.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Prioritet.kt similarity index 50% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/Prioritet.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Prioritet.kt index a34e729..0a1bd48 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/Prioritet.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Prioritet.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter enum class Prioritet { HOY, diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/Readme.md b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Readme.md similarity index 100% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/Readme.md rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Readme.md diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/Status.kt b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Status.kt similarity index 68% rename from app/src/main/kotlin/oppgavestyring/oppgave/adapter/Status.kt rename to app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Status.kt index e17867e..cb337ce 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/Status.kt +++ b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/Status.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter enum class Status { OPPRETTET, diff --git "a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kOppgaverResponse.kt" "b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kOppgaverResponse.kt" similarity index 68% rename from "app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kOppgaverResponse.kt" rename to "app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kOppgaverResponse.kt" index b110ee1..c0f6e65 100644 --- "a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kOppgaverResponse.kt" +++ "b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kOppgaverResponse.kt" @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter data class SøkOppgaverResponse( val antallTreffTotalt: Long, diff --git "a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kQueryParams.kt" "b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kQueryParams.kt" similarity index 96% rename from "app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kQueryParams.kt" rename to "app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kQueryParams.kt" index 6f20756..beb216b 100644 --- "a/app/src/main/kotlin/oppgavestyring/oppgave/adapter/S\303\270kQueryParams.kt" +++ "b/app/src/main/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/S\303\270kQueryParams.kt" @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter import io.ktor.util.* diff --git a/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringGateway.kt b/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringGateway.kt new file mode 100644 index 0000000..a86421a --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringGateway.kt @@ -0,0 +1,7 @@ +package oppgavestyring.ekstern.tilgangsstyring + +class TilgangstyringGateway { + + //fun filterOppgaver(principal: JWTPrincipal, List) + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringService.kt b/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringService.kt new file mode 100644 index 0000000..7c07f60 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/ekstern/tilgangsstyring/TilgangstyringService.kt @@ -0,0 +1,35 @@ +package oppgavestyring.ekstern.tilgangsstyring + +import oppgavestyring.config.security.OppgavePrincipal +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.intern.oppgave.db.Oppgave + +object TilgangstyringService { + + private val nayOppgaver = listOf( + Avklaringsbehovtype.AVKLAR_STUDENT, + Avklaringsbehovtype.FASTSETT_BEREGNINGSTIDSPUNKT, + Avklaringsbehovtype.VURDER_SYKEPENGEERSTATNING, + Avklaringsbehovtype.FORESLÅ_VEDTAK, + Avklaringsbehovtype.FATTE_VEDTAK + ) + + + // spør tilgangstyring videre på vegne av brukerkall + fun kanSaksbehandlerSeOppgave(oppgave: Oppgave) { + + } + + // spør oppgavestyring med ident ikke fra token, feks ved tildeling av oppgave til andre + fun kanSaksbehandlerSeOppgave(principal: OppgavePrincipal, oppgave: Oppgave): Boolean { + if (principal.isSaksbehandler() && oppgave.avklaringsbehovtype in nayOppgaver) { + return true + } + + if (principal.isVeileder() && oppgave.avklaringsbehovtype !in nayOppgaver) { + return true + } + return false + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/intern/filter/FilterDto.kt b/app/src/main/kotlin/oppgavestyring/intern/filter/FilterDto.kt new file mode 100644 index 0000000..3129d2f --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/filter/FilterDto.kt @@ -0,0 +1,17 @@ +package oppgavestyring.intern.filter + +class FilterDto( + val id: Long, + val tittel: String, + val beskrivelse: String, + val filter: String +) { + companion object { + fun fromBusinessObject(filter: OppgaveFilter) = FilterDto( + id = filter.id.value, + tittel = filter.tittel, + beskrivelse = filter.beskrivelse, + filter = filter.filter + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/intern/filter/FilterRoute.kt b/app/src/main/kotlin/oppgavestyring/intern/filter/FilterRoute.kt new file mode 100644 index 0000000..d68dcae --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/filter/FilterRoute.kt @@ -0,0 +1,51 @@ +package oppgavestyring.intern.filter + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import oppgavestyring.LOG +import oppgavestyring.config.security.OppgavePrincipal +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.transactions.transaction + +fun Route.filter() { + + route("filter") { + get { + val filter = transaction { + OppgaveFilter.all() + .map { FilterDto.fromBusinessObject(it) } + } + call.respond(filter) + } + + post { + val filter = call.receive() + transaction { + OppgaveFilter.new { + tittel = filter.tittel + beskrivelse = filter.beskrivelse + this.filter = filter.filter + opprettetAv = call.principal()!!.ident.toString() + } + } + } + + delete("/{id}") { + val filterId = call.parameters["id"]?.toLong() ?: throw IllegalArgumentException("Filterid mangler") + val principal = call.principal()!! + LOG.info("Bruker: ${principal.ident} sletter filter: $filterId") + + transaction { + OppgaveFilterTable.deleteWhere { OppgaveFilterTable.id eq filterId } + } + + call.respond(HttpStatusCode.OK) + } + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilter.kt b/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilter.kt new file mode 100644 index 0000000..58d2085 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilter.kt @@ -0,0 +1,48 @@ +package oppgavestyring.intern.filter + +import oppgavestyring.intern.oppgave.NavIdent +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.javatime.CurrentDateTime +import org.jetbrains.exposed.sql.javatime.datetime + +class OppgaveFilter(id: EntityID) : LongEntity(id) { + companion object: LongEntityClass(OppgaveFilterTable) + + var tittel by OppgaveFilterTable.tittel + var beskrivelse by OppgaveFilterTable.beskrivelse + var filter by OppgaveFilterTable.filter + val opprettetTid by OppgaveFilterTable.opprettetTid + var opprettetAv by OppgaveFilterTable.opprettetAv + val tildelt by FilterTildelt referrersOn FilterTildeltTable.oppgave + +} + +class FilterTildelt(id: EntityID) : LongEntity(id) { + companion object: LongEntityClass(FilterTildeltTable) + + private var _navIdent by FilterTildeltTable.navIdent + var navIdent: NavIdent + set(value) { _navIdent = value.toString() } + get() = NavIdent(_navIdent) + var hovedFilter by FilterTildeltTable.hovedfilter + val oppgave by FilterTildeltTable.oppgave + +} + +object OppgaveFilterTable: LongIdTable("OPPGAVE_FILTER") { + val tittel = varchar("TITTEL", 50) + val beskrivelse = varchar("BESKRIVELSE", 255) + val filter = text("FILTER_JSON", ) + val opprettetTid = datetime("OPPRETTET_TID").defaultExpression(CurrentDateTime) + val opprettetAv = varchar("OPPRETTET_AV", 7) +} + +object FilterTildeltTable: LongIdTable("FILTER_TILDELT") { + val oppgave = reference("OPPGAVE_FILTER_ID", OppgaveFilterTable) + val navIdent = varchar("NAVIDENT", 7) + val hovedfilter = bool("HOVEDFILTER").default(false) +} + diff --git a/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilterService.kt b/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilterService.kt new file mode 100644 index 0000000..9d4e648 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/filter/OppgaveFilterService.kt @@ -0,0 +1,9 @@ +package oppgavestyring.intern.filter + +class OppgaveFilterService { + + /*fun finnAktivtFilterForBruker(principal: OppgavePrincipal): OppgaveFilter { + val filter = FilterTildelt.find { FilterTildeltTable.navIdent eq principal.ident.asString() } + }*/ + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/NavIdent.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/NavIdent.kt similarity index 77% rename from app/src/main/kotlin/oppgavestyring/oppgave/NavIdent.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/NavIdent.kt index 1c05003..9673506 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/NavIdent.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/NavIdent.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave +package oppgavestyring.intern.oppgave private const val REGEX = "^[A-Å]\\d{6}$" @@ -8,5 +8,5 @@ data class NavIdent(private val navIdent: String) { if (!REGEX.toRegex().matches(navIdent)) throw IllegalArgumentException("Feil format på navIdent: $navIdent. Riktig format er stor bokstav og 6 tall.") } - fun asString(): String = navIdent + override fun toString(): String = navIdent } diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/Oppgave.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/Oppgave.kt similarity index 72% rename from app/src/main/kotlin/oppgavestyring/oppgave/Oppgave.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/Oppgave.kt index b08c337..48db064 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/Oppgave.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/Oppgave.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave +package oppgavestyring.intern.oppgave class Oppgave( private val oppgaveId: OppgaveId, diff --git a/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveId.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveId.kt new file mode 100644 index 0000000..b766d68 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveId.kt @@ -0,0 +1,3 @@ +package oppgavestyring.intern.oppgave + +typealias OppgaveId = Long \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveService.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveService.kt new file mode 100644 index 0000000..0c9e741 --- /dev/null +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/OppgaveService.kt @@ -0,0 +1,104 @@ +package oppgavestyring.intern.oppgave + +import io.ktor.server.plugins.* +import oppgavestyring.config.security.OppgavePrincipal +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovstatus +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.ekstern.tilgangsstyring.TilgangstyringService +import oppgavestyring.intern.oppgave.api.OppgaveParams +import oppgavestyring.intern.oppgave.api.generateOppgaveFilter +import oppgavestyring.intern.oppgave.api.generateOppgaveSorting +import oppgavestyring.intern.oppgave.db.Oppgave +import oppgavestyring.intern.oppgave.db.OppgaveTabell +import oppgavestyring.intern.oppgave.db.Tildelt +import oppgavestyring.intern.oppgave.db.TildeltTabell +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.vendors.ForUpdateOption +import java.time.LocalDateTime + +typealias Behandlingsreferanse = String +typealias Saksnummer = String + +class OppgaveService { + + fun opprett( + personident: String, + saksnummer: Saksnummer, + behandlingsreferanse: Behandlingsreferanse, + behandlingstype: Behandlingstype, + avklaringsbehovtype: Avklaringsbehovtype, + avklaringsbehovOpprettetTidspunkt: LocalDateTime, + behandlingOpprettetTidspunkt: LocalDateTime + ): Oppgave { + return Oppgave.new { + this.saksnummer = saksnummer + this.behandlingsreferanse = behandlingsreferanse + this.behandlingstype = behandlingstype + this.avklaringsbehovtype = avklaringsbehovtype + status = Avklaringsbehovstatus.OPPRETTET + this.avklaringsbehovOpprettetTidspunkt = avklaringsbehovOpprettetTidspunkt + this.behandlingOpprettetTidspunkt = behandlingOpprettetTidspunkt + personnummer = personident + } + } + + fun frigiRessursFraOppgave(id: OppgaveId) { + Oppgave[id].tildelt?.delete() + } + + fun tildelOppgave(id: OppgaveId, navIdent: NavIdent) { + val oppgave = Oppgave[id] + Tildelt.new { + ident = navIdent + this.oppgave = oppgave + } + } + + fun søk(principal: OppgavePrincipal, searchParams: OppgaveParams): List { + val filters = generateOppgaveFilter(searchParams) + + return (OppgaveTabell leftJoin TildeltTabell) + .select(OppgaveTabell.columns) + .where { filters } + .orderBy(*generateOppgaveSorting(searchParams)) + .map { Oppgave.wrapRow(it) } + .filter { TilgangstyringService.kanSaksbehandlerSeOppgave(principal, it) } + } + + + fun hentÅpneOppgaver(principal: OppgavePrincipal): List { + return Oppgave.find { OppgaveTabell.status eq Avklaringsbehovstatus.OPPRETTET } + .filter { TilgangstyringService.kanSaksbehandlerSeOppgave(principal, it) } + } + + fun hent(oppgaveId: OppgaveId): Oppgave { + return Oppgave[oppgaveId] + } + + fun lukkOppgaverPåBehandling(behandlingsreferanse: Behandlingsreferanse) { + Oppgave.find { OppgaveTabell.behandlingsreferanse eq behandlingsreferanse } + .forEach { it.lukkOppgave() } + } + + fun hentNesteOppgave(principal: OppgavePrincipal, searchParams: OppgaveParams): Oppgave { + val oppgaveFilter = generateOppgaveFilter(searchParams) + val oppgaveSortering = generateOppgaveSorting(searchParams) + + val nesteOppgave = (OppgaveTabell leftJoin TildeltTabell) + .select(OppgaveTabell.columns) + .forUpdate(ForUpdateOption.PostgreSQL.ForUpdate(ofTables = arrayOf(OppgaveTabell))) + .where { oppgaveFilter and + (OppgaveTabell.status eq Avklaringsbehovstatus.OPPRETTET and + (TildeltTabell.ident.isNull())) } + .orderBy(*oppgaveSortering) + .map { Oppgave.wrapRow(it) } + .firstOrNull { TilgangstyringService.kanSaksbehandlerSeOppgave(principal, it) } ?: throw NotFoundException("Ingen flere ledige oppgaver") + Tildelt.new { + ident = principal.ident + oppgave = nesteOppgave + } + return nesteOppgave + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/Personident.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/Personident.kt similarity index 73% rename from app/src/main/kotlin/oppgavestyring/oppgave/Personident.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/Personident.kt index 79fe987..696f151 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/Personident.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/Personident.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave +package oppgavestyring.intern.oppgave private const val REGEX = "^\\d{11}$" @@ -9,5 +9,5 @@ data class Personident(private val personident: String) { throw IllegalArgumentException("Personident må bestå av 11 tall") } - fun asString() : String = personident + override fun toString() : String = personident } diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/api/ApiUtils.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/ApiUtils.kt similarity index 77% rename from app/src/main/kotlin/oppgavestyring/oppgave/api/ApiUtils.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/api/ApiUtils.kt index 0c73ee2..08c2afa 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/api/ApiUtils.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/ApiUtils.kt @@ -1,16 +1,24 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api import io.ktor.http.* import io.ktor.util.* -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.Behandlingstype -import oppgavestyring.oppgave.db.OppgaveTabell -import org.jetbrains.exposed.sql.* +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.intern.oppgave.db.OppgaveTabell +import oppgavestyring.intern.oppgave.db.TildeltTabell +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.Op +import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.SqlExpressionBuilder.greaterEq import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList import org.jetbrains.exposed.sql.SqlExpressionBuilder.lessEq +import org.jetbrains.exposed.sql.SqlExpressionBuilder.like +import org.jetbrains.exposed.sql.and import java.time.LocalDateTime import java.time.temporal.ChronoUnit +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set enum class SearchParams { @@ -43,16 +51,14 @@ fun parseSorting(sortings: List) = fun generateOppgaveFilter(searchParams: OppgaveParams) = searchParams.filters.map { filter -> when (filter.key) { + OppgaveDto::foedselsnummer.name -> OppgaveTabell.personnummer like "%${filter.value.first()}%" + OppgaveDto::tilordnetRessurs.name -> TildeltTabell.ident like "%${filter.value.first()}%" OppgaveDto::behandlingstype.name -> OppgaveTabell.behandlingstype .inList(filter.value.map { Behandlingstype.valueOf(it) }) - OppgaveDto::avklaringsbehov.name -> OppgaveTabell.avklaringbehovtype .inList(filter.value.map { Avklaringsbehovtype.valueOf(it) }) - OppgaveDto::avklaringsbehovOpprettetTid.name -> timeWithinRange(OppgaveTabell.avklaringsbehovOpprettetTidspunkt, filter.value.first()) - OppgaveDto::behandlingOpprettetTid.name -> timeWithinRange(OppgaveTabell.behandlingOpprettetTidspunkt, filter.value.first()) - else -> null } }.filterNotNull() @@ -76,6 +82,8 @@ fun getTimerangeFromISOStirng(dateRange: String): List { fun generateOppgaveSorting(searchParams: OppgaveParams) = searchParams.sorting.map { when (it.key) { + OppgaveDto::foedselsnummer.name -> OppgaveTabell.personnummer to it.value + OppgaveDto::tilordnetRessurs.name -> TildeltTabell.ident to it.value OppgaveDto::behandlingstype.name -> OppgaveTabell.behandlingstype to it.value OppgaveDto::avklaringsbehov.name -> OppgaveTabell.avklaringbehovtype to it.value OppgaveDto::avklaringsbehovOpprettetTid.name -> OppgaveTabell.avklaringsbehovOpprettetTidspunkt to it.value diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/api/FrigiOppgaveRequest.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/FrigiOppgaveRequest.kt similarity index 57% rename from app/src/main/kotlin/oppgavestyring/oppgave/api/FrigiOppgaveRequest.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/api/FrigiOppgaveRequest.kt index abbabda..0299b0e 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/api/FrigiOppgaveRequest.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/FrigiOppgaveRequest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api data class FrigiOppgaveRequest( val versjon: Long diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaveRoute.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRoute.kt similarity index 66% rename from app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaveRoute.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRoute.kt index 0310d24..3683986 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaveRoute.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRoute.kt @@ -1,17 +1,22 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import oppgavestyring.LOG -import oppgavestyring.oppgave.NavIdent -import oppgavestyring.oppgave.OppgaveService +import oppgavestyring.config.security.OppgavePrincipal +import oppgavestyring.intern.oppgave.NavIdent +import oppgavestyring.intern.oppgave.OppgaveService import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.ktor.ext.inject -fun Route.oppgaver(oppgaveService: OppgaveService) { +fun Route.oppgaver() { + + val oppgaveService: OppgaveService by inject() route("/oppgaver") { @@ -19,11 +24,13 @@ fun Route.oppgaver(oppgaveService: OppgaveService) { LOG.info("Forsøker å søke opp alle oppgaver tilknyttet AAP") val searchParams = parseUrlFiltering(call.request.queryParameters) + val principal = call.principal()!! + val oppgaver = transaction { val oppgaver = if (!searchParams.isEmpty()) - oppgaveService.søk(searchParams) + oppgaveService.søk(principal, searchParams) else - oppgaveService.hentÅpneOppgaver() + oppgaveService.hentÅpneOppgaver(principal) oppgaver.map { OppgaveDto.fromOppgave(it) } } @@ -45,6 +52,20 @@ fun Route.oppgaver(oppgaveService: OppgaveService) { call.respond(HttpStatusCode.OK, oppgave) } + get("/nesteOppgave") { + val principal = call.principal()!! + LOG.info("Bruker ${principal.ident.toString()} etterspørr neste oppgave") + + val searchParams = parseUrlFiltering(call.request.queryParameters) + + val response = transaction { + val oppgave = oppgaveService.hentNesteOppgave(principal, searchParams) + OppgaveDto.fromOppgave(oppgave) + } + + call.respond(response) + } + patch("/{id}/tildelRessurs") { LOG.info("Forsøker å tildele ressurs til oppgave") @@ -60,7 +81,7 @@ fun Route.oppgaver(oppgaveService: OppgaveService) { ) } - call.respond(HttpStatusCode.OK) + call.respond(HttpStatusCode.NoContent) } patch("/{id}/frigi") { @@ -79,9 +100,11 @@ fun Route.oppgaver(oppgaveService: OppgaveService) { ) } - call.respond(HttpStatusCode.OK) + call.respond(HttpStatusCode.NoContent) } + + } } diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaverResponse.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaverResponse.kt similarity index 75% rename from app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaverResponse.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaverResponse.kt index f6080ad..bd16eca 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/api/OppgaverResponse.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/OppgaverResponse.kt @@ -1,11 +1,11 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovstatus -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.Behandlingstype -import oppgavestyring.oppgave.Behandlingsreferanse -import oppgavestyring.oppgave.db.Oppgave +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovstatus +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.intern.oppgave.Behandlingsreferanse +import oppgavestyring.intern.oppgave.db.Oppgave import java.time.LocalDateTime data class OppgaverResponse( @@ -34,7 +34,7 @@ data class OppgaveDto( saksnummer = oppgave.saksnummer, status = oppgave.status, foedselsnummer = oppgave.personnummer, - tilordnetRessurs = oppgave.tildelt?.ident, + tilordnetRessurs = oppgave.tildelt?.ident?.toString(), avklaringsbehov = oppgave.avklaringsbehovtype, behandlingOpprettetTid = oppgave.behandlingOpprettetTidspunkt, avklaringsbehovOpprettetTid = oppgave.avklaringsbehovOpprettetTidspunkt, diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/api/TildelRessursRequest.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/TildelRessursRequest.kt similarity index 66% rename from app/src/main/kotlin/oppgavestyring/oppgave/api/TildelRessursRequest.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/api/TildelRessursRequest.kt index 6789b77..a1d9dcb 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/api/TildelRessursRequest.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/api/TildelRessursRequest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api data class TildelRessursRequest( val versjon: Long, diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/db/Oppgave.kt b/app/src/main/kotlin/oppgavestyring/intern/oppgave/db/Oppgave.kt similarity index 83% rename from app/src/main/kotlin/oppgavestyring/oppgave/db/Oppgave.kt rename to app/src/main/kotlin/oppgavestyring/intern/oppgave/db/Oppgave.kt index fcb1f34..c7aef1f 100644 --- a/app/src/main/kotlin/oppgavestyring/oppgave/db/Oppgave.kt +++ b/app/src/main/kotlin/oppgavestyring/intern/oppgave/db/Oppgave.kt @@ -1,9 +1,10 @@ -package oppgavestyring.oppgave.db +package oppgavestyring.intern.oppgave.db -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovstatus -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovstatus +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.intern.oppgave.NavIdent import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID @@ -37,7 +38,10 @@ class Oppgave(id: EntityID): LongEntity(id) { class Utfører(id: EntityID): LongEntity(id) { companion object : LongEntityClass(UtførerTabell) - var ident by UtførerTabell.ident + private var _ident by UtførerTabell.ident + var ident: NavIdent + set(ident) { _ident = ident.toString() } + get() = NavIdent(_ident) var tidsstempel by UtførerTabell.tidsstempel var oppgave by Oppgave referencedOn UtførerTabell.oppgave } @@ -45,7 +49,10 @@ class Utfører(id: EntityID): LongEntity(id) { class Tildelt(id: EntityID): LongEntity(id) { companion object : LongEntityClass(TildeltTabell) - var ident by TildeltTabell.ident + private var _ident by TildeltTabell.ident + var ident: NavIdent + set(ident) { _ident = ident.toString()} + get() = NavIdent(_ident) var tidsstempel by TildeltTabell.tidsstempel var oppgave by Oppgave referencedOn TildeltTabell.oppgave } @@ -73,7 +80,6 @@ object UtførerTabell: LongIdTable("UTFORER") { object TildeltTabell: LongIdTable("TILDELT") { val ident = varchar("IDENT", 50) val tidsstempel = timestamp("TIDSSTEMPEL").defaultExpression(CurrentTimestamp) - val oppgave = reference("OPPGAVE_ID", OppgaveTabell) } diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveId.kt b/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveId.kt deleted file mode 100644 index 9a6da6c..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveId.kt +++ /dev/null @@ -1,3 +0,0 @@ -package oppgavestyring.oppgave - -typealias OppgaveId = Long \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveRepository.kt b/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveRepository.kt deleted file mode 100644 index 7a2a3f5..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveRepository.kt +++ /dev/null @@ -1,8 +0,0 @@ -package oppgavestyring.oppgave - -import oppgavestyring.oppgave.adapter.OpprettResponse - -interface OppgaveRepository { - fun lagre(nyOppgave: OpprettResponse) - -} diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveService.kt b/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveService.kt deleted file mode 100644 index 4dcf424..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/OppgaveService.kt +++ /dev/null @@ -1,77 +0,0 @@ -package oppgavestyring.oppgave - -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovstatus -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.Behandlingstype -import oppgavestyring.oppgave.api.OppgaveParams -import oppgavestyring.oppgave.api.generateOppgaveFilter -import oppgavestyring.oppgave.api.generateOppgaveSorting -import oppgavestyring.oppgave.db.Oppgave -import oppgavestyring.oppgave.db.OppgaveTabell -import oppgavestyring.oppgave.db.Tildelt -import org.jetbrains.exposed.sql.SizedIterable -import java.time.LocalDateTime - -typealias Behandlingsreferanse = String -typealias Saksnummer = String - -class OppgaveService { - - fun opprett( - personident: String, - saksnummer: Saksnummer, - behandlingsreferanse: Behandlingsreferanse, - behandlingstype: Behandlingstype, - avklaringsbehovtype: Avklaringsbehovtype, - avklaringsbehovOpprettetTidspunkt: LocalDateTime, - behandlingOpprettetTidspunkt: LocalDateTime - ): Oppgave { - return Oppgave.new { - this.saksnummer = saksnummer - this.behandlingsreferanse = behandlingsreferanse - this.behandlingstype = behandlingstype - this.avklaringsbehovtype = avklaringsbehovtype - status = Avklaringsbehovstatus.OPPRETTET - this.avklaringsbehovOpprettetTidspunkt = avklaringsbehovOpprettetTidspunkt - this.behandlingOpprettetTidspunkt = behandlingOpprettetTidspunkt - personnummer = personident - } - } - - fun frigiRessursFraOppgave(id: OppgaveId) { - Oppgave[id].tildelt?.delete() - } - - fun tildelOppgave(id: OppgaveId, navIdent: NavIdent) { - val oppgave = Oppgave[id] - Tildelt.new { - ident = navIdent.asString() - this.oppgave = oppgave - } - } - - fun søk(searchParams: OppgaveParams): SizedIterable { - val filters = generateOppgaveFilter(searchParams) - - return Oppgave.find { - filters - }.orderBy( - *generateOppgaveSorting(searchParams) - ) - } - - - fun hentÅpneOppgaver(): SizedIterable { - return Oppgave.find { OppgaveTabell.status eq Avklaringsbehovstatus.OPPRETTET } - } - - fun hent(oppgaveId: OppgaveId): Oppgave { - return Oppgave[oppgaveId] - } - - fun lukkOppgaverPåBehandling(behandlingsreferanse: Behandlingsreferanse) { - Oppgave.find { OppgaveTabell.behandlingsreferanse eq behandlingsreferanse } - .forEach { it.lukkOppgave() } - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/Oppgavetype.kt b/app/src/main/kotlin/oppgavestyring/oppgave/Oppgavetype.kt deleted file mode 100644 index 4b3f196..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/Oppgavetype.kt +++ /dev/null @@ -1,9 +0,0 @@ -package oppgavestyring.oppgave - -enum class Oppgavetype(private val kode: String) { - - BEHANDLE_SAK("STARTV"), //TODO: bruker startv grunnet mangel på bedre verdi, burde endres til noe mer passende - AVKLARINGSBEHOV("TODO"); - - fun kode() = kode -} \ No newline at end of file diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/Versjon.kt b/app/src/main/kotlin/oppgavestyring/oppgave/Versjon.kt deleted file mode 100644 index b2e2710..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/Versjon.kt +++ /dev/null @@ -1,5 +0,0 @@ -package oppgavestyring.oppgave - -data class Versjon(private val versjon: Long) { - fun asLong() : Long = versjon -} diff --git a/app/src/main/kotlin/oppgavestyring/oppgave/db/FakeOppgaveRepository.kt b/app/src/main/kotlin/oppgavestyring/oppgave/db/FakeOppgaveRepository.kt deleted file mode 100644 index 723dad7..0000000 --- a/app/src/main/kotlin/oppgavestyring/oppgave/db/FakeOppgaveRepository.kt +++ /dev/null @@ -1,14 +0,0 @@ -package oppgavestyring.oppgave.db - -import oppgavestyring.oppgave.OppgaveRepository -import oppgavestyring.oppgave.adapter.OpprettResponse - -object FakeOppgaveRepository : OppgaveRepository { - - private val map : MutableMap = HashMap() - - override fun lagre(nyOppgave: OpprettResponse) { - map.put(nyOppgave.id, nyOppgave) - } - -} diff --git a/app/src/main/resources/flyway/V1.0__Initial_Oppgave_Database_Modell.sql b/app/src/main/resources/flyway/V1.0__Initial_Oppgave_Database_Modell.sql index a4695cf..5e1f840 100644 --- a/app/src/main/resources/flyway/V1.0__Initial_Oppgave_Database_Modell.sql +++ b/app/src/main/resources/flyway/V1.0__Initial_Oppgave_Database_Modell.sql @@ -31,4 +31,4 @@ CREATE TABLE TILDELT ( CREATE TABLE OPPGAVE_API_REF ( OPPGAVE_ID BIGINT REFERENCES OPPGAVE(ID), OPPGAVE_API_ID BIGINT NOT NULL UNIQUE -) \ No newline at end of file +) diff --git a/app/src/main/resources/flyway/V1.1__Oppgave_filter_table.sql b/app/src/main/resources/flyway/V1.1__Oppgave_filter_table.sql new file mode 100644 index 0000000..963b0d7 --- /dev/null +++ b/app/src/main/resources/flyway/V1.1__Oppgave_filter_table.sql @@ -0,0 +1,17 @@ + + +CREATE TABLE OPPGAVE_FILTER( + ID BIGSERIAL PRIMARY KEY, + TITTEL VARCHAR(50) NOT NULL, + BESKRIVELSE VARCHAR(255) NOT NULL, + FILTER_JSON TEXT NOT NULL, + OPPRETTET_TID TIMESTAMP(3) NOT NULL, + OPPRETTET_AV VARCHAR(7) NOT NULL +); + +CREATE TABLE FILTER_TILDELT( + ID BIGSERIAL PRIMARY KEY, + OPPGAVE_FILTER_ID BIGINT REFERENCES OPPGAVE_FILTER(ID), + NAVIDENT VARCHAR(7) NOT NULL, + HOVEDFILTER BOOLEAN NOT NULL DEFAULT FALSE +); \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/config/db/DatabaseSingletonTest.kt b/app/src/test/kotlin/oppgavestyring/config/db/DatabaseManagerTest.kt similarity index 73% rename from app/src/test/kotlin/oppgavestyring/config/db/DatabaseSingletonTest.kt rename to app/src/test/kotlin/oppgavestyring/config/db/DatabaseManagerTest.kt index 1bcd703..24c9116 100644 --- a/app/src/test/kotlin/oppgavestyring/config/db/DatabaseSingletonTest.kt +++ b/app/src/test/kotlin/oppgavestyring/config/db/DatabaseManagerTest.kt @@ -1,17 +1,16 @@ package oppgavestyring.config.db -import oppgavestyring.TestDatabase +import oppgavestyring.testutils.TestDatabase import org.jetbrains.exposed.sql.Column import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.javatime.timestamp import org.jetbrains.exposed.sql.transactions.transaction -import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.time.Instant @@ -24,21 +23,18 @@ class DatabaseSingletonTest { } } - @BeforeEach + @AfterEach fun beforeEach() { TestDatabase.reset() } - private fun connectToDatabase() { - DatabaseSingleton.init(DbConfig( + val databaseManager = DatabaseManager( + DatabaseConfiguration( connectionURL = TestDatabase.connectionUrl, username = TestDatabase.username, - password = TestDatabase.password))} - - @Test - fun `verify working database connection`() { - connectToDatabase() - } + password = TestDatabase.password + ) + ) @Test fun `verify schema creation form Exposed`() { @@ -49,7 +45,7 @@ class DatabaseSingletonTest { override val primaryKey = PrimaryKey(id, name = "PK_TEST_ID") } - connectToDatabase() + val testTable = TestTable() transaction { @@ -66,10 +62,8 @@ class DatabaseSingletonTest { @Test fun `run flyway migration without any errors`() { - connectToDatabase() - Flyway.migrate(DatabaseSingleton.connection ?: - throw IllegalStateException("Database connection is not initialized")) - println("SDFSDFDF") + TestDatabase.reset() + Flyway.migrate(databaseManager.connection) } } \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingRouteTest.kt b/app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingRouteTest.kt new file mode 100644 index 0000000..2a4b1f7 --- /dev/null +++ b/app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingRouteTest.kt @@ -0,0 +1,115 @@ +package oppgavestyring.ekstern.behandlingsflyt + +import behandlingsflytRequest +import io.ktor.client.request.* +import io.ktor.http.* +import oppgavestyring.config.db.DB_CONFIG_PREFIX +import oppgavestyring.config.db.Flyway +import oppgavestyring.ekstern.behandlingsflyt.dto.* +import oppgavestyring.intern.oppgave.db.Oppgave +import oppgavestyring.intern.oppgave.db.OppgaveTabell +import oppgavestyring.testutils.TestDatabase +import oppgavestyring.testutils.oppgavestyringWithFakes +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction +import org.junit.jupiter.api.* +import java.time.LocalDateTime + +@Nested +class BehandlingRouteTest { + companion object { + @BeforeAll + @JvmStatic + fun beforeAll() { + TestDatabase.start() + Flyway.migrate(TestDatabase.getConnection()) + + System.setProperty("${DB_CONFIG_PREFIX}_JDBC_URL", TestDatabase.connectionUrl) + System.setProperty("${DB_CONFIG_PREFIX}_USERNAME", TestDatabase.username) + System.setProperty("${DB_CONFIG_PREFIX}_PASSWORD", TestDatabase.password) + } + } + + @AfterEach + fun setup() { + TestDatabase.reset() + Flyway.migrate(TestDatabase.getConnection()) + } + + + @Test + fun `opprett oppgave`() { + oppgavestyringWithFakes { _, client -> + val actual = client.post("/behandling") { + contentType(ContentType.Application.Json) + setBody( + behandlingsflytRequest + ) + } + + Assertions.assertEquals(HttpStatusCode.Created, actual.status) + } + } + + @Test + fun `lukk oppgave på samme behandling`() { + oppgavestyringWithFakes { _, client -> + val oppgave = transaction { + Oppgave.new { + saksnummer = "2352345" + behandlingsreferanse = "354636" + personnummer = "12345432543" + status = Avklaringsbehovstatus.OPPRETTET + avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_SYKDOM + behandlingstype = Behandlingstype.Førstegangsbehandling + avklaringsbehovOpprettetTidspunkt = LocalDateTime.now() + behandlingOpprettetTidspunkt = LocalDateTime.now() + this.personnummer = personnummer + } + } + + client.post("/behandling") { + contentType(ContentType.Application.Json) + setBody( + BehandlingshistorikkRequest( + saksnummer = oppgave.saksnummer, + behandlingType = oppgave.behandlingstype, + status = Behandlingstatus.OPPRETTET, + personident = oppgave.personnummer, + avklaringsbehov = listOf( + AvklaringsbehovDto( + definisjon = Definisjon(Avklaringsbehovtype.FATTE_VEDTAK.kode), + status = Avklaringsbehovstatus.OPPRETTET, + endringer = listOf( + AvklaringsbehovhendelseEndring( + status = Avklaringsbehovstatus.OPPRETTET, + endretAv = "yolo", + tidsstempel = LocalDateTime.now() + ) + ) + ) + ), + opprettetTidspunkt = LocalDateTime.now(), + referanse = oppgave.behandlingsreferanse + + ) + ) + } + + transaction { + oppgave.refresh() + val nyOppgave = Oppgave.find { + (OppgaveTabell.saksnummer eq oppgave.saksnummer) and + (OppgaveTabell.avklaringbehovtype eq Avklaringsbehovtype.FATTE_VEDTAK) and + (OppgaveTabell.status eq Avklaringsbehovstatus.OPPRETTET) + } + + org.assertj.core.api.Assertions.assertThat(oppgave.status).isEqualTo(Avklaringsbehovstatus.AVSLUTTET) + org.assertj.core.api.Assertions.assertThat(nyOppgave).isNotNull + } + } + + + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapterTest.kt b/app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapterTest.kt similarity index 93% rename from app/src/test/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapterTest.kt rename to app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapterTest.kt index 7a26044..fc3e646 100644 --- a/app/src/test/kotlin/oppgavestyring/behandlingsflyt/BehandlingsflytAdapterTest.kt +++ b/app/src/test/kotlin/oppgavestyring/ekstern/behandlingsflyt/BehandlingsflytAdapterTest.kt @@ -1,12 +1,12 @@ -package oppgavestyring.behandlingsflyt +package oppgavestyring.ekstern.behandlingsflyt import io.mockk.every import io.mockk.justRun import io.mockk.mockk import io.mockk.verify -import oppgavestyring.behandlingsflyt.dto.* -import oppgavestyring.oppgave.OppgaveService -import oppgavestyring.oppgave.db.Oppgave +import oppgavestyring.ekstern.behandlingsflyt.dto.* +import oppgavestyring.intern.oppgave.OppgaveService +import oppgavestyring.intern.oppgave.db.Oppgave import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.time.LocalDateTime diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/adapter/FakeOppgaveClient.kt b/app/src/test/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/FakeOppgaveClient.kt similarity index 88% rename from app/src/test/kotlin/oppgavestyring/oppgave/adapter/FakeOppgaveClient.kt rename to app/src/test/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/FakeOppgaveClient.kt index 4827dbf..770c2a8 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/adapter/FakeOppgaveClient.kt +++ b/app/src/test/kotlin/oppgavestyring/ekstern/oppgaveapi/adapter/FakeOppgaveClient.kt @@ -1,7 +1,7 @@ -package oppgavestyring.oppgave.adapter +package oppgavestyring.ekstern.oppgaveapi.adapter -import oppgavestyring.oppgave.OppgaveGateway -import oppgavestyring.oppgave.OppgaveId +import oppgavestyring.ekstern.oppgaveapi.OppgaveGateway +import oppgavestyring.intern.oppgave.OppgaveId class FakeOppgaveClient : OppgaveGateway { diff --git a/app/src/test/kotlin/oppgavestyring/fakes/AzureFake.kt b/app/src/test/kotlin/oppgavestyring/fakes/AzureFake.kt deleted file mode 100644 index 1f63c69..0000000 --- a/app/src/test/kotlin/oppgavestyring/fakes/AzureFake.kt +++ /dev/null @@ -1,36 +0,0 @@ -package oppgavestyring.fakes - -import io.ktor.http.* -import io.ktor.serialization.jackson.* -import io.ktor.server.application.* -import io.ktor.server.engine.* -import io.ktor.server.netty.* -import io.ktor.server.plugins.contentnegotiation.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import oppgavestyring.port - -class AzureFake : AutoCloseable { - private val server = embeddedServer(Netty, port = 0, module = Application::azure).apply { start() } - val port: Int get() = server.port() - override fun close() = server.stop(0, 0) -} - -private fun Application.azure() { - install(ContentNegotiation) { - jackson {} - } - - routing { - post("/token") { - call.respondText(contentType = ContentType.Application.Json) { - """ - { - "exprires_in" : 3600, - "access_token": "very.secure.token" - } - """.trimMargin() - } - } - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/intern/filter/FilterRouteApiTest.kt b/app/src/test/kotlin/oppgavestyring/intern/filter/FilterRouteApiTest.kt new file mode 100644 index 0000000..dd072a7 --- /dev/null +++ b/app/src/test/kotlin/oppgavestyring/intern/filter/FilterRouteApiTest.kt @@ -0,0 +1,109 @@ +package oppgavestyring.intern.filter + +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.http.* +import oppgavestyring.config.db.DB_CONFIG_PREFIX +import oppgavestyring.config.db.Flyway +import oppgavestyring.testutils.TestDatabase +import oppgavestyring.testutils.oppgavestyringWithFakes +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.transaction +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test + +class FilterRouteApiTest { + companion object { + @BeforeAll + @JvmStatic + fun beforeAll() { + TestDatabase.start() + Flyway.migrate(TestDatabase.getConnection()) + + System.setProperty("${DB_CONFIG_PREFIX}_JDBC_URL", TestDatabase.connectionUrl) + System.setProperty("${DB_CONFIG_PREFIX}_USERNAME", TestDatabase.username) + System.setProperty("${DB_CONFIG_PREFIX}_PASSWORD", TestDatabase.password) + } + } + + @AfterEach + fun setup() { + TestDatabase.reset() + Flyway.migrate(TestDatabase.getConnection()) + } + + @Test + fun `create oppgavefilter`() { + oppgavestyringWithFakes { _, client -> + val filterDto = FilterDto( + 1, + "Oppgave", + "Dette er en oppgave", + """{"hello": "world"}""" + ) + + client.post("/filter") { + contentType(ContentType.Application.Json) + setBody(filterDto) + } + } + val filter = transaction { + OppgaveFilter.all().firstOrNull() + } + + assertThat(filter).isNotNull + } + + @Test + fun `fetch oppgavefilter`() { + + val expected = FilterDto( + 1, + "Oppgave", + "Dette er en oppgave", + """{"hello": "world"}""" + ) + transaction { + OppgaveFilter.new { + tittel = expected.tittel + beskrivelse = expected.beskrivelse + filter = expected.filter + opprettetAv = "K112233" + } + } + + oppgavestyringWithFakes { _, client -> + val actual = client.get("/filter") { + accept(ContentType.Application.Json) + }.body>() + + assertThat(actual.first()) + .usingRecursiveComparison() + .isEqualTo(expected) + } + + } + + @Test + fun `slett oppgavefilter`() { + val filterId = transaction { + OppgaveFilter.new { + tittel = "Test" + beskrivelse = "Testbeskrivelse" + filter = "{}" + opprettetAv = "K112233" + }.id.value + } + + oppgavestyringWithFakes { _, client -> + client.delete("/filter/$filterId") + } + + transaction { + val actual = OppgaveFilter.findById(filterId) + assertThat(actual).isNull() + } + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/NavIdentTest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/NavIdentTest.kt similarity index 94% rename from app/src/test/kotlin/oppgavestyring/oppgave/NavIdentTest.kt rename to app/src/test/kotlin/oppgavestyring/intern/oppgave/NavIdentTest.kt index 86dc740..36efee3 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/NavIdentTest.kt +++ b/app/src/test/kotlin/oppgavestyring/intern/oppgave/NavIdentTest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave +package oppgavestyring.intern.oppgave import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -28,7 +28,7 @@ class NavIdentTest { @Test fun `navIdent må bestå av en bokstav og 6 tall`() { val navIdent = NavIdent("D113442") - assertThat(navIdent.asString()).isEqualTo("D113442") + assertThat(navIdent.toString()).isEqualTo("D113442") } @Test diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/OppgaveTabellServiceTest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/OppgaveTabellServiceTest.kt similarity index 50% rename from app/src/test/kotlin/oppgavestyring/oppgave/OppgaveTabellServiceTest.kt rename to app/src/test/kotlin/oppgavestyring/intern/oppgave/OppgaveTabellServiceTest.kt index a0ed44e..175db54 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/OppgaveTabellServiceTest.kt +++ b/app/src/test/kotlin/oppgavestyring/intern/oppgave/OppgaveTabellServiceTest.kt @@ -1,4 +1,4 @@ -package oppgavestyring.oppgave +package oppgavestyring.intern.oppgave class OppgaveTabellServiceTest { diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiUtilsKtTest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/ApiUtilsTest.kt similarity index 95% rename from app/src/test/kotlin/oppgavestyring/oppgave/api/ApiUtilsKtTest.kt rename to app/src/test/kotlin/oppgavestyring/intern/oppgave/api/ApiUtilsTest.kt index c57f107..5af999c 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiUtilsKtTest.kt +++ b/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/ApiUtilsTest.kt @@ -1,13 +1,13 @@ -package oppgavestyring.oppgave.api +package oppgavestyring.intern.oppgave.api import io.ktor.http.* -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype import org.assertj.core.api.Assertions import org.jetbrains.exposed.sql.SortOrder import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -class ApiUtilsKtTest{ +class ApiUtilsTest{ @Nested inner class Sorting { diff --git a/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRouteTest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRouteTest.kt new file mode 100644 index 0000000..d0fdc32 --- /dev/null +++ b/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/OppgaveRouteTest.kt @@ -0,0 +1,393 @@ +package oppgavestyring.intern.oppgave.api + +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.http.* +import oppgavestyring.config.db.DB_CONFIG_PREFIX +import oppgavestyring.config.db.Flyway +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovstatus +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.intern.oppgave.NavIdent +import oppgavestyring.intern.oppgave.db.Oppgave +import oppgavestyring.intern.oppgave.db.Tildelt +import oppgavestyring.testutils.TestDatabase +import oppgavestyring.testutils.oppgavestyringWithFakes +import org.assertj.core.api.Assertions +import org.jetbrains.exposed.sql.transactions.transaction +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import java.time.LocalDateTime +import java.time.temporal.ChronoUnit + +@Nested +class OppgaveRouteTest { + companion object { + @BeforeAll + @JvmStatic + fun beforeAll() { + TestDatabase.start() + Flyway.migrate(TestDatabase.getConnection()) + + System.setProperty("${DB_CONFIG_PREFIX}_JDBC_URL", TestDatabase.connectionUrl) + System.setProperty("${DB_CONFIG_PREFIX}_USERNAME", TestDatabase.username) + System.setProperty("${DB_CONFIG_PREFIX}_PASSWORD", TestDatabase.password) + } + } + + @AfterEach + fun setup() { + TestDatabase.reset() + Flyway.migrate(TestDatabase.getConnection()) + } + + + fun genererOppgave() = Oppgave.new { + saksnummer = "2352345" + behandlingsreferanse = "23642" + personnummer = "12345432543" + status = Avklaringsbehovstatus.OPPRETTET + avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_SYKDOM + behandlingstype = Behandlingstype.Førstegangsbehandling + avklaringsbehovOpprettetTidspunkt = + LocalDateTime.of(2020, 1, 1, 1, 1, 1, 222).truncatedTo(ChronoUnit.MILLIS) + behandlingOpprettetTidspunkt = LocalDateTime.of(2021, 1, 1, 1, 1, 1, 222).truncatedTo(ChronoUnit.MILLIS) + this.personnummer = personnummer + } + + @Test + fun `hent oppgave`() { + oppgavestyringWithFakes { fakes, client -> + + val oppgave = transaction { + genererOppgave() + } + + val actual = client.get("/oppgaver/${oppgave.id.value}") { + accept(ContentType.Application.Json) + }.body() + + val expected = OppgaveDto( + oppgaveId = oppgave.id.value, + saksnummer = "2352345", + behandlingsreferanse = "23642", + behandlingstype = Behandlingstype.Førstegangsbehandling, + avklaringsbehov = Avklaringsbehovtype.AVKLAR_SYKDOM, + status = Avklaringsbehovstatus.OPPRETTET, + foedselsnummer = oppgave.personnummer, + avklaringsbehovOpprettetTid = oppgave.avklaringsbehovOpprettetTidspunkt, + behandlingOpprettetTid = oppgave.behandlingOpprettetTidspunkt, + oppgaveOpprettet = LocalDateTime.now() + ) + + Assertions.assertThat(actual) + .usingRecursiveComparison() + .ignoringFieldsMatchingRegexes("oppgaveOpprettet") + .isEqualTo(expected) + } + } + + @Test + fun `hent alle oppgaver, verifiser at bare åpne oppgaver blir hentet`() { + oppgavestyringWithFakes { fakes, client -> + val åpenOppgaveId = transaction { + genererOppgave().lukkOppgave() + genererOppgave().id.value + } + + val actual = client.get("/oppgaver") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isOne() + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(åpenOppgaveId) + } + } + + @Test + fun `hent alle oppgaver med sortering på $property`() { + val sorteringsParameter = "?sortering=behandlingOpprettetTid=desc" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + genererOppgave().behandlingOpprettetTidspunkt = LocalDateTime.of(2020, 10, 1, 10, 10, 10) + val førsteOppgave = genererOppgave() + førsteOppgave.behandlingOpprettetTidspunkt = LocalDateTime.of(2020, 10, 1, 10, 10, 11) + førsteOppgave.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(2) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med sortering på tildelt`() { + val sorteringsParameter = "?sortering=tilordnetRessurs=desc" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + + val oppgave1 = genererOppgave() + val oppgave2 = genererOppgave() + Tildelt.new { + ident = NavIdent("K123456") + oppgave = oppgave1 + } + Tildelt.new { + ident = NavIdent("A111111") + oppgave = oppgave2 + } + + oppgave1.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(2) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med filtrering på property`() { + val sorteringsParameter = "?filtrering=avklaringsbehov=AVKLAR_SYKDOM" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_BISTANDSBEHOV + genererOppgave().id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(1) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med filtrering på foedselsnummer`() { + val sorteringsParameter = "?filtrering=foedselsnummer=101010" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + val oppgave1 = genererOppgave() + oppgave1.personnummer = "10101012345" + genererOppgave() + oppgave1.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(1) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med filtrering på relasjonsverdi`() { + val sorteringsParameter = "?filtrering=tilordnetRessurs=K101010" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + val oppgave1 = genererOppgave() + Tildelt.new { + ident = NavIdent("K101010") + oppgave = oppgave1 + } + genererOppgave() + oppgave1.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(1) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med filtrering på enkelt dato`() { + val filterTime = LocalDateTime.of(2020, 10, 10, 10, 10, 10, 11111) + val urlTime = filterTime.truncatedTo(ChronoUnit.DAYS) + + val sorteringsParameter = "?filtrering=behandlingOpprettetTid%3D${urlTime.minusDays(3)}%2F${urlTime.plusDays(3)}" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + genererOppgave() + val oppgave = genererOppgave() + oppgave.behandlingOpprettetTidspunkt = filterTime + oppgave.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(1) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + @Test + fun `hent alle oppgaver med filtrering på fra til dato`() { + val filterTime = LocalDateTime.of(2020, 10, 10, 10, 10, 10, 11111) + + val sorteringsParameter = "?filtrering=behandlingOpprettetTid%3D${filterTime.truncatedTo(ChronoUnit.DAYS)}" + + oppgavestyringWithFakes { fakes, client -> + val førsteOppgave = transaction { + genererOppgave() + val oppgave = genererOppgave() + oppgave.behandlingOpprettetTidspunkt = filterTime + oppgave.id.value + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(1) + + Assertions.assertThat(actual.oppgaver.first().oppgaveId) + .isEqualTo(førsteOppgave) + } + } + + + @Test + fun `hent alle oppgaver med filtrering på flere verdier av samme property`() { + val sorteringsParameter = "?filtrering=avklaringsbehov%3DFASTSETT_ARBEIDSEVNE%26avklaringsbehov%3DAVKLAR_BISTANDSBEHOV" + + oppgavestyringWithFakes { fakes, client -> + transaction { + genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.FASTSETT_ARBEIDSEVNE + genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_BISTANDSBEHOV + genererOppgave() + } + + val actual = client.get("/oppgaver$sorteringsParameter") { + accept(ContentType.Application.Json) + contentType(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual.oppgaver.size) + .isEqualTo(2) + + Assertions.assertThat(actual.oppgaver.map { it.avklaringsbehov }) + .doesNotContain(Avklaringsbehovtype.AVKLAR_SYKDOM) + } + } + + @Test + fun `tildelOppgave`() { + oppgavestyringWithFakes { fakes, client -> + val oppgaveId = transaction { + genererOppgave().id.value + } + + val actual = client.patch("/oppgaver/$oppgaveId/tildelRessurs") { + contentType(ContentType.Application.Json) + setBody( + TildelRessursRequest( + navIdent = "T123456", + versjon = 12 + ) + ) + } + + Assertions.assertThat(actual.status) + .isEqualTo(HttpStatusCode.NoContent) + } + } + + @Test + fun `frigi oppgave fjerner tildeling fra oppgave`() { + oppgavestyringWithFakes { fakes, client -> + val oppgaveId = transaction { + val oppgave = genererOppgave() + Tildelt.new { + ident = NavIdent("T123456") + this.oppgave = oppgave + } + oppgave.id.value + } + + client.patch("/oppgaver/$oppgaveId/frigi") { + } + + transaction { + Assertions.assertThat(Oppgave[oppgaveId].tildelt).isNull() + } + } + } + + @Test + fun `hent neste oppgave`() { + oppgavestyringWithFakes { fakes, client -> + val oppgaveId = transaction { + val tildeltOppgave = genererOppgave() + Tildelt.new { + ident = NavIdent("T123456") + this.oppgave = tildeltOppgave + } + genererOppgave().status = Avklaringsbehovstatus.AVSLUTTET + genererOppgave().id.value + } + + val actual = client.get("/oppgaver/nesteOppgave") { + accept(ContentType.Application.Json) + }.body() + + Assertions.assertThat(actual).isNotNull() + Assertions.assertThat(actual.oppgaveId).isEqualTo(oppgaveId) + Assertions.assertThat(actual.tilordnetRessurs).isNotNull() + } + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/api/behandlingsflytRequest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/api/behandlingsflytRequest.kt similarity index 100% rename from app/src/test/kotlin/oppgavestyring/oppgave/api/behandlingsflytRequest.kt rename to app/src/test/kotlin/oppgavestyring/intern/oppgave/api/behandlingsflytRequest.kt diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/db/OppgaveDtoTabellDaoTest.kt b/app/src/test/kotlin/oppgavestyring/intern/oppgave/db/OppgaveDtoTabellDaoTest.kt similarity index 79% rename from app/src/test/kotlin/oppgavestyring/oppgave/db/OppgaveDtoTabellDaoTest.kt rename to app/src/test/kotlin/oppgavestyring/intern/oppgave/db/OppgaveDtoTabellDaoTest.kt index 393ebca..bcd5a34 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/db/OppgaveDtoTabellDaoTest.kt +++ b/app/src/test/kotlin/oppgavestyring/intern/oppgave/db/OppgaveDtoTabellDaoTest.kt @@ -1,17 +1,17 @@ -package oppgavestyring.oppgave.db +package oppgavestyring.intern.oppgave.db -import oppgavestyring.TestDatabase -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovstatus -import oppgavestyring.behandlingsflyt.dto.Avklaringsbehovtype -import oppgavestyring.behandlingsflyt.dto.Behandlingstype import oppgavestyring.config.db.Flyway +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovstatus +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.behandlingsflyt.dto.Behandlingstype +import oppgavestyring.intern.oppgave.NavIdent +import oppgavestyring.testutils.TestDatabase import org.jetbrains.exposed.sql.transactions.transaction +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.time.LocalDateTime -import java.util.* import kotlin.test.assertEquals @@ -35,10 +35,11 @@ class OppgaveDtoTabellDaoTest { @JvmStatic fun beforeAll() { TestDatabase.start() + TestDatabase.getConnection() } } - @BeforeEach + @AfterEach fun setup() { TestDatabase.reset() Flyway.migrate(TestDatabase.getConnection()) @@ -60,7 +61,7 @@ class OppgaveDtoTabellDaoTest { val opprettetOppgave = generateOppgave() Utfører.new { - ident = UUID.randomUUID().toString() + ident = NavIdent("R123456") oppgave = opprettetOppgave } @@ -71,7 +72,7 @@ class OppgaveDtoTabellDaoTest { @Test fun `forventer å kunne tildele oppgave til person`() { - val ident = "YOLO" + val ident = NavIdent("K123456") transaction { val opprettetOppgave = generateOppgave() diff --git a/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiTest.kt b/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiTest.kt index a168e36..e69de29 100644 --- a/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiTest.kt +++ b/app/src/test/kotlin/oppgavestyring/oppgave/api/ApiTest.kt @@ -1,370 +0,0 @@ -package oppgavestyring.oppgave.api - -import behandlingsflytRequest -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.http.* -import io.ktor.server.util.* -import oppgavestyring.TestDatabase -import oppgavestyring.behandlingsflyt.dto.* -import oppgavestyring.config.db.DB_CONFIG_PREFIX -import oppgavestyring.config.db.Flyway -import oppgavestyring.oppgave.db.Oppgave -import oppgavestyring.oppgave.db.OppgaveTabell -import oppgavestyring.oppgave.db.Tildelt -import oppgavestyring.oppgavestyringWithFakes -import org.assertj.core.api.Assertions.assertThat -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.transactions.transaction -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import java.time.LocalDateTime -import java.time.temporal.ChronoUnit - -class ApiTest { - companion object { - @BeforeAll - @JvmStatic - fun beforeAll() { - TestDatabase.start() - Flyway.migrate(TestDatabase.getConnection()) - - System.setProperty("${DB_CONFIG_PREFIX}_JDBC_URL", TestDatabase.connectionUrl) - System.setProperty("${DB_CONFIG_PREFIX}_USERNAME", TestDatabase.username) - System.setProperty("${DB_CONFIG_PREFIX}_PASSWORD", TestDatabase.password) - } - } - - @BeforeEach - fun setup() { - TestDatabase.reset() - Flyway.migrate(TestDatabase.getConnection()) - } - - @Nested - inner class `behandling route` { - - @Test - fun `opprett oppgave`() { - oppgavestyringWithFakes { _, client -> - val actual = client.post("/behandling") { - contentType(ContentType.Application.Json) - setBody( - behandlingsflytRequest - ) - } - - assertEquals(HttpStatusCode.Created, actual.status) - } - } - - - @Test - fun `lukk oppgave på samme behandling`() { - oppgavestyringWithFakes { _, client -> - val oppgave = transaction { - Oppgave.new { - saksnummer = "2352345" - behandlingsreferanse = "354636" - personnummer = "12345432543" - status = Avklaringsbehovstatus.OPPRETTET - avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_SYKDOM - behandlingstype = Behandlingstype.Førstegangsbehandling - avklaringsbehovOpprettetTidspunkt = LocalDateTime.now() - behandlingOpprettetTidspunkt = LocalDateTime.now() - this.personnummer = personnummer - } - } - - client.post("/behandling") { - contentType(ContentType.Application.Json) - setBody( - BehandlingshistorikkRequest( - saksnummer = oppgave.saksnummer, - behandlingType = oppgave.behandlingstype, - status = Behandlingstatus.OPPRETTET, - personident = oppgave.personnummer, - avklaringsbehov = listOf( - AvklaringsbehovDto( - definisjon = Definisjon(Avklaringsbehovtype.FATTE_VEDTAK.kode), - status = Avklaringsbehovstatus.OPPRETTET, - endringer = listOf( - AvklaringsbehovhendelseEndring( - status = Avklaringsbehovstatus.OPPRETTET, - endretAv = "yolo", - tidsstempel = LocalDateTime.now() - ) - ) - ) - ), - opprettetTidspunkt = LocalDateTime.now(), - referanse = oppgave.behandlingsreferanse - - ) - ) - } - - transaction { - oppgave.refresh() - val nyOppgave = Oppgave.find { (OppgaveTabell.saksnummer eq oppgave.saksnummer) and - (OppgaveTabell.avklaringbehovtype eq Avklaringsbehovtype.FATTE_VEDTAK) and - (OppgaveTabell.status eq Avklaringsbehovstatus.OPPRETTET) - } - - assertThat(oppgave.status).isEqualTo(Avklaringsbehovstatus.AVSLUTTET) - assertThat(nyOppgave).isNotNull - } - } - - - } - - } - - - @Nested - inner class `oppgave route` { - - fun genererOppgave() = Oppgave.new { - saksnummer = "2352345" - behandlingsreferanse = "23642" - personnummer = "12345432543" - status = Avklaringsbehovstatus.OPPRETTET - avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_SYKDOM - behandlingstype = Behandlingstype.Førstegangsbehandling - avklaringsbehovOpprettetTidspunkt = - LocalDateTime.of(2020, 1, 1, 1, 1, 1, 222).truncatedTo(ChronoUnit.MILLIS) - behandlingOpprettetTidspunkt = LocalDateTime.of(2021, 1, 1, 1, 1, 1, 222).truncatedTo(ChronoUnit.MILLIS) - this.personnummer = personnummer - } - - @Test - fun `hent oppgave`() { - oppgavestyringWithFakes { fakes, client -> - - val oppgave = transaction { - genererOppgave() - } - - val actual = client.get("/oppgaver/${oppgave.id.value}") { - accept(ContentType.Application.Json) - }.body() - - val expected = OppgaveDto( - oppgaveId = oppgave.id.value, - saksnummer = "2352345", - behandlingsreferanse = "23642", - behandlingstype = Behandlingstype.Førstegangsbehandling, - avklaringsbehov = Avklaringsbehovtype.AVKLAR_SYKDOM, - status = Avklaringsbehovstatus.OPPRETTET, - foedselsnummer = oppgave.personnummer, - avklaringsbehovOpprettetTid = oppgave.avklaringsbehovOpprettetTidspunkt, - behandlingOpprettetTid = oppgave.behandlingOpprettetTidspunkt, - oppgaveOpprettet = LocalDateTime.now() - ) - - assertThat(actual) - .usingRecursiveComparison() - .ignoringFieldsMatchingRegexes("oppgaveOpprettet") - .isEqualTo(expected) - } - } - - @Test - fun `hent alle oppgaver, verifiser at bare åpne oppgaver blir hentet`() { - oppgavestyringWithFakes{fakes, client -> - val åpenOppgaveId = transaction { - genererOppgave().lukkOppgave() - genererOppgave().id.value - } - - val actual = client.get("/oppgaver") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isOne() - - assertThat(actual.oppgaver.first().oppgaveId) - .isEqualTo(åpenOppgaveId) - } - } - - @Test - fun `hent alle oppgaver med sortering på $property`() { - val sorteringsParameter = "?sortering=behandlingOpprettetTid=desc" - - oppgavestyringWithFakes{fakes, client -> - val førsteOppgave = transaction { - genererOppgave().behandlingOpprettetTidspunkt = LocalDateTime.of(2020, 10, 1, 10, 10, 10) - val førsteOppgave = genererOppgave() - førsteOppgave.behandlingOpprettetTidspunkt = LocalDateTime.of(2020, 10, 1, 10, 10, 11) - førsteOppgave.id.value - } - - val actual = client.get("/oppgaver$sorteringsParameter") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isEqualTo(2) - - assertThat(actual.oppgaver.first().oppgaveId) - .isEqualTo(førsteOppgave) - } - } - - @Test - fun `hent alle oppgaver med filtrering på property`() { - val sorteringsParameter = "?filtrering=avklaringsbehov=AVKLAR_SYKDOM" - - oppgavestyringWithFakes{fakes, client -> - val førsteOppgave = transaction { - genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_STUDENT - genererOppgave().id.value - } - - val actual = client.get("/oppgaver$sorteringsParameter") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isEqualTo(1) - - assertThat(actual.oppgaver.first().oppgaveId) - .isEqualTo(førsteOppgave) - } - } - - @Test - fun `hent alle oppgaver med filtrering på enkelt dato`() { - val filterTime = LocalDateTime.of(2020, 10, 10, 10, 10, 10, 11111) - val urlTime = filterTime.truncatedTo(ChronoUnit.DAYS) - - val sorteringsParameter = "?filtrering=behandlingOpprettetTid%3D${urlTime.minusDays(3)}%2F${urlTime.plusDays(3)}" - - oppgavestyringWithFakes{fakes, client -> - val førsteOppgave = transaction { - genererOppgave() - val oppgave = genererOppgave() - oppgave.behandlingOpprettetTidspunkt = filterTime - oppgave.id.value - } - - val actual = client.get("/oppgaver$sorteringsParameter") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isEqualTo(1) - - assertThat(actual.oppgaver.first().oppgaveId) - .isEqualTo(førsteOppgave) - } - } - - @Test - fun `hent alle oppgaver med filtrering på fra til dato`() { - val filterTime = LocalDateTime.of(2020, 10, 10, 10, 10, 10, 11111) - - val sorteringsParameter = "?filtrering=behandlingOpprettetTid%3D${filterTime.truncatedTo(ChronoUnit.DAYS)}" - - oppgavestyringWithFakes{fakes, client -> - val førsteOppgave = transaction { - genererOppgave() - val oppgave = genererOppgave() - oppgave.behandlingOpprettetTidspunkt = filterTime - oppgave.id.value - } - - val actual = client.get("/oppgaver$sorteringsParameter") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isEqualTo(1) - - assertThat(actual.oppgaver.first().oppgaveId) - .isEqualTo(førsteOppgave) - } - } - - - @Test - fun `hent alle oppgaver med filtrering på flere verdier av samme property`() { - val sorteringsParameter = "?filtrering=avklaringsbehov%3DAVKLAR_STUDENT%26avklaringsbehov%3DAVKLAR_BISTANDSBEHOV" - - oppgavestyringWithFakes{fakes, client -> - transaction { - genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_STUDENT - genererOppgave().avklaringsbehovtype = Avklaringsbehovtype.AVKLAR_BISTANDSBEHOV - genererOppgave() - } - - val actual = client.get("/oppgaver$sorteringsParameter") { - accept(ContentType.Application.Json) - contentType(ContentType.Application.Json) - }.body() - - assertThat(actual.oppgaver.size) - .isEqualTo(2) - - assertThat(actual.oppgaver.map { it.avklaringsbehov }) - .doesNotContain(Avklaringsbehovtype.AVKLAR_SYKDOM) - } - } - - @Test - fun `tildelOppgave`() { - oppgavestyringWithFakes { fakes, client -> - val oppgaveId = transaction { - genererOppgave().id.value - } - - val actual = client.patch("/oppgaver/$oppgaveId/tildelRessurs") { - bearerAuth("token") - contentType(ContentType.Application.Json) - setBody( - TildelRessursRequest( - navIdent = "T123456", - versjon = 12 - ) - ) - } - - assertThat(actual.status) - .isEqualTo(HttpStatusCode.OK) - } - } - - @Test - fun `frigi oppgave fjerner tildeling fra oppgave`() { - oppgavestyringWithFakes { fakes, client -> - val oppgaveId = transaction { - val oppgave = genererOppgave() - Tildelt.new { - ident = "T123456" - this.oppgave = oppgave - } - oppgave.id.value - } - - client.patch("/oppgaver/$oppgaveId/frigi") { - bearerAuth("token") - } - - transaction { - assertThat(Oppgave[oppgaveId].tildelt).isNull() - } - } - } - } -} diff --git a/app/src/test/kotlin/oppgavestyring/TestUtils.kt b/app/src/test/kotlin/oppgavestyring/testutils/TestUtils.kt similarity index 68% rename from app/src/test/kotlin/oppgavestyring/TestUtils.kt rename to app/src/test/kotlin/oppgavestyring/testutils/TestUtils.kt index f6d8602..c9a8887 100644 --- a/app/src/test/kotlin/oppgavestyring/TestUtils.kt +++ b/app/src/test/kotlin/oppgavestyring/testutils/TestUtils.kt @@ -1,21 +1,25 @@ -package oppgavestyring +package oppgavestyring.testutils -import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import io.ktor.client.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* import io.ktor.serialization.jackson.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.testing.* import kotlinx.coroutines.runBlocking import no.nav.aap.ktor.client.auth.azure.AzureConfig -import oppgavestyring.config.db.DatabaseSingleton -import oppgavestyring.config.db.DbConfig -import oppgavestyring.fakes.AzureFake -import oppgavestyring.fakes.OppgaveFake +import oppgavestyring.Config +import oppgavestyring.OppgaveConfig +import oppgavestyring.config.db.DatabaseConfiguration +import oppgavestyring.config.db.DatabaseManager +import oppgavestyring.server +import oppgavestyring.testutils.fakes.AzureFake +import oppgavestyring.testutils.fakes.OppgaveFake +import oppgavestyring.testutils.fakes.generateJwtToken import org.testcontainers.containers.PostgreSQLContainer -import org.testcontainers.containers.wait.strategy.Wait import java.net.URI import javax.sql.DataSource @@ -46,11 +50,13 @@ internal fun oppgavestyringWithFakes(test: suspend (Fakes, HttpClient) -> Unit) server(fakes.config) } - val client = createClient { + val client = client.config { + install(DefaultRequest) { + bearerAuth(generateJwtToken()) + } install(ContentNegotiation) { jackson { - registerModules(JavaTimeModule()) - disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + registerModule(JavaTimeModule()) } } } @@ -67,15 +73,13 @@ internal class TestConfig(oppgavePort: Int, azurePort: Int) : Config( ), azure = AzureConfig( tokenEndpoint = "http://localhost:$azurePort/token", - clientId = "", + clientId = "oppgave", clientSecret = "", - jwksUri = "", - issuer = "", + jwksUri = "http://localhost:$azurePort", + issuer = "nav", ), ) - - object TestDatabase { val postgres = PostgreSQLContainer("postgres:16") @@ -83,18 +87,20 @@ object TestDatabase { val password get() = postgres.password val connectionUrl get() = postgres.jdbcUrl + private var connection: DataSource? = null + fun start() { postgres.start() } fun stop() { postgres.stop()} fun reset() { postgres.execInContainer( "psql", "-U", "test", "-d", "test" , "-c", "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" ) } - fun getConnection(): DataSource{ - DatabaseSingleton.init( - DbConfig( + + fun getConnection() = if (connection == null) DatabaseManager( + DatabaseConfiguration( connectionURL = connectionUrl, username = username, - password = password) + password = password ) - return DatabaseSingleton.connection!! - } + ).connection.let { connection = it; it } + else connection!! } \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/testutils/fakes/AzureFake.kt b/app/src/test/kotlin/oppgavestyring/testutils/fakes/AzureFake.kt new file mode 100644 index 0000000..11e6f62 --- /dev/null +++ b/app/src/test/kotlin/oppgavestyring/testutils/fakes/AzureFake.kt @@ -0,0 +1,72 @@ +package oppgavestyring.testutils.fakes + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import com.fasterxml.jackson.databind.ObjectMapper +import io.ktor.serialization.jackson.* +import io.ktor.server.application.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import oppgavestyring.testutils.port +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey +import java.util.* + +class AzureFake : AutoCloseable { + private val server = embeddedServer(Netty, port = 0, module = Application::azure).apply { start() } + val port: Int get() = server.port() + override fun close() = server.stop(0, 0) +} + +val rsaKeyPair = generateRsaKeyPair() +val privateKey = rsaKeyPair.private as RSAPrivateKey +val publicKey = rsaKeyPair.public as RSAPublicKey + + +fun generateRsaKeyPair(): KeyPair { + val generator = KeyPairGenerator.getInstance("RSA") + generator.initialize(512) + return generator.generateKeyPair() +} + +fun generateJwtToken() = JWT.create() + .withAudience("oppgave") + .withIssuer("nav") + .withClaim("username", "Testy mcTester") + .withSubject("1234567890") + .withClaim("NAVident", "T120345") + .withArrayClaim("groups", arrayOf("12353679-aa80-4e59-bb47-95e727bfe85c")) + .withExpiresAt(Date(System.currentTimeMillis() + 60000)) + .withIssuedAt(Date(System.currentTimeMillis() - 60000)) + .sign(Algorithm.RSA256(publicKey, privateKey)) + +private fun Application.azure() { + install(ContentNegotiation) { + jackson {} + } + + routing { + get { + call.respondText { + ObjectMapper().writeValueAsString( + mapOf( + "keys" to listOf( + mapOf( + "kty" to publicKey.algorithm, + "kid" to "dd9c18e6-7001-4197-9c52-99e378052971", + "n" to Base64.getUrlEncoder().encodeToString(publicKey.modulus.toByteArray()), + "e" to Base64.getUrlEncoder().encodeToString(publicKey.publicExponent.toByteArray()), + "alg" to "RS256", + ) + ) + ) + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/oppgavestyring/fakes/OppgaveFake.kt b/app/src/test/kotlin/oppgavestyring/testutils/fakes/OppgaveFake.kt similarity index 89% rename from app/src/test/kotlin/oppgavestyring/fakes/OppgaveFake.kt rename to app/src/test/kotlin/oppgavestyring/testutils/fakes/OppgaveFake.kt index 0631263..f76dcd0 100644 --- a/app/src/test/kotlin/oppgavestyring/fakes/OppgaveFake.kt +++ b/app/src/test/kotlin/oppgavestyring/testutils/fakes/OppgaveFake.kt @@ -1,4 +1,4 @@ -package oppgavestyring.fakes +package oppgavestyring.testutils.fakes import io.ktor.http.* import io.ktor.serialization.jackson.* @@ -9,10 +9,10 @@ import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import oppgavestyring.port -import oppgavestyring.oppgave.adapter.OpprettRequest -import oppgavestyring.oppgave.adapter.OpprettResponse -import oppgavestyring.oppgave.adapter.Status +import oppgavestyring.ekstern.oppgaveapi.adapter.OpprettRequest +import oppgavestyring.ekstern.oppgaveapi.adapter.OpprettResponse +import oppgavestyring.ekstern.oppgaveapi.adapter.Status +import oppgavestyring.testutils.port class OppgaveFake : AutoCloseable { diff --git a/app/src/test/kotlin/tilgangsstyring/TilgangstyringServiceTest.kt b/app/src/test/kotlin/tilgangsstyring/TilgangstyringServiceTest.kt new file mode 100644 index 0000000..f7a511e --- /dev/null +++ b/app/src/test/kotlin/tilgangsstyring/TilgangstyringServiceTest.kt @@ -0,0 +1,74 @@ +package tilgangsstyring + +import io.mockk.every +import io.mockk.mockk +import oppgavestyring.config.security.OppgavePrincipal +import oppgavestyring.ekstern.behandlingsflyt.dto.Avklaringsbehovtype +import oppgavestyring.ekstern.tilgangsstyring.TilgangstyringService +import oppgavestyring.intern.oppgave.db.Oppgave +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class TilgangstyringServiceTest { + + val tilgangstyringService = TilgangstyringService + + @Test + fun `saksbehandler kan se saksbehandleroppgave`() { + + val oppgave = mockk() + every { oppgave.avklaringsbehovtype } returns Avklaringsbehovtype.AVKLAR_STUDENT + val principal = mockk() + every { principal.isSaksbehandler() } returns true + every { principal.isVeileder() } returns false + + val actual = tilgangstyringService.kanSaksbehandlerSeOppgave(principal, oppgave) + + assertTrue(actual) + } + + @Test + fun `saksbehandler kan ikke se veilederoppgave`() { + + val oppgave = mockk() + every { oppgave.avklaringsbehovtype } returns Avklaringsbehovtype.AVKLAR_SYKDOM + val principal = mockk() + every { principal.isSaksbehandler() } returns true + every { principal.isVeileder() } returns false + + + val actual = tilgangstyringService.kanSaksbehandlerSeOppgave(principal, oppgave) + + assertFalse(actual) + } + + @Test + fun `veileder kan se veilederoppgave`() { + + val oppgave = mockk() + every { oppgave.avklaringsbehovtype } returns Avklaringsbehovtype.AVKLAR_SYKDOM + val principal = mockk() + every { principal.isSaksbehandler() } returns false + every { principal.isVeileder() } returns true + + val actual = tilgangstyringService.kanSaksbehandlerSeOppgave(principal, oppgave) + + assertTrue(actual) + } + + @Test + fun `veileder kan ikke se saksbehandleroppgaver`() { + + val oppgave = mockk() + every { oppgave.avklaringsbehovtype } returns Avklaringsbehovtype.AVKLAR_STUDENT + val principal = mockk() + every { principal.isSaksbehandler() } returns false + every { principal.isVeileder() } returns true + + val actual = tilgangstyringService.kanSaksbehandlerSeOppgave(principal, oppgave) + + assertFalse(actual) + } + +} \ No newline at end of file diff --git a/behandlingsflyt/build.gradle.kts b/behandlingsflyt/build.gradle.kts deleted file mode 100644 index c5e0faf..0000000 --- a/behandlingsflyt/build.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -plugins { - kotlin("jvm") version "1.9.23" - id("io.ktor.plugin") version "2.3.10" -} - -group = "behandlingsflyt" -version = "unspecified" - -repositories { - mavenCentral() -} - -dependencies { -} - -tasks.test { - useJUnitPlatform() -} \ No newline at end of file