From 67269b1b3ee0ad664451ffb1209f1f0d38d9992c Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Wed, 22 Nov 2023 16:44:29 +0100 Subject: [PATCH] Fix PR comments --- .../guides/multi-app-solution/_index.nb.md | 95 ++++++- .../instructions/_index.nb.md | 35 ++- .../instructions/app-a/_index.nb.md | 242 +++++++++++++++++- .../instructions/app-b/_index.en.md | 2 +- .../instructions/app-b/_index.nb.md | 72 +++++- .../multi-app-architecture.drawio.svg | 184 ++++++++----- .../multi-app-solution/testing/_index.en.md | 4 +- .../multi-app-solution/testing/_index.nb.md | 94 ++++++- 8 files changed, 644 insertions(+), 84 deletions(-) diff --git a/content/app/guides/multi-app-solution/_index.nb.md b/content/app/guides/multi-app-solution/_index.nb.md index 739a2db7471..e724a62ca31 100644 --- a/content/app/guides/multi-app-solution/_index.nb.md +++ b/content/app/guides/multi-app-solution/_index.nb.md @@ -1,16 +1,99 @@ --- -title: Generell fremgangsmåte for å utvikle en multi-app løsning i Altinn -linktitle: Multi-app løsning -description: Vurderinger som burde gjøres og forklaringer på hvordan å gå frem når man utvikler en multi-app løsning +title: Generell fremgangsmåte for å utvikle en flerappsløsning i Altinn +linktitle: Flerappsløsning +description: Vurderinger som burde gjøres og forklaringer på hvordan å gå frem når man utvikler en flerappsløsning weight: 250 aliases: - /app/multi-app-solution/ + --- -Før du leser videre i denne guiden, vær så snill å gjør en vurdering om en multi-app løsning er det du trenger for å realisere skjemaet ditt. +## Hva er en flerappsløsning? + +En flerappsløsning er en løsning som består av to eller flere +samarbeidende applikasjoner, der applikasjon A typisk vil utløse +opprettelsen av en ny +instans av applikasjon B. Som en del av +opprettelsen av applikasjon B er det mulig å +forhåndsfylle instansen med spesifikke data fra den pågående +forekomsten av applikasjon A. + +Denne guiden tar deg gjennom en flerappsløsning som består av to +apper; _applikasjon A_ og _applikasjon B_, +men konseptet kan utvides til å inneholde flere applikasjoner av +type A eller type B, eller begge typer. + +![Eksempelarkitektur for en flerapp-løsning](multi-app-architecture.drawio.svg) + +### Terminologi + +- **En instans:** Når vi snakker om instanser i en + applikasjonskontekst, refererer dette til unik data som beskriver + detaljer om den spesifikke økten som pågår i applikasjonen. + Dataene inkluderer informasjon om hvem som fyller ut + dataene og hva dataene inneholder. +- **Applikasjon A:** Dette vil være en applikasjon som fungerer som en vanlig + Altinn-applikasjon, noe som betyr at + sluttbrukere vil samhandle med den. Mens de fyller ut skjemaet, vil de + jobbe på sin egen private instans. Imidlertid + vil den skille seg fra andre Altinn-apper siden tjeneste-eieren + har tilpasset den for å inkludere handlinger som + vil opprette en ny instans av _applikasjon B_. +- **Applikasjon B:** Dette vil være en applikasjon som kan ha flere + formål, men hovedformålet vil være + å motta og håndtere data fra _applikasjon A_. + Denne applikasjonen vil skille seg fra + andre Altinn-apper siden instanser opprettes av + utløsere i en annen applikasjon. + +## Trenger jeg en flerappsløsning? + +Altinn tilbyr et robust sett med API-er og eventstøtte for behandling av data fra Altinn-apper. Hvis disse +alternativene ikke +samsvarer med dine behov, kan du vurdere en flerappsløsning. + +### Brukstilfeller der du kan vurdere å bruke en flerappsløsning: + +Vi har skissert noen vanlige brukstilfeller hvor en flerappsløsning kan være hensiktsmessig. + +- Organisasjonen har begrenset utviklingskapasitet eller ønsker ikke + å utvikle og vedlikeholde et nytt system for behandling av data fra + Altinn. +- Eksisterende oppsett i organisasjonen for behandling av data fra + Altinn oppfyller ikke kravene til sikkerhet. + +Ved å implementere en flerappsløsning kan en organisasjon bruke Altinn-innboksen for å motta data. I +de fleste tilfeller vil personene som trenger å behandle dataene allerede ha tilgang til organisasjonen i Altinn eller +kan +tildeles denne tilgangen. Den siste applikasjonen i dataflyten (applikasjon B i vårt tilfelle) kan angi +autorisasjonsregler +som krever en spesifikk rolle før tilgang til dataene gis, og dermed støtte begrenset tilgang til sensitive data til +personer med et offisielt behov. + +## Hvordan fungerer egentlig flerappsløsning? + +En flerappsløsning er en måte å konfigurere flere skjemaer for å kommunisere gjennom API-kall. Den spesifikke +kommunikasjonen +vi vil beskrive i denne veilederen er opprettelsen av en ny instans av en applikasjon (B) utløst av en annen +applikasjon +(A). Et typisk scenario ville være at en sluttbruker fyller ut eller laster opp informasjon i en instans av +applikasjon A. Når sluttbruker trykker +på knappen for å sende inn skjemaet, sendes et API-kall til en annen applikasjon (B), og det opprettes en ny instans +av denne applikasjonen hvor +svarene fra applikasjon A er en del av informasjonen. + +### En integrasjon mellom appen og Maskinporten kan være nødvendig -## Trenger jeg en multi-app løsning? -... +For at en applikasjon skal utføre handlinger på en annen applikasjon, for eksempel opprette en ny instans på vegne av +en sluttbruker eller organisasjon, må den være autorisert. +Av natur vil forespørselen om å opprette instansen av applikasjon B inkludere legitimasjonen til sluttbrukeren +som fyller ut applikasjon A. +I de fleste tilfeller vil ikke denne sluttbrukeren være autorisert til å instansiere nye instanser på vegne av +organisasjonen som eier applikasjon B, og dette vil derfor feile. +En måte å sikre at applikasjonen er autorisert til å utføre instansieringshandlingen på, er å bruke +applikasjoneierens legitimasjon i stedet for sluttbrukerens legitimasjon. +Dette oppnås ved å bruke en Maskinporten-integrasjon for å generere en token som representerer organisasjonen +og legge dette tokenet til i forespørslene som applikasjon A gjør mot applikasjon B. {{}} \ No newline at end of file diff --git a/content/app/guides/multi-app-solution/instructions/_index.nb.md b/content/app/guides/multi-app-solution/instructions/_index.nb.md index 103615a25db..97dcd22b8c7 100644 --- a/content/app/guides/multi-app-solution/instructions/_index.nb.md +++ b/content/app/guides/multi-app-solution/instructions/_index.nb.md @@ -1,7 +1,7 @@ --- -title: Instructions for making a multi-app solution in Altinn -linktitle: Multi-app solution instructions -description: Explanations of how to go about when creating a general multi-app solution +title: Instruksjoner for å utvikle en flerappsløsning i Altinn +linktitle: Instruksjoner +description: Forklaringer om hvordan du går frem for å lage en generell flerappsløsning weight: 20 aliases: @@ -9,4 +9,31 @@ aliases: --- -{{}} \ No newline at end of file +## Forutsetninger + +Før du starter på den tekniske implementeringen, må du sørge for at de nødvendige forutsetningene er oppfylt. + +### Funksjonelle forutsetninger + +1. App-utvikleren må ha tilgang til å opprette, utvikle og distribuere applikasjoner eid av en organisasjon. +2. Et eksisterende Altinn-skjema (applikasjon A) der dataene som er ment å videresendes til applikasjon + B, er identifisert. +3. Det skal være klart hvem instanse-eierne er, det vil si hvilke roller og tilganger de har. + +### Tekniske forutsetninger + +1. Applikasjonene dine bruker versjon 8 eller nyere av Altinn-nugets. +2. Organisasjonen har allerede en eksisterende Maskinporten-klient med riktige altinn-spesifikke + scopes; `altinn:serviceowner/instances.read` og + `altinn:serviceowner/instances.write`* +3. En integrasjon mellom applikasjon(en) og klientene i Maskinporten. Dette må gjøres i applikasjonen(e) + som skal sende forespørsler til en annen applikasjon, hvor forespørslene må autoriseres av applikasjonenseier.* + +Hvis trinn 2 og 3 av de tekniske kravene mangler, se +seksjonen [Maskinporten-App Integrering](../../maskinporten-app-integration) + +\* _Hvis sluttbrukeren av applikasjon A har de nødvendige rollene for å instansiere applikasjon B på vegne av den +tiltenkte +mottakeren, kan du hoppe over disse tekniske kravene._ + +{{}} \ No newline at end of file diff --git a/content/app/guides/multi-app-solution/instructions/app-a/_index.nb.md b/content/app/guides/multi-app-solution/instructions/app-a/_index.nb.md index b424777d7de..38445764c41 100644 --- a/content/app/guides/multi-app-solution/instructions/app-a/_index.nb.md +++ b/content/app/guides/multi-app-solution/instructions/app-a/_index.nb.md @@ -1,11 +1,243 @@ --- -title: -linktitle: Multi-app solution instructions -description: -weight: 20 -toc: true +title: Applikasjon A +linktitle: Applikasjon A +description: Instruksjoner for å sette opp applikasjon A +weight: 10 aliases: - /app/multi-app-solution/instructions/app-a --- + +Applikasjon A er ansvarlig for å utløse opprettelsen av applikasjon B og sende data til den. +For å oppnå dette må flere trinn følges. + +1. Utvid applikasjonsprosessen med et ekstra steg. +2. Legg til logikk for opprettelse av applikasjon B til en hendelsestrigger. +3. Fyll/hent og send videre relevant data til den nyopprettede instansen av applikasjon B. + +{{% notice warning %}} +Disse retningslinjene forutsetter at det allerede eksisterer en grunnleggende Altinn-applikasjon. Fokuset i denne +veilederen er på +de mer tekniske tilpasningene som er nødvendige for å realisere formålet med flerappsløsningen +{{% /notice %}} + +## Legg til steg i prosessen + +### Hvorfor behovet for flere steg + +I de fleste tilfeller er det nødvendig å sende dataene som sluttbrukeren +har lagt til i skjemaet, videre til applikasjon B. Disse dataene er bevart i pdf-elementet som lagres som en del +av instansobjektet. Denne pdf-en genereres bare ved _slutten_ av et steg. Derfor er det behov for +et +ekstra steg for å kunne hente ut pdf-en. Du må ha minst to steg, der det +siste steget _ikke_ er et datasteg. Steget kan være _confirm_ +eller _feedback_. Vi anbefaler å bruke stegtypen _confirm_, og det er det de følgende retningslinjene vil +bruke. + +### Hvordan utvide prosessen med flere steg + +For å legge til steg for å utvide applikasjonsprosessen, må vi oppdatere `process.bpmn` og `policy.xml`. + +1. Du vil finne eksempler på hvordan du tilpasser filen `process.bpmn`, der applikasjonsprosessen er definert, i + [prosessdokumentasjonen](/app/development/configuration/process). +

