Skip to content
Snippets Groups Projects
Commit a8018ff4 authored by Jan Zickermann's avatar Jan Zickermann
Browse files

OZG-4095 Render html as plaintext with jsoup

parent 683d679c
Branches
Tags
2 merge requests!12Ozg 4095 abrufen aller nachrichten html,!11Ozg 4095 abrufen aller nachrichten
......@@ -22,6 +22,7 @@
<openapi-generator.version>7.10.0</openapi-generator.version>
<swagger-parser.version>2.1.23</swagger-parser.version>
<wiremock-spring-boot.version>3.6.0</wiremock-spring-boot.version>
<jsoup.version>1.18.3</jsoup.version>
</properties>
<dependencies>
<!-- OZG-Cloud -->
......@@ -59,6 +60,11 @@
<artifactId>swagger-parser</artifactId>
<version>${swagger-parser.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<!-- test -->
<dependency>
......
package de.ozgcloud.nachrichten.postfach.osiv2.transfer;
import java.util.List;
import java.util.function.Function;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public record Osi2HtmlDocument(String html) {
private record SpanRendering(String tag, Function<Element, String> markdownReplacement) {
static SpanRendering of(String tag, Function<Element, String> markdownReplacement) {
return new SpanRendering(tag, markdownReplacement);
}
void replaceElementsWithMarkdownSpansIn(Document document) {
document.body()
.select(tag)
.replaceAll(anchor -> new Element("span")
.text(markdownReplacement.apply(anchor))
);
}
}
static final List<SpanRendering> SPAN_RENDERINGS = List.of(
SpanRendering.of("h1", heading -> "# " + heading.text()),
SpanRendering.of("h2", heading -> "## " + heading.text()),
SpanRendering.of("h3", heading -> "### " + heading.text()),
SpanRendering.of("i", italic -> "*" + italic.text() + "*"),
SpanRendering.of("em", italic -> "*" + italic.text() + "*"),
SpanRendering.of("b", bold -> "**" + bold.text() + "**"),
SpanRendering.of("strong", bold -> "**" + bold.text() + "**"),
SpanRendering.of("img", image -> "![" + image.attr("alt") + "](" + image.attr("src") + ")"),
SpanRendering.of("a", anchor -> "[" + anchor.text() + "](" + anchor.attr("href") + ")"),
SpanRendering.of("blockquote", bold -> "> " + bold.wholeText())
);
public String renderHTMLToPlainText() {
var document = Jsoup.parse(html);
addNewlinesForSubsequentParagraphs(document);
replaceElementsWithMarkdownSpansIn(document);
return document.wholeText();
}
private void addNewlinesForSubsequentParagraphs(Document document) {
document.body()
.select("p + p")
.prepend("\n");
}
private void replaceElementsWithMarkdownSpansIn(Document document) {
for (var entry : SPAN_RENDERINGS) {
entry.replaceElementsWithMarkdownSpansIn(document);
}
}
public static String renderPlainText(String html) {
return new Osi2HtmlDocument(html).renderHTMLToPlainText();
}
}
......@@ -2,6 +2,7 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer;
import java.time.ZoneOffset;
import org.jsoup.Jsoup;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
......@@ -15,7 +16,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage;
import lombok.Builder;
import lombok.Getter;
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR, imports = ZoneOffset.class)
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR, imports = { ZoneOffset.class, Osi2HtmlDocument.class })
public interface Osi2ResponseMapper {
String POSTFACH_ADDRESS_VERSION = "2.0";
......@@ -32,7 +33,7 @@ public interface Osi2ResponseMapper {
@Mapping(target = "direction", constant = "IN")
@Mapping(target = "vorgangId", source = "sequencenumber")
@Mapping(target = "referencedNachricht", ignore = true)
@Mapping(target = "mailBody", source = "body")
@Mapping(target = "mailBody", expression = "java( message.getIsHtml() ? Osi2HtmlDocument.renderPlainText(message.getBody()) : message.getBody() )")
@Mapping(target = "replyOption", source = "replyAction")
@Mapping(target = "attachments", ignore = true)
PostfachNachricht toPostfachNachricht(V1ReplyMessage message);
......
......@@ -12,7 +12,11 @@ public class V1ReplyMessageTestFactory {
private static final String SEQUENCE_NUMMER = "OZG-Cloud-VorgangId";
private static final String SUBJECT = "Das ist das Subject";
private static final String BODY = """
Das ist das Multiline
Das ist das Multiline&amp;<br><br/>
Body""";
private static final String CLEAN_BODY = """
Das ist das Multiline&
Body""";
private static final String DISPLAY_NAME = "Das ist der Absender";
private static final String ORIGIN_SENDER = "das ist der original Sender";
......
package de.ozgcloud.nachrichten.postfach.osiv2.transfer;
import static org.assertj.core.api.AssertionsForInterfaceTypes.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class Osi2HtmlDocumentTest {
@DisplayName("should render anchor link")
@Test
void shouldRenderAnchorLink() {
var plainText = renderPlainText("<a href=\"https://www.example.com\">Example</a>");
assertThat("[Example](https://www.example.com)").isEqualTo(plainText);
}
@DisplayName("should render h1 heading")
@Test
void shouldRenderH1Heading() {
var plainText = renderPlainText("<h1>Example</h1>");
assertThat(plainText).isEqualTo("# Example");
}
@DisplayName("should render h2 heading")
@Test
void shouldRenderH2Heading() {
var plainText = renderPlainText("<h2>Example</h2>");
assertThat(plainText).isEqualTo("## Example");
}
@DisplayName("should render h3 heading")
@Test
void shouldRenderH3Heading() {
var plainText = renderPlainText("<h3>Example</h3>");
assertThat(plainText ).isEqualTo("### Example");
}
@DisplayName("should render italic")
@ParameterizedTest
@ValueSource(strings = { "<i>Example</i>", "<em>Example</em>" })
void shouldRenderItalic(String italicExample) {
var plainText = renderPlainText(italicExample);
assertThat(plainText).isEqualTo("*Example*");
}
@DisplayName("should render bold")
@ParameterizedTest
@ValueSource(strings = { "<b>Example</b>", "<strong>Example</strong>" })
void shouldRenderBold(String boldExample) {
var plainText = renderPlainText(boldExample);
assertThat(plainText).isEqualTo("**Example**");
}
@DisplayName("should render image")
@Test
void shouldRenderImage() {
var plainText = renderPlainText("<img src=\"https://www.example.com/image.jpg\" alt=\"Example\">");
assertThat(plainText).isEqualTo("![Example](https://www.example.com/image.jpg)");
}
@DisplayName("should render blockquote")
@Test
void shouldRenderBlockquote() {
var plainText = renderPlainText("<blockquote><p>Example</p><p>Example2</p></blockquote>");
assertThat(plainText).isEqualTo("> Example\nExample2");
}
@DisplayName("should render html")
@Test
void shouldRenderHtml() {
var plainText = renderPlainText("<p>Example&#128566;</p><br/><p>Example2</p><b>");
assertThat(plainText).isEqualTo("Example\uD83D\uDE36\nExample2****");
}
private String renderPlainText(String html) {
return new Osi2HtmlDocument(html).renderHTMLToPlainText();
}
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ class Osi2ResponseMapperTest {
@InjectMocks
private Osi2ResponseMapper mapper = Mappers.getMapper(Osi2ResponseMapper.class);
private V1ReplyMessage message = V1ReplyMessageTestFactory.create();
private final V1ReplyMessage message = V1ReplyMessageTestFactory.create();
@DisplayName("map V1ReplyMessage to PostfachNachricht")
@Nested
......@@ -91,6 +91,15 @@ class Osi2ResponseMapperTest {
Body""");
}
@Test
void shouldMapHTMLBody(){
var postfachNachricht = mapper.toPostfachNachricht(message.isHtml(true));
assertThat(postfachNachricht.getMailBody()).isEqualTo("""
Das ist das Multiline
Body""");
}
@Test
void shouldHaveReplyOption(){
var postfachNachricht = mapper.toPostfachNachricht(message);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment