Skip to content

Commit dfb6828

Browse files
Tsff 1205 seksjoner for redigerbar (#901)
utvidet tester med flere seksjoner. Trekker ut html Dropper <section...> i slutt resultatet da det er nøsted inni body. fjerner logo nytt endepunkt for editor. Editor svarer med original, redigert og tidligere redigert. deprekerer html felter fra valg endepunktet som nå erstattes av denne nye. renser og tillater kun predefinerte tags og attributter slik for å ha kontroll over output. Får lagre-renser og seksjonskonverter til å matche mer Inkluderer title på lenker * Legger på JsonCreator da enumen blir deserialisert fra kodeverdi. * ung-sak.openapi.json updated by build pipeline skip-checks:true --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 3c22188 commit dfb6828

File tree

19 files changed

+563
-60
lines changed

19 files changed

+563
-60
lines changed

behandlingslager/domene/src/main/java/no/nav/ung/sak/behandlingslager/formidling/VedtaksbrevValgRepository.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,19 @@ public List<VedtaksbrevValgEntitet> finnNyesteDeaktiverteVedtakbrevValg(Long beh
5858
.setParameter("behandlingId", behandlingId);
5959
return query.getResultList();
6060
}
61+
62+
public Optional<VedtaksbrevValgEntitet> finnNyesteDeaktiverteVedtakbrevValg(Long behandlingId, DokumentMalType dokumentMalType) {
63+
TypedQuery<VedtaksbrevValgEntitet> query = entityManager.createQuery(
64+
"SELECT v FROM VedtaksbrevValgEntitet v WHERE " +
65+
"v.behandlingId = :behandlingId " +
66+
"AND v.aktiv = false " +
67+
"AND v.dokumentMalType = :dokumentMalType " +
68+
"AND v.opprettetTidspunkt = (" +
69+
"SELECT MAX(v2.opprettetTidspunkt) FROM VedtaksbrevValgEntitet v2 WHERE v2.behandlingId = :behandlingId AND v2.aktiv = false AND v2.dokumentMalType = v.dokumentMalType" +
70+
")", VedtaksbrevValgEntitet.class)
71+
.setParameter("behandlingId", behandlingId)
72+
.setParameter("dokumentMalType", dokumentMalType);
73+
return HibernateVerktøy.hentUniktResultat(query);
74+
}
6175
}
6276

behandlingslager/domene/src/main/java/no/nav/ung/sak/behandlingslager/formidling/XhtmlBrevRenser.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import org.slf4j.LoggerFactory;
88

99
import java.nio.charset.StandardCharsets;
10-
import java.util.List;
1110
import java.util.Objects;
1211