Når du bruker stegtypen _confirm_, må vi tillate å gå tilbake til en tidligere stegtype, noe som også + betyr + at vi + må dra nytte av _exclusive gateways_. Les mer om exclusive + gateways [her](/app/development/configuration/process/exclusive-gateways). +2. Filen `policy.xml`, der autorisasjonsreglene er definert, trenger oppdateringer slik at lese- og skriveoperasjoner + kan utføres på det nye steget.

Se [XACML-policy](/authorization/guide/xacml) + , [policyredigerer](/app/development/configuration/authorization) + og [Retningslinjer for autorisasjonsregler](/app/development/configuration/authorization/guidelines_authorization) + for detaljer. De fleste apper tillater dette som standard med gjeldende mal. + +## Utløs instansiering av applikasjon B + +### Hvorfor kreves det spesiell tilpasning for å utløse instansieringen av applikasjon B + +Det essensielle formålet med en flerappsløsning avhenger av at en instans av en applikasjon opprettes av en +gitt utløserhandlign i en annen Altinn-applikasjon. Den naturlige måten å instansiere en Altinn-applikasjon på er ved å +gjøre en +API POST-forespørsel til den kjørende Altinn-applikasjonen. Det er altså ingen innebygd måte i Altinn-konteksten +for å utløse +denne atferden, noe som betyr at vi må utløse API-forespørselen med egendefinert kode i applikasjon A. + +### Hvordan tilpasse applikasjon A for å utløse instansiering av applikasjon B + +Den generelle tilnærmingen for at en Altinn-applikasjon skal utføre egendefinerte operasjoner, er å implementere kode på +visse hooks, som +er forhåndsdefinerte funksjoner i app-backend. +Les om hvordan denne egendefinerte koden legges til [her](/app/development/configuration/process/pre-post-hooks). + +1. Hvis det ikke allerede er til stede, opprett en fil for å implementere den egendefinerte koden som kjører på slutten + av et + steg, `ProcessTaskEnd.cs`. I filen implementerer du koden som oppretter instansobjektet som vil bli brukt som + grunnlag for den nye instansen av applikasjon B. Se nedenfor for et eksempel på en mal. Sørg for at + instansopprettelsen skjer når + steget er fullført, dvs. bruk funksjonen `ProcessTaskEnd.End()`. Dette er nødvendig siden brukeren kan gå tilbake + til datasteget og gjøre endringer på skjemaet.

