diff --git a/common/infrastructure/src/main/kotlin/no/nav/su/se/bakover/common/infrastructure/web/Extensions.kt b/common/infrastructure/src/main/kotlin/no/nav/su/se/bakover/common/infrastructure/web/Extensions.kt index f9363560b6..1c35612084 100644 --- a/common/infrastructure/src/main/kotlin/no/nav/su/se/bakover/common/infrastructure/web/Extensions.kt +++ b/common/infrastructure/src/main/kotlin/no/nav/su/se/bakover/common/infrastructure/web/Extensions.kt @@ -221,3 +221,6 @@ suspend inline fun ApplicationCall.withBody( }.onRight(ifRight) } } + +fun ApplicationCall.isMultipartFormDataRequest(): Boolean = + this.request.headers["content-type"]?.contains("multipart/form-data") ?: false diff --git "a/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommand.kt" "b/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommand.kt" similarity index 95% rename from "domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommand.kt" rename to "domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommand.kt" index 5ec6530c61..efd1afd814 100644 --- "a/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommand.kt" +++ "b/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommand.kt" @@ -10,7 +10,7 @@ import no.nav.su.se.bakover.common.tid.Tidspunkt import java.time.Clock import java.util.UUID -data class JournalførOgSendDokumentCommand( +data class JournalførOgSendOpplastetPdfSomBrevCommand( val sakId: UUID, val saksbehandler: NavIdentBruker.Saksbehandler, val journaltittel: String, @@ -19,6 +19,7 @@ data class JournalførOgSendDokumentCommand( val distribusjonstype: Distribusjonstype, ) { fun opprettDokumentMedMetadata(clock: Clock): Dokument.MedMetadata { + // TODO - enkel løsning, men det er ikke ønskelig at domenet skal forholde seg til json val generertDokumentJson = createJson() return when (this.distribusjonstype) { diff --git a/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/SakService.kt b/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/SakService.kt index 7d989a4ac8..acda682ee1 100644 --- a/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/SakService.kt +++ b/domain/src/main/kotlin/no/nav/su/se/bakover/domain/sak/SakService.kt @@ -64,13 +64,13 @@ interface SakService { fun hentSakForVedtak(vedtakId: UUID): Sak? fun hentSakForSøknad(søknadId: UUID): Either - fun opprettFritekstDokument(request: OpprettDokumentRequest): Either - fun genererLagreOgSendFritekstDokument(request: OpprettDokumentRequest): Either + fun genererFritekstbrevPåSak(request: OpprettDokumentRequest): Either + fun genererLagreOgSendFritekstbrevPåSak(request: OpprettDokumentRequest): Either /** * Sending av dokumentet gjøres i en automatisk jobb når dokumentet lagres i databasen. */ - fun lagreOgSendFritekstDokument(request: JournalførOgSendDokumentCommand): Dokument.MedMetadata + fun lagreOgSendOpplastetPdfPåSak(request: JournalførOgSendOpplastetPdfSomBrevCommand): Dokument.MedMetadata fun hentAlleJournalposter(sakId: UUID): Either> fun oppdaterFødselsnummer(command: OppdaterFødselsnummerPåSakCommand): Either diff --git "a/domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommandTest.kt" "b/domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommandTest.kt" similarity index 97% rename from "domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommandTest.kt" rename to "domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommandTest.kt" index 937501bb48..d39459eaad 100644 --- "a/domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendDokumentCommandTest.kt" +++ "b/domain/src/test/kotlin/no/nav/su/se/bakover/domain/sak/Journalf\303\270rOgSendOpplastetPdfSomBrevCommandTest.kt" @@ -11,7 +11,7 @@ import no.nav.su.se.bakover.test.fixedTidspunkt import org.junit.jupiter.api.Test import java.util.UUID -class JournalførOgSendDokumentCommandTest { +class JournalførOgSendOpplastetPdfSomBrevCommandTest { @Test fun `oppretter dokument med metadata`() { @@ -86,7 +86,7 @@ class JournalførOgSendDokumentCommandTest { pdf: PdfA = PdfA("pdf".toByteArray()), distribueringsadresse: Distribueringsadresse? = null, distribusjonstype: Distribusjonstype = Distribusjonstype.VEDTAK, - ) = JournalførOgSendDokumentCommand( + ) = JournalførOgSendOpplastetPdfSomBrevCommand( sakId = sakId, saksbehandler = saksbehandler, journaltittel = journaltittel, diff --git a/service/src/main/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImpl.kt b/service/src/main/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImpl.kt index 079354f7c8..73165e0362 100644 --- a/service/src/main/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImpl.kt +++ b/service/src/main/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImpl.kt @@ -27,7 +27,7 @@ import no.nav.su.se.bakover.domain.Sak import no.nav.su.se.bakover.domain.brev.command.FritekstDokumentCommand import no.nav.su.se.bakover.domain.revurdering.RevurderingId import no.nav.su.se.bakover.domain.sak.FantIkkeSak -import no.nav.su.se.bakover.domain.sak.JournalførOgSendDokumentCommand +import no.nav.su.se.bakover.domain.sak.JournalførOgSendOpplastetPdfSomBrevCommand import no.nav.su.se.bakover.domain.sak.KunneIkkeHenteGjeldendeGrunnlagsdataForVedtak import no.nav.su.se.bakover.domain.sak.KunneIkkeHenteGjeldendeVedtaksdata import no.nav.su.se.bakover.domain.sak.KunneIkkeOppretteDokument @@ -148,7 +148,7 @@ class SakServiceImpl( return sakRepo.hentSakForSøknad(søknadId)?.right() ?: FantIkkeSak.left() } - override fun opprettFritekstDokument(request: OpprettDokumentRequest): Either { + override fun genererFritekstbrevPåSak(request: OpprettDokumentRequest): Either { val sak = sakRepo.hentSak(request.sakId) ?: throw IllegalStateException("Fant ikke sak ved opprettFritekstDokument. sakid ${request.sakId}") @@ -166,15 +166,18 @@ class SakServiceImpl( } } - override fun genererLagreOgSendFritekstDokument(request: OpprettDokumentRequest): Either { - return opprettFritekstDokument(request).map { + override fun genererLagreOgSendFritekstbrevPåSak(request: OpprettDokumentRequest): Either { + return genererFritekstbrevPåSak(request).map { it.leggTilMetadata(Dokument.Metadata(sakId = request.sakId), request.distribueringsadresse) }.onRight { dokumentRepo.lagre(it) } } - override fun lagreOgSendFritekstDokument(request: JournalførOgSendDokumentCommand): Dokument.MedMetadata { + override fun lagreOgSendOpplastetPdfPåSak(request: JournalførOgSendOpplastetPdfSomBrevCommand): Dokument.MedMetadata { + /** + * vi tar for god fisk at sakId finnes. Det vil smelle i databasen hvis sakId(foreign key) ikke finnes + */ return request.opprettDokumentMedMetadata(clock).also { dokumentRepo.lagre(it) } diff --git a/service/src/test/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImplTest.kt b/service/src/test/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImplTest.kt index 7860baaa74..b2f944e0a0 100644 --- a/service/src/test/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImplTest.kt +++ b/service/src/test/kotlin/no/nav/su/se/bakover/service/sak/SakServiceImplTest.kt @@ -20,7 +20,7 @@ import no.nav.su.se.bakover.common.journal.JournalpostId import no.nav.su.se.bakover.common.tid.periode.år import no.nav.su.se.bakover.domain.Sak import no.nav.su.se.bakover.domain.brev.command.FritekstDokumentCommand -import no.nav.su.se.bakover.domain.sak.JournalførOgSendDokumentCommand +import no.nav.su.se.bakover.domain.sak.JournalførOgSendOpplastetPdfSomBrevCommand import no.nav.su.se.bakover.domain.sak.OpprettDokumentRequest import no.nav.su.se.bakover.domain.sak.SakRepo import no.nav.su.se.bakover.domain.statistikk.StatistikkEvent @@ -299,7 +299,7 @@ internal class SakServiceImplTest { } SakServiceImpl(sakRepo, fixedClock, mock(), brevService, mock(), mock()) - .opprettFritekstDokument( + .genererFritekstbrevPåSak( request = OpprettDokumentRequest( sakId = sak.id, saksbehandler = saksbehandler, @@ -331,7 +331,7 @@ internal class SakServiceImplTest { } val actual = SakServiceImpl(sakRepo, fixedClock, dokumentRepo, brevService, mock(), mock()) - .genererLagreOgSendFritekstDokument( + .genererLagreOgSendFritekstbrevPåSak( request = OpprettDokumentRequest( sakId = sak.id, saksbehandler = saksbehandler, @@ -377,8 +377,8 @@ internal class SakServiceImplTest { } val actual = - SakServiceImpl(mock(), fixedClock, dokumentRepo, mock(), mock(), mock()).lagreOgSendFritekstDokument( - request = JournalførOgSendDokumentCommand( + SakServiceImpl(mock(), fixedClock, dokumentRepo, mock(), mock(), mock()).lagreOgSendOpplastetPdfPåSak( + request = JournalførOgSendOpplastetPdfSomBrevCommand( sakId = expecedSakId, saksbehandler = saksbehandler, journaltittel = "Vedtaksbrev om nytt vedtak", diff --git a/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutes.kt b/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutes.kt index bd01fad8d8..d32a5db5d5 100644 --- a/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutes.kt +++ b/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutes.kt @@ -3,25 +3,18 @@ package no.nav.su.se.bakover.web.routes.sak import arrow.core.Either import arrow.core.flatMap import arrow.core.merge -import dokument.domain.distribuering.Distribueringsadresse import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode.Companion.BadRequest import io.ktor.http.HttpStatusCode.Companion.Created import io.ktor.http.HttpStatusCode.Companion.NotFound import io.ktor.http.HttpStatusCode.Companion.OK -import io.ktor.http.content.PartData -import io.ktor.http.content.readAllParts -import io.ktor.http.content.streamProvider import io.ktor.server.application.call -import io.ktor.server.request.receiveMultipart import io.ktor.server.response.respondBytes import io.ktor.server.routing.Route import io.ktor.server.routing.get import io.ktor.server.routing.post import no.nav.su.se.bakover.common.audit.AuditLogEvent import no.nav.su.se.bakover.common.brukerrolle.Brukerrolle -import no.nav.su.se.bakover.common.deserialize -import no.nav.su.se.bakover.common.domain.PdfA import no.nav.su.se.bakover.common.domain.Saksnummer import no.nav.su.se.bakover.common.domain.sak.Sakstype import no.nav.su.se.bakover.common.infrastructure.PeriodeJson.Companion.toJson @@ -30,6 +23,7 @@ import no.nav.su.se.bakover.common.infrastructure.web.Resultat import no.nav.su.se.bakover.common.infrastructure.web.audit import no.nav.su.se.bakover.common.infrastructure.web.authorize import no.nav.su.se.bakover.common.infrastructure.web.errorJson +import no.nav.su.se.bakover.common.infrastructure.web.isMultipartFormDataRequest import no.nav.su.se.bakover.common.infrastructure.web.parameter import no.nav.su.se.bakover.common.infrastructure.web.suUserContext import no.nav.su.se.bakover.common.infrastructure.web.svar @@ -38,7 +32,6 @@ import no.nav.su.se.bakover.common.infrastructure.web.withSakId import no.nav.su.se.bakover.common.person.Fnr import no.nav.su.se.bakover.common.serialize import no.nav.su.se.bakover.common.tid.periode.Periode -import no.nav.su.se.bakover.domain.sak.JournalførOgSendDokumentCommand import no.nav.su.se.bakover.domain.sak.KunneIkkeHenteGjeldendeVedtaksdata import no.nav.su.se.bakover.domain.sak.KunneIkkeOppretteDokument import no.nav.su.se.bakover.domain.sak.OpprettDokumentRequest @@ -256,78 +249,26 @@ internal fun Route.sakRoutes( } } - data class DistribueringsadresseBody( - val adresselinje1: String, - val adresselinje2: String?, - val adresselinje3: String?, - val postnummer: String, - val poststed: String, - ) { - fun toDomain(): Distribueringsadresse = Distribueringsadresse( - adresselinje1 = adresselinje1, - adresselinje2 = adresselinje2, - adresselinje3 = adresselinje3, - postnummer = postnummer, - poststed = poststed, - ) - } - - data class DokumentBody( - val tittel: String, - val fritekst: String, - val adresse: DistribueringsadresseBody?, - val distribusjonstype: Distribusjonstype, - ) - post("$SAK_PATH/{sakId}/fritekstDokument/lagreOgSend") { authorize(Brukerrolle.Saksbehandler) { call.withSakId { sakId -> - when (call.request.headers["content-type"]?.contains("multipart/form-data")) { + when (call.isMultipartFormDataRequest()) { /** * Dersom requesten er multipart, har dem lagt på en allerede generert PDF, og vi skal bare * journalføre, og distribuere denne. */ - true -> { - val parts = call.receiveMultipart().readAllParts() - - /** - * Vi forventer en viss rekkefølge fra frontend på innholdet i formdata - * 1. journaltittel - * 2. distribusjonstype - * 3. pdf - * 4. distribueringsadresse - Denne er den eneste som er optional, og kommer sist i rekkefølgen - */ - val journaltittel: String = (parts[0] as PartData.FormItem).value - val distribusjonstype: dokument.domain.Distribusjonstype = - Distribusjonstype.valueOf((parts[1] as PartData.FormItem).value).toDomain() - val pdfContent: ByteArray = (parts[2] as PartData.FileItem).streamProvider().readBytes() - val distribueringsadresse: Distribueringsadresse? = parts.getOrNull(3)?.let { - val distribueringsadresseAsJson = (it as PartData.FormItem).value - deserialize(distribueringsadresseAsJson).toDomain() - } - - sakService.lagreOgSendFritekstDokument( - request = JournalførOgSendDokumentCommand( - sakId = sakId, - saksbehandler = call.suUserContext.saksbehandler, - journaltittel = journaltittel, - pdf = PdfA(content = pdfContent), - distribueringsadresse = distribueringsadresse, - distribusjonstype = distribusjonstype, - ), - ) - + true -> call.lagCommandForLagreOgSendOpplastetPdfPåSak(sakId).let { + sakService.lagreOgSendOpplastetPdfPåSak(request = it) call.svar(Resultat.accepted()) } + /** * så lenge requesten ikke er spesifikk multipart/form-data så vil den bli behandlet som en vanlig text/plain / app/json * vi forventer at frontend sender en body med fritekst, og vi skal generere dokumentet */ - null, - false, - -> { + false -> { call.withBody { body -> - val res = sakService.genererLagreOgSendFritekstDokument( + val res = sakService.genererLagreOgSendFritekstbrevPåSak( OpprettDokumentRequest( sakId = sakId, saksbehandler = call.suUserContext.saksbehandler, @@ -358,7 +299,7 @@ internal fun Route.sakRoutes( authorize(Brukerrolle.Saksbehandler) { call.withSakId { sakId -> call.withBody { body -> - val res = sakService.opprettFritekstDokument( + val res = sakService.genererFritekstbrevPåSak( OpprettDokumentRequest( sakId = sakId, saksbehandler = call.suUserContext.saksbehandler, diff --git a/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutesEx.kt b/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutesEx.kt new file mode 100644 index 0000000000..70a0b32d68 --- /dev/null +++ b/web/src/main/kotlin/no/nav/su/se/bakover/web/routes/sak/SakRoutesEx.kt @@ -0,0 +1,67 @@ +package no.nav.su.se.bakover.web.routes.sak + +import dokument.domain.distribuering.Distribueringsadresse +import io.ktor.http.content.PartData +import io.ktor.http.content.readAllParts +import io.ktor.http.content.streamProvider +import io.ktor.server.application.ApplicationCall +import io.ktor.server.request.receiveMultipart +import no.nav.su.se.bakover.common.deserialize +import no.nav.su.se.bakover.common.domain.PdfA +import no.nav.su.se.bakover.common.infrastructure.web.suUserContext +import no.nav.su.se.bakover.domain.sak.JournalførOgSendOpplastetPdfSomBrevCommand +import java.util.UUID + +data class DistribueringsadresseBody( + val adresselinje1: String, + val adresselinje2: String?, + val adresselinje3: String?, + val postnummer: String, + val poststed: String, +) { + fun toDomain(): Distribueringsadresse = Distribueringsadresse( + adresselinje1 = adresselinje1, + adresselinje2 = adresselinje2, + adresselinje3 = adresselinje3, + postnummer = postnummer, + poststed = poststed, + ) +} + +data class DokumentBody( + val tittel: String, + val fritekst: String, + val adresse: DistribueringsadresseBody?, + val distribusjonstype: Distribusjonstype, +) + +suspend fun ApplicationCall.lagCommandForLagreOgSendOpplastetPdfPåSak( + sakId: UUID, +): JournalførOgSendOpplastetPdfSomBrevCommand { + val parts = this.receiveMultipart().readAllParts() + + /** + * Vi forventer en viss rekkefølge fra frontend på innholdet i formdata + * 1. journaltittel + * 2. distribusjonstype + * 3. pdf + * 4. distribueringsadresse - Denne er den eneste som er optional, og kommer sist i rekkefølgen + */ + val journaltittel: String = (parts[0] as PartData.FormItem).value + val distribusjonstype: dokument.domain.Distribusjonstype = + Distribusjonstype.valueOf((parts[1] as PartData.FormItem).value).toDomain() + val pdfContent: ByteArray = (parts[2] as PartData.FileItem).streamProvider().readBytes() + val distribueringsadresse: Distribueringsadresse? = parts.getOrNull(3)?.let { + val distribueringsadresseAsJson = (it as PartData.FormItem).value + deserialize(distribueringsadresseAsJson).toDomain() + } + + return JournalførOgSendOpplastetPdfSomBrevCommand( + sakId = sakId, + saksbehandler = this.suUserContext.saksbehandler, + journaltittel = journaltittel, + pdf = PdfA(content = pdfContent), + distribueringsadresse = distribueringsadresse, + distribusjonstype = distribusjonstype, + ) +} diff --git a/web/src/main/kotlin/no/nav/su/se/bakover/web/services/AccessCheckProxy.kt b/web/src/main/kotlin/no/nav/su/se/bakover/web/services/AccessCheckProxy.kt index 34e76e20a4..b6248acbd4 100644 --- a/web/src/main/kotlin/no/nav/su/se/bakover/web/services/AccessCheckProxy.kt +++ b/web/src/main/kotlin/no/nav/su/se/bakover/web/services/AccessCheckProxy.kt @@ -120,7 +120,7 @@ import no.nav.su.se.bakover.domain.revurdering.vilkår.uføre.KunneIkkeLeggeTilU import no.nav.su.se.bakover.domain.revurdering.vilkår.utenlandsopphold.KunneIkkeLeggeTilUtenlandsopphold import no.nav.su.se.bakover.domain.sak.FantIkkeSak import no.nav.su.se.bakover.domain.sak.FeilVedHentingAvGjeldendeVedtaksdataForPeriode -import no.nav.su.se.bakover.domain.sak.JournalførOgSendDokumentCommand +import no.nav.su.se.bakover.domain.sak.JournalførOgSendOpplastetPdfSomBrevCommand import no.nav.su.se.bakover.domain.sak.KunneIkkeHenteGjeldendeGrunnlagsdataForVedtak import no.nav.su.se.bakover.domain.sak.KunneIkkeHenteGjeldendeVedtaksdata import no.nav.su.se.bakover.domain.sak.KunneIkkeOppretteDokument @@ -392,19 +392,19 @@ open class AccessCheckProxy( return services.sak.hentSakForSøknad(søknadId) } - override fun opprettFritekstDokument(request: OpprettDokumentRequest): Either { + override fun genererFritekstbrevPåSak(request: OpprettDokumentRequest): Either { assertHarTilgangTilSak(request.sakId) - return services.sak.opprettFritekstDokument(request) + return services.sak.genererFritekstbrevPåSak(request) } - override fun genererLagreOgSendFritekstDokument(request: OpprettDokumentRequest): Either { + override fun genererLagreOgSendFritekstbrevPåSak(request: OpprettDokumentRequest): Either { assertHarTilgangTilSak(request.sakId) - return services.sak.genererLagreOgSendFritekstDokument(request) + return services.sak.genererLagreOgSendFritekstbrevPåSak(request) } - override fun lagreOgSendFritekstDokument(request: JournalførOgSendDokumentCommand): Dokument.MedMetadata { + override fun lagreOgSendOpplastetPdfPåSak(request: JournalførOgSendOpplastetPdfSomBrevCommand): Dokument.MedMetadata { assertHarTilgangTilSak(request.sakId) - return services.sak.lagreOgSendFritekstDokument(request) + return services.sak.lagreOgSendOpplastetPdfPåSak(request) } override fun hentAlleJournalposter(sakId: UUID): Either> {