1312
/**
@@ -22,9 +21,14 @@ public class XhtmlBrevRenser {
2221
.charset(StandardCharsets.UTF_8)
2322
.prettyPrint(false);
2423

25-
private static final List<String> SAFE_TAGS = List.of("b", "em", "i", "strong", "u", "br", "li", "ol", "p", "ul", "h1", "h2", "h3", "a");
24+
private static final Safelist SAFELIST = Safelist.none()
25+
.addTags(
26+
"b", "em", "i", "strong", "u", "br", "li", "ol", "p", "ul", "h1", "h2", "h3", "a"
27+
)
28+
.addAttributes("a", "href", "title")
29+
.addProtocols("a", "href", "http", "https");
30+
2631

27-
private static final Safelist SAFELIST = Safelist.none().addTags(SAFE_TAGS.toArray(new String[0]));
2832

2933
public static String rens(String input) {
3034
Objects.requireNonNull(input, "Input må være satt");

behandlingslager/domene/src/test/java/no/nav/ung/sak/behandlingslager/formidling/XhtmlBrevRenserTest.java

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,72 @@
88

99
class XhtmlBrevRenserTest {
1010

11-
private final XhtmlBrevRenser sanitizer = new XhtmlBrevRenser();
12-
1311
@Test
1412
void skal_gjøre_om_html_breakline_til_xhtml_breakline() {
15-
assertThat(sanitizer.rens("<br>")).isEqualTo("<br />");
13+
assertThat(rens("<br>")).isEqualTo("<br />");
1614
}
1715

1816
@Test
1917
void skal_avslutte_ulukkede_tagger() {
20-
assertThat(sanitizer.rens("<p>")).isEqualTo("<p></p>");
21-
assertThat(sanitizer.rens("</p>")).isEqualTo("<p></p>");
22-
assertThat(sanitizer.rens("0<i>1</p>2</i>3<p>4"))
18+
assertThat(rens("<p>")).isEqualTo("<p></p>");
19+
assertThat(rens("</p>")).isEqualTo("<p></p>");
20+
assertThat(rens("0<i>1</p>2</i>3<p>4"))
2321
.isEqualToIgnoringWhitespace("0 <i>1 <p></p> 2</i> 3 <p>4</p>");
2422
}
2523

2624
@Test
2725
void skal_funke_med_spesialtegn() {
28-
assertThat(sanitizer.rens("&")).isEqualTo("&amp;");
29-
assertThat(sanitizer.rens("<")).isEqualTo("&lt;");
30-
assertThat(sanitizer.rens(">")).isEqualTo("&gt;");
31-
assertThat(sanitizer.rens("[")).isEqualTo("[");
32-
assertThat(sanitizer.rens("]")).isEqualTo("]");
33-
assertThat(sanitizer.rens("&amp;")).isEqualTo("&amp;");
34-
assertThat(sanitizer.rens("&nbsp;")).isEqualTo("&#xa0;");
35-
assertThat(sanitizer.rens(" ")).isEqualTo("&#xa0;");
26+
assertThat(rens("&")).isEqualTo("&amp;");
27+
assertThat(rens("<")).isEqualTo("&lt;");
28+
assertThat(rens(">")).isEqualTo("&gt;");
29+
assertThat(rens("[")).isEqualTo("[");
30+
assertThat(rens("]")).isEqualTo("]");
31+
assertThat(rens("&amp;")).isEqualTo("&amp;");
32+
assertThat(rens("&nbsp;")).isEqualTo("&#xa0;");
33+
assertThat(rens(" ")).isEqualTo("&#xa0;");
3634

37-
sanitizer.rens("!\"#¤%/()=?`§\\;:<>*€¨^ +-;,è");
35+
rens("!\"#¤%/()=?`§\\;:<>*€¨^ +-;,è");
3836
}
3937

4038
@ParameterizedTest
4139
@ValueSource(strings = {"script", "style"})
4240
void skal_fjerne_innhold_og_tagg_i_ikke_støttede_kjente_html_tagger(String tag) {
43-
assertThat(sanitizer.rens("<" + tag + ">tekst inni en tagg</" + tag + ">")).isEqualTo("");
44-
assertThat(sanitizer.rens("<" + tag + ">")).isEqualTo("");
45-
assertThat(sanitizer.rens("</" + tag + ">")).isEqualTo("");
41+
assertThat(rens("<" + tag + ">tekst inni en tagg</" + tag + ">")).isEqualTo("");
42+
assertThat(rens("<" + tag + ">")).isEqualTo("");
43+
assertThat(rens("</" + tag + ">")).isEqualTo("");
4644
}
4745

4846
@Test
4947
void skal_fjerne_tagg_men_beholde_innhold_i_ukjente_tagger() {
5048
String text = "tekst inni en tagg";
51-
assertThat(sanitizer.rens("<FINNESIKKE>" + text + "</FINNESIKKE>")).isEqualTo(text);
52-
assertThat(sanitizer.rens("<![CDATA[" + text + "]]>")).isEqualTo(text);
53-
assertThat(sanitizer.rens("<FINNESIKKE>")).isEqualTo("");
54-
assertThat(sanitizer.rens("</FINNESIKKE>")).isEqualTo("");
49+
assertThat(rens("<FINNESIKKE>" + text + "</FINNESIKKE>")).isEqualTo(text);
50+
assertThat(rens("<![CDATA[" + text + "]]>")).isEqualTo(text);
51+
assertThat(rens("<FINNESIKKE>")).isEqualTo("");
52+
assertThat(rens("</FINNESIKKE>")).isEqualTo("");
5553
}
5654

5755
@Test
5856
void skal_fjerne_attributter_i_tagger() {
59-
assertThat(sanitizer.rens("<h1 class='overskrift' onclick='stealCookies()'>overskrift</h1>"))
57+
assertThat(rens("<h1 class='overskrift' onclick='stealCookies()'>overskrift</h1>"))
6058
.isEqualTo("<h1>overskrift</h1>");
61-
assertThat(sanitizer.rens("<a href=\"https://www.unsecure.com\">www.secure.com</a>"))
62-
.isEqualTo("<a>www.secure.com</a>");
59+
}
60+
61+
62+
@Test
63+
void skal_ikke_fjerne_href_og_title_attributter_for_lenker() {
64+
assertThat(rens("<a href=\"https://www.secure.com\" title=\"tittel\" rel=\"noreferrer\">www.secure.com</a>"))
65+
.isEqualTo("<a href=\"https://www.secure.com\" title=\"tittel\">www.secure.com</a>");
6366
}
6467

6568
@ParameterizedTest
6669
@ValueSource(strings = {"h1", "h2", "p"})
6770
void skal_ikke_fjerne_støttede_tagger(String tag) {
6871
String text = "tekst inni en tagg";
69-
assertThat(sanitizer.rens("<" + tag + ">" + text + "</" + tag + ">"))
72+
assertThat(rens("<" + tag + ">" + text + "</" + tag + ">"))
7073
.isEqualTo("<" + tag + ">" + text + "</" + tag + ">");
7174
}
75+
76+
private static String rens(String input) {
77+
return XhtmlBrevRenser.rens(input);
78+
}
7279
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package no.nav.ung.sak.formidling.vedtak;
2+
3+
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.editor.VedtaksbrevSeksjon;
4+
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.editor.VedtaksbrevSeksjonType;
5+
import org.jsoup.Jsoup;
6+
import org.jsoup.nodes.Document;
7+
import org.jsoup.nodes.Element;
8+
import org.jsoup.safety.Safelist;
9+
import org.jsoup.select.Elements;
10+
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
15+
public class BrevXhtmlTilSeksjonKonverter {
16+
private static final Safelist SAFELIST = Safelist.none()
17+
.addTags(
18+
"div",
19+
"p",
20+
"h1",
21+
"h2",
22+
"a",
23+
"span",
24+
"section",
25+
"header",
26+
"footer",
27+
"style",
28+
"table",
29+
"tr",
30+
"td"
31+
32+
)
33+
.addAttributes(":all", "class", "id")
34+
.addAttributes("div", "data-hidden", "data-editable")
35+
.addAttributes("a", "href", "title")
36+
.addAttributes("span", "class")
37+
.addAttributes(":all", "style")
38+
.addProtocols("a", "href", "http", "https");
39+
40+
41+
42+
public static List<VedtaksbrevSeksjon> konverter(String html) {
43+
List<VedtaksbrevSeksjon> seksjoner = new ArrayList<>();
44+
45+
// Parse HTML med Jsoup
46+
String clean = Jsoup.clean(html, "", SAFELIST);
47+
Document doc = Jsoup.parse(clean);
48+
doc.outputSettings(new Document.OutputSettings()
49+
.syntax(Document.OutputSettings.Syntax.xml)
50+
.charset(StandardCharsets.UTF_8)
51+
.prettyPrint(false));
52+
53+
// Del 1: Style - Trekk ut style taggen
54+
Element style = doc.selectFirst("style");
55+
if (style == null) {
56+
throw new IllegalArgumentException("Fant ingen styleelement");
57+
}
58+
59+
seksjoner.add(new VedtaksbrevSeksjon(VedtaksbrevSeksjonType.STYLE, style.outerHtml()));
60+
61+
Element header = doc.selectFirst("header");
62+
if (header == null) {
63+
throw new IllegalArgumentException("Fant ingen headerelement");
64+
}
65+
header.select("#nav_logo_container").remove();
66+
seksjoner.add(new VedtaksbrevSeksjon(VedtaksbrevSeksjonType.STATISK, header.outerHtml()));
67+
68+
Element editableDiv = doc.body().selectFirst("div[data-editable]");
69+
if (editableDiv == null) {
70+
throw new IllegalArgumentException("Fant ingen <div data-editable=...> element");
71+
}
72+
seksjoner.add(new VedtaksbrevSeksjon(VedtaksbrevSeksjonType.REDIGERBAR, editableDiv.html()));
73+
74+
Elements footer = editableDiv.nextElementSiblings();
75+
seksjoner.add(new VedtaksbrevSeksjon(VedtaksbrevSeksjonType.STATISK, footer.outerHtml()));
76+
77+
return seksjoner;
78+
}
79+
80+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package no.nav.ung.sak.formidling.vedtak;
2+
3+
import no.nav.ung.kodeverk.dokument.DokumentMalType;
4+
5+
public record VedtaksbrevForhåndsvisInput(
6+
Long behandlingId,
7+
DokumentMalType dokumentMalType,
8+
Boolean redigertVersjon,
9+
boolean htmlVersjon
10+
) {
11+
}

formidling/src/main/java/no/nav/ung/sak/formidling/vedtak/VedtaksbrevTjeneste.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.inject.Inject;
66
import no.nav.fpsak.tidsserie.LocalDateTimeline;
77
import no.nav.ung.kodeverk.KodeverdiSomObjekt;
8+
import no.nav.ung.kodeverk.dokument.DokumentMalType;
89
import no.nav.ung.sak.behandlingslager.behandling.repository.BehandlingRepository;
910
import no.nav.ung.sak.behandlingslager.formidling.VedtaksbrevValgEntitet;
1011
import no.nav.ung.sak.behandlingslager.formidling.VedtaksbrevValgRepository;
@@ -14,10 +15,12 @@
1415
import no.nav.ung.sak.formidling.vedtak.regler.Vedtaksbrev;
1516
import no.nav.ung.sak.formidling.vedtak.regler.VedtaksbrevReglerUng;
1617
import no.nav.ung.sak.formidling.vedtak.resultat.DetaljertResultat;
17-
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.VedtaksbrevForhåndsvisRequest;
1818
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.VedtaksbrevValg;
1919
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.VedtaksbrevValgRequest;
2020
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.VedtaksbrevValgResponse;
21+
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.editor.VedtaksbrevEditorResponse;
22+
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.editor.VedtaksbrevSeksjon;
23+
import no.nav.ung.sak.kontrakt.formidling.vedtaksbrev.editor.VedtaksbrevSeksjonType;
2124
import org.slf4j.Logger;
2225
import org.slf4j.LoggerFactory;
2326

@@ -96,7 +99,8 @@ private static VedtaksbrevValg mapVedtaksbrevValg(Vedtaksbrev resultat, Optional
9699
!erAvsluttet && egenskaper.kanOverstyreRediger(),
97100
resultat.forklaring(),
98101
redigertBrevHtml,
99-
tidligereRedigertTekst);
102+
tidligereRedigertTekst,
103+
redigertBrevHtml == null && deaktivertValg.isPresent());
100104
}
101105

102106
private static VedtaksbrevValgResponse mapIngenBrevResponse(BehandlingVedtaksbrevResultat totalResultat) {
@@ -113,7 +117,8 @@ private static VedtaksbrevValgResponse mapIngenBrevResponse(BehandlingVedtaksbre
113117
false,
114118
it.forklaring(),
115119
null,
116-
null
120+
null,
121+
false
117122
)).toList()
118123
);
119124
}
@@ -159,7 +164,7 @@ public VedtaksbrevValgEntitet lagreVedtaksbrev(VedtaksbrevValgRequest dto) {
159164

160165
}
161166

162-
public GenerertBrev forhåndsvis(VedtaksbrevForhåndsvisRequest dto) {
167+
public GenerertBrev forhåndsvis(VedtaksbrevForhåndsvisInput dto) {
163168
Long behandlingId = dto.behandlingId();
164169
BehandlingVedtaksbrevResultat totalresultater = vedtaksbrevRegler.kjør(behandlingId);
165170
validerHarBrev(totalresultater);
@@ -248,5 +253,35 @@ public void ryddVedTilbakeHopp(Long behandlingId) {
248253

249254

250255
}
256+
257+
public VedtaksbrevEditorResponse editor(Long behandlingId, DokumentMalType dokumentMalType) {
258+
GenerertBrev forhåndsvis = forhåndsvis(new VedtaksbrevForhåndsvisInput(
259+
behandlingId,
260+
dokumentMalType,
261+
false,
262+
true
263+
));
264+
265+
List<VedtaksbrevSeksjon> original = BrevXhtmlTilSeksjonKonverter.konverter(forhåndsvis.dokument().html());
266+
List<VedtaksbrevSeksjon> redigert = vedtaksbrevValgRepository.finnVedtakbrevValg(behandlingId, dokumentMalType)
267+
.filter(VedtaksbrevValgEntitet::isRedigert)
268+
.map(it -> erstattRedigerBar(original, it.getRedigertBrevHtml()))
269+
.orElse(null);
270+
271+
List<VedtaksbrevSeksjon> tidligereRedigert = redigert == null ?
272+
vedtaksbrevValgRepository.finnNyesteDeaktiverteVedtakbrevValg(behandlingId, dokumentMalType)
273+
.map(it -> erstattRedigerBar(original, it.getRedigertBrevHtml()))
274+
.orElse(null)
275+
: null;
276+
277+
return new VedtaksbrevEditorResponse(original, redigert, tidligereRedigert);
278+
}
279+
280+
private List<VedtaksbrevSeksjon> erstattRedigerBar(List<VedtaksbrevSeksjon> original, String redigertBrevHtml) {
281+
return original.stream().map(it ->
282+
it.type() == VedtaksbrevSeksjonType.REDIGERBAR ?
283+
new VedtaksbrevSeksjon(VedtaksbrevSeksjonType.REDIGERBAR, redigertBrevHtml) : it)
284+
.toList();
285+
}
251286
}
252287

formidling/src/main/resources/pdfgen/templates/felles/footer/footer.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<p>Du finner mer informasjon på <a title="ungdomsprogrammet" href="https://nav.no/ungdomsprogrammet">nav.no/ungdomsprogrammet</a>.
33
</p>
44

5-
<p>På <a href="https://nav.no/kontakt">nav.no/kontakt</a> kan du chatte eller skrive til oss. </p>
5+
<p>På <a title="kontakt" href="https://nav.no/kontakt" >nav.no/kontakt</a> kan du chatte eller skrive til oss. </p>
66

77
<p>Hvis du ikke finner svar på nav.no kan du ringe oss på telefon 55 55 33 33, hverdager 09:00-15:00.</p>
88

formidling/src/main/resources/pdfgen/templates/ungdomsprogramytelse/innvilgelse.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
</p>
4242

4343
<p>
44-
Du finner mer informasjon om utbetalingen hvis du <a href="https://www.nav.no/min-side">logger inn på Min
44+
Du finner mer informasjon om utbetalingen hvis du <a href="https://www.nav.no/min-side" title="min side">logger inn på Min
4545
side på nav.no</a>.
4646
</p>
4747

0 commit comments

Comments
 (0)