`instanceOwner`-delen av instansobjektet er essensiell da + det er her du spesifiserer instanseieren. Å definere det med `OrganisationNumber` betyr at eieren er en + organisasjon, + mens å definere det med `PersonNumber` betyr at eieren er en privatperson.

En naturlig del av instansobjektet + er _prefill_-delen der du + legger til ønskede data som den nye instansen av applikasjon B skal fylles ut med. Det resulterende instansobjektet + vil se omtrent slik ut: + + ```csharp + var instanceTemplate = new InstansiationInstance + { + InstanceOwner = new InstanceOwner + { + //OrganisationNumber = [mottakerOrgNr], Eller + //PersonNumber = [mottakerSsnNr], + }, + Prefill = new() + { + {"noenDataIMottakerDataModell", noenVerdiFraDenneTriggerApplikasjonen}, + {"merDataIMottakerDataModell", noenStatiskVerdi}, + ... + }, + }; + ``` + +2. For å faktisk utføre forespørselen for å opprette instansen, må vi legge til en klient. Se + [konsumer dokumentasjonen](/app/development/api/consume#implementere-klienten) for å se et eksempel på hvordan + en slik klient kan legges til i applikasjonen. Et passende navn for klienten som brukes i denne konteksten kan for + eksempel være + `AppInstantiationClient`. I tillegg til instruksjonene i den refererte dokumentasjonen, trenger + konstruktøren vår ytterligere konfigurasjon for HttpClienten. Legg til følgende kode i konstruktøren for å legge til + en + subscription key i + headeren til forespørslene som sendes av http-klienten. + ```csharp + public AppClient( + ... + HttpClient httpClient, + ... + { + ... + httpClient.DefaultRequestHeaders.Add(General.SubscriptionKeyHeaderName, platformSettings.Value.SubscriptionKey); + _client = httpClient; + ... + } + ``` + + I stedet for å opprette en funksjon i klienten med navnet `GetCountry`, som i dokumentasjonen nevnt ovenfor, + implementer + den + følgende funksjonen, `CreateNewInstance`: + + ```csharp + public async Task CreateNewInstance(string AppOwnerOrgName, string applicationB, InstansiationInstance instanceTemplate) + { + string apiUrl = $"{AppOwnerOrgName}/{applicationB}/instances/create"; + + string envUrl = $"https://{AppOwnerOrgName}.apps.{_settings.HostName}"; + + _client.BaseAddress = new Uri(envUrl); + + StringContent content = new StringContent(JsonConvert.SerializeObject(instanceTemplate), Encoding.UTF8, "application/json"); + + HttpResponseMessage response = await _client.PostAsync(apiUrl, content); + + if (response.IsSuccessStatusCode) + { + Instance createdInstance = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + + return createdInstance; + } + throw await PlatformHttpException.CreateAsync(response); + } + ``` + +3. I filen `ProcessTaskEnd.cs`, legg til den nye _AppInstantiationClient_ i klassen `ProcessTaskEnd` på samme måte + som _CountryClient_ legges til i klassen `DataProcessingHandler` + i [konsumer dokumentasjonen](/app/development/api/consume#bruke-klienten-i-applikasjonslogikken). + Videre, kall metoden som utløser forespørselen i appInstantiationClient slik: + + ```csharp + Instance applicationBInstance = await _appInstantiationClient.CreateNewInstance([AppOwnerOrgName], [applicationB], [instanceTemplate]); + ``` + +Hvis klienten skal autentisere seg selv som sluttbruker, heller enn applikasjonseieren via maskinporten, vennligst +referanse +[app-lib klientimplementeringene](https://github.com/Altinn/app-lib-dotnet/tree/main/src/Altinn.App.Core/Infrastructure/Clients) +for detaljer om hvordan du tilpasser API-forespørselen i AppInstantiationClient for å oppnå dette. + +## Levering av data til applikasjon B + +### Hvorfor manipulere dataene for applikasjon B i applikasjon A + +Det er naturlig å utnytte flerappsløsningen for å kontrollere presentasjonen av informasjon i applikasjon +B dynamisk avhengig av hvilke data som er lagt inn i en instans av applikasjon A. Dette betyr at alle tilpasninger på +applikasjon B som er avhengige av data hentet fra applikasjon A, må gjøres i applikasjon A og på en eller annen måte +bli levert eller representert i applikasjon B. + +### Hente data fra applikasjon A for å sende videre til applikasjon B + +Før noen datatyper kan legges til, må de hentes fra Altinn Storage siden applikasjonen ikke har +direkte tilgang til dette som standard. +Den mest sannsynlige datatypen å sende videre fra applikasjon A til applikasjon B er pdf-en som inkluderer all +informasjonen fylt ut i instansen av applikasjon A. For å hente denne dataen fra applikasjon A, må den hentes fra Altinn +Storage. Pdf-en eksisterer på instanstobjektet som en del av `dataTypes`-feltet med navnet `ref-data-as-pdf`. Dette kan +hentes ved å få tak i instansobjektet og hente dataen direkte på objektet, eller ved å bruke den allerede +definerte `GetBinaryData`-metoden på dataklienten. +Se eksempelkode nedenfor for begge deler: + + ```csharp + // Using the instance object directly with the GetInstance method on the InstanceClient + Instance updatedInstance = await _instanceClient.GetInstance(innsendingsApp, mutliAppOwner, int.Parse(instance.InstanceOwner.PartyId), instanceGuid); + DataElement pdf = updatedInstance.Data.FindLast(d => d.DataType == "ref-data-as-pdf"); + + // Using the GetBinaryData method on the DataClient + var stream = await _dataClient.GetBinaryData(instance.Org, instance.AppId,int.Parse(instance.InstanceOwner.PartyId), instanceGuid, Guid.Parse(pdf.Id)); + ``` + +_NB: For å bruke disse metodene i klassen `ProcessTaskEnd`, må konstruktøren konfigureres for å bruke +InstanceClient og/eller DataClient._ + + + +### Hvordan kontrollere data i applikasjon B fra applikasjon A + +Det er flere måter å kontrollere visse data i applikasjon B på, der en eller flere kan utnyttes: + +- **Alt 1:** Legg til data som verdier i datamodellen til + applikasjon B ved å legge til navnet på datamodellfeltet og + den tilsvarende verdien i `prefill`-feltet til + instansmalen som du opprettet i [Utløs opprettelsen av applikasjon B](#trigger-the-instantiation-of-application-b) + -delen over. +- **Alt 2:** Hvis intensjonen er å manipulere tekstene i Altinn + Innboks for instanser av applikasjon B, + bruk [_presentasjonsfelt_](/app/development/configuration/messagebox/presentationfields) + . + +- **Alt 3:** Legg til data som binære data ved å sende en POST-forespørsel til instansen av applikasjon B. + ```csharp + public async Task InsertBinaryData(string org, string app, string instanceId, string contentType, string filename, Stream stream) + { + string envUrl = $"https://{org}.apps.{_settings.HostName}"; + _client.BaseAddress = new Uri(envUrl); + + string apiUrl = $"{org}/{app}/instances/{instanceId}/data?dataType=vedlegg"; + + StreamContent content = new(stream); + content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + if (!string.IsNullOrEmpty(filename)) + { + content.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Attachment) + { + FileName = filename, + FileNameStar = filename + }; + } + + HttpResponseMessage response = await _client.PostAsync(apiUrl, content); + + if (response.IsSuccessStatusCode) + { + await Task.CompletedTask; + } + } + ``` \ No newline at end of file diff --git a/content/app/guides/multi-app-solution/instructions/app-b/_index.en.md b/content/app/guides/multi-app-solution/instructions/app-b/_index.en.md index ac6382035c6..00c9db6cb0e 100644 --- a/content/app/guides/multi-app-solution/instructions/app-b/_index.en.md +++ b/content/app/guides/multi-app-solution/instructions/app-b/_index.en.md @@ -31,7 +31,7 @@ If using presentation fields or prefill, as explained in [alternative 1 and 2 in the final part of app A instructions](../app-a#control-data-in-app-b) , no custom code is required. -If utilizing alternative 3, the data needs to be actively fetched from the instance. This is done by utilising +If utilizing alternative 3, the data needs to be actively fetched from the instance. This is done by utilizing the `ProcessDataRead` method in the `DataProcessor` service along with the `UpdateData` method on the `dataClient`. See example code below: diff --git a/content/app/guides/multi-app-solution/instructions/app-b/_index.nb.md b/content/app/guides/multi-app-solution/instructions/app-b/_index.nb.md index 1ecbda1eb08..74521970fe2 100644 --- a/content/app/guides/multi-app-solution/instructions/app-b/_index.nb.md +++ b/content/app/guides/multi-app-solution/instructions/app-b/_index.nb.md @@ -1,10 +1,74 @@ --- -title: Mottaksapp -linktitle: Multi-app solution instructions -description: Instruksjoner for mottaksappen +title: Applikasjon B +linktitle: Applikasjon B +description: Instruksjoner for å sette opp applikasjon B weight: 20 aliases: -- /app/multi-app-solution/instructions/receiver-app +- /app/multi-app-solution/instructions/app-b --- + +Applikasjon B er først og fremst ansvarlig for å håndtere og presentere data som den henter fra applikasjon A. +Utover dette kan applikasjonen fungere som en vanlig Altinn-applikasjon der det siste trinnet er å sende inn skjemaet, +og +dermed +avslutte livssyklusen til den opprettede instansen. På en annen side, hvis det ikke er en naturlig måte å avslutte +instansen +av applikasjon +B på, må dette håndteres manuelt. + +Les følgende seksjoner for mer detaljer: + +- [Henting av data fra applikasjon A](#henting-av-data-fra-applikasjon-a) +- [Stopp en aktiv instans](#stopp-en-aktiv-instans) + +## Henting av data fra applikasjon A + +Applikasjon B trenger mye mindre konfigurasjon, som et +minimum. Hovedoppgaven +for applikasjon B er å hente ut dataene mottatt +fra applikasjon A og representere eller behandle dem på en måte. + +Hvis du bruker presentasjonsfelt eller prefill, som forklart +i [alternativ 1 og 2 i den siste delen av app A-instruksjonene](../app-a#kontrollere-data-i-app-b) +, er ingen tilpasset kode nødvendig. + +Hvis du benytter alternativ 3, må dataene aktivt hentes fra instansen. Dette gjøres ved å bruke +`ProcessDataRead`-metoden i servicen `DataProcessor` sammen med `UpdateData` +metoden på `dataClient`. Se eksempelkode nedenfor: + +```csharp +public async Task ProcessDataRead(Instance instance, Guid? dataId, object data) +{ + bool redigert = false; + + if (data.GetType() == typeof(DataModel)) + { + DataModel modell = (DataModel)data; + + DataElement data = instance.Data.FirstOrDefault(de => de.DataType == [DATA_TYPE]); + + if (data != null) + { + var instansGuid = Guid.Parse(instance.Id.Split("/")[1]); + + await _dataClient.UpdateData(modell, instansGuid, typeof(DataModel), instance.Org, instance.AppId, int.Parse(instance.InstanceOwner.PartyId), Guid.Parse(instance.Data.Where(de => de.DataType == [DATA_TYPE]).First().Id)); + redigert = true; + } + } + return await Task.FromResult(redigert); +} +``` + +## Stopp en aktiv instans + +Siden denne applikasjonen, i de fleste tilfeller, vil fungere som +et on-demand-dashboard for å hente inn data fra +applikasjon A, har applikasjonen ingen naturlig måte å avslutte sin +prosess på. For å omgå dette hindret, bør de innkommende skjemaene enten: + +1. slettes manuelt etter å ha blitt lest, eller +2. de må implementeres med et krav om noen form for + brukerinteraksjon + som vil utløse avslutningen av prosessen. \ No newline at end of file diff --git a/content/app/guides/multi-app-solution/multi-app-architecture.drawio.svg b/content/app/guides/multi-app-solution/multi-app-architecture.drawio.svg index 72816409fee..52dbe95c67e 100644 --- a/content/app/guides/multi-app-solution/multi-app-architecture.drawio.svg +++ b/content/app/guides/multi-app-solution/multi-app-architecture.drawio.svg @@ -1,59 +1,103 @@ - + + + + - - - - - - + - -
-
+ +
+
+
+ End user +
+
+
+
+ + End us... + + + + + + + + + + +
+
Application A
- + Application A
- - - + + + - -
-
+ +
+
Application B
- + Application B - + - -
-
+ +
+


@@ -61,98 +105,124 @@


-
- Case worker +
Case worker
- + Case w... - - + + - -
-
+ +
+
Instantiates w/prefill
- + Instantiates w/prefill - - + + - -
-
+ +
+
Uploads attachments
- + Uploads attachments - - + + - -
-
+ +
+
PDF
- + PDF - - + + - -
-
+ +
+
Image
- + Image - - + + - - - Text is not SVG - cannot display - + + Text is not SVG - cannot display \ No newline at end of file diff --git a/content/app/guides/multi-app-solution/testing/_index.en.md b/content/app/guides/multi-app-solution/testing/_index.en.md index b997db4085a..845cb568463 100644 --- a/content/app/guides/multi-app-solution/testing/_index.en.md +++ b/content/app/guides/multi-app-solution/testing/_index.en.md @@ -53,8 +53,8 @@ If doing this modification be very careful that these secrets must not be shared After this modification the application is set up correctly with a client that can be authorized with Maskinporten when sending the instantiation request to application B. However, this request will not -be executed successfully due to the receiving application is not -running. App-localtest is limited to only handle one running application, but if the receiving application is running in +be executed successfully due to application B is not +running. App-localtest is limited to only handle one running application, but if application B is running in the environment, preferably in tt02 during test, you can change the request to point to this environment instead of local.altinn.cloud. This can be done by changing the envUrl in the `AppClient.CreateNewInstance()` method. diff --git a/content/app/guides/multi-app-solution/testing/_index.nb.md b/content/app/guides/multi-app-solution/testing/_index.nb.md index 2ba11c91fba..3d80c0738f5 100644 --- a/content/app/guides/multi-app-solution/testing/_index.nb.md +++ b/content/app/guides/multi-app-solution/testing/_index.nb.md @@ -1,10 +1,94 @@ --- -title: Preparations before making a multi-app solution in Altinn -linktitle: Multi-app solution preparations -description: What preparations that should be done before creating a multi-app solution -weight: 10 +title: Teste en flerappsløsning i Altinn +linktitle: Testing +description: Hvordan teste flerappsløasningen under utvikling +weight: 50 +toc: true aliases: -- /app/multi-app-solution/preparations/ +- /app/multi-app-solution/testing/ --- + +## Hvordan fungerer testing med Maskinporten + +Når du samhandler med Maskinporten i en applikasjon, er det noen ting du bør være klar over. + +Først og fremst lar Samarbeidsportalen deg opprettholde to forskjellige klienter; en for test, kalt `ver2`/`test`, og +en annen for +produksjon, +kalt `prod`. Du bør opprette begge klientene, men selvfølgelig bare bruke testklienten for testing og +produksjonsklienten for +produksjon. Hvilken klient du skal bruke i hvilken situasjon, avgjøres av forskjellige konfigurasjoner for +`appsettings.{env}.json`-filene. Det er forskjellige tilgangsregler for å opprette disse klientene, så sørg for at du er +klar over +disse begrensningene +beskrevet +på [Samarbeidsportalen](https://docs.digdir.no/docs/Maskinporten/maskinporten_sjolvbetjening_web#innlogging-og-tilgang). + +For det andre, siden integrering av denne klienten med en Altinn-app avhenger av autorisasjon gjennom offentlige og +private nøkler (JWT) +lagret som Azure-sekretesser, trenger du tilgang til organisasjonens Azure Key vault. + +## Hva kan gjøres i Studio + +Støtten for utvikling av flerapp-løsninger i Studio er for øyeblikket svært begrenset. Derfor kan Studio bare gi hjelp +med allerede støttede konfigurasjoner for enkeltapper. +Dette betyr at du bare kan bygge de individuelle applikasjonene og visualisere utseendet deres i +forhåndsvisningsverktøyet. + +## Hva kan gjøres i app-localtest + +Når du kjører applikasjonen lokalt i app-localtest, kan du teste all logikken i applikasjon A til +punktet der opprettelsesforespørselen til applikasjon B utløses. Årsaken til dette er at AppClient prøver å få tilgang +til +Azure Key vault for å hente de nødvendige hemmelighetene for autorisasjon til Maskinporten. Men hemmelighetene som +trengs for å få +tillatelse til å få tilgang til Azure Key vault, er ikke tilgjengelige når du kjører i lokaltest. + +Imidlertid er det en måte å omgå dette på, for testformål. Nøklene som trengs, `clientID` og `encodedJWT`, for å +autorisere forespørsler til Maskinporten kan kopieres fra din organisasjons Azure Key vault og *midlertidig* limes inn i +`appsettings.json` +filen. + +{{% notice warning %}} +Vær veldig forsiktig med denne endringen, disse nøklene må ikke deles ved å laste dem opp til gitea. +{{% /notice %}} + +Etter denne endringen er applikasjonen satt opp riktig med en klient som kan +autoriseres med Maskinporten når opprettelsesforespørselen sendes til applikasjon B. Imidlertid vil ikke +denne forespørselen bli utført vellykket fordi applikasjon B ikke kjører. App-localtest kan bare håndtere én +kjørende applikasjon, men hvis +applikasjon B kjører i +miljøet, helst i tt02 under test, kan du endre forespørselen til å peke på dette miljøet i stedet for +local.altinn.cloud. Dette kan gjøres ved å endre envUrl i `AppClient.CreateNewInstance()`-metoden. + +Endre denne linjen: + +```csharp +string envUrl = $"https://{org}.apps.{_settings.HostName}"; +``` + +Til dette: + +```csharp +string envUrl = $"https://{org}.apps.tt02"; +``` + +_NB: Ikke endre variabelen HostName i appsettings.json, siden denne også brukes til andre kritiske formål._ + +Med mindre du har noe imot å injisere testdata fra applikasjon B i organisasjonen din sin Altinn Innboks, bør du +justere mottakeren av instansen som skal opprettes i instansetemplatet i applikasjon A. Dette gjøres +ved å bruke `PersonNumber` i stedet for `OrganisationNumber` i `InstanceOwner`-delen av malobjektet +i `ProcessTaskEnd.End()`-metoden. Det anbefales å bruke et personnummer for en testbruker fra Tenor-testdatabasen. +Når du tester om skjemaet fra applikasjon B har kommet gjennom, må du logge inn +på [tt02.altinn.no](https://tt02.altinn.no/) +med samme testbruker fra Tenor. + +## Hva må gjøres i tt02 + +Før du faktisk ruller ut applikasjonene i produksjon, bør skjemaene ha blitt testet fullt ut i tt02 med faktisk +bruk av Azure Key Vault og riktig variabel for envUrl. Dette betyr at begge applikasjonene bør testes mens de kjører i +tt02. Det er fortsatt mulig å teste med en testbruker fra Tenor som mottaker av instansen, men et alternativ +er å be om en testorganisasjon som kan motta disse skjemaene. Dette kan gjøres ved å sende en forespørsel til +servicedesk@altinn.no. \ No newline at end of file