This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 80cca2039a5b0e3216fbc5de210e7ca742578f67
Author: TungTV <vtt...@linagora.com>
AuthorDate: Wed Nov 27 15:43:52 2024 +0700

    JAMES-4077 SearchHighlight support search on html_body field
---
 .../searchhighligt/SearchHighLighterContract.java  |  30 ++-
 .../search/OpenSearchSearchHighlighter.java        |   1 +
 .../opensearch/search/OpenSearchSearcher.java      |   1 +
 .../src/main/resources/eml/html_body.eml           | 240 +++++++++++++++++++++
 .../contract/SearchSnippetGetMethodContract.scala  |  93 +++++++-
 5 files changed, 363 insertions(+), 2 deletions(-)

diff --git 
a/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java
 
b/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java
index 8083639e87..2181140be9 100644
--- 
a/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java
+++ 
b/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.mailbox.searchhighligt;
 
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
 
@@ -37,6 +36,7 @@ import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
 import org.apache.james.mailbox.model.SearchQuery;
 import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.message.MultipartBuilder;
 import org.apache.james.util.ClassLoaderUtils;
 import org.junit.jupiter.api.Test;
 
@@ -504,4 +504,32 @@ public interface SearchHighLighterContract {
             .isPresent()
             .satisfies(highlightedBody -> 
assertThat(highlightedBody.get()).contains("This is a <mark>beautiful</mark> 
banana"));
     }
+
+    @Test
+    default void shouldHighLightBodyWhenHTMLBodyMatched() throws Exception {
+        Message message1 = Message.Builder.of()
+            .setBody(MultipartBuilder.create("report")
+                .addBinaryPart("content <b>barcamp</b> <i>HTML</i> 
xinchao".getBytes(StandardCharsets.UTF_8), "text/html")
+                .build())
+            .build();
+        MailboxSession session = session(USERNAME1);
+        ComposedMessageId m1 = 
appendMessage(MessageManager.AppendCommand.from(message1), session).getId();
+
+        verifyMessageWasIndexed(1);
+
+        MultimailboxesSearchQuery multiMailboxSearch = 
MultimailboxesSearchQuery.from(SearchQuery.of(
+                SearchQuery.bodyContains("barcamp")))
+            .inMailboxes(List.of(m1.getMailboxId()))
+            .build();
+
+        List<SearchSnippet> searchSnippets = 
Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), 
multiMailboxSearch, session))
+            .collectList()
+            .block();
+        assertThat(searchSnippets).hasSize(1);
+        assertSoftly(softly -> {
+            
softly.assertThat(searchSnippets.getFirst().messageId()).isEqualTo(m1.getMessageId());
+            
softly.assertThat(searchSnippets.getFirst().highlightedBody()).isPresent();
+            
softly.assertThat(searchSnippets.getFirst().highlightedBody().get()).contains("<mark>barcamp</mark>");
+        });
+    }
 }
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearchHighlighter.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearchHighlighter.java
index 2c69bc8ccc..1454c7ab2d 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearchHighlighter.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearchHighlighter.java
@@ -88,6 +88,7 @@ public class OpenSearchSearchHighlighter implements 
SearchHighlighter {
         Optional<String> highlightedSubject =  
Optional.ofNullable(highlightHit.get(JsonMessageConstants.SUBJECT))
             .map(List::getFirst);
         Optional<String> highlightedTextBody = 
Optional.ofNullable(highlightHit.get(JsonMessageConstants.TEXT_BODY))
+            .or(() -> 
Optional.ofNullable(highlightHit.get(JsonMessageConstants.HTML_BODY)))
             .or(() -> 
Optional.ofNullable(highlightHit.get(ATTACHMENT_TEXT_CONTENT_FIELD)))
             .map(List::getFirst);
 
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
index 09f1524de4..f15d8e1b60 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
@@ -86,6 +86,7 @@ public class OpenSearchSearcher {
         this.highlightQuery = new Highlight.Builder()
             .fields(JsonMessageConstants.SUBJECT, highlightField)
             .fields(JsonMessageConstants.TEXT_BODY, highlightField)
+            .fields(JsonMessageConstants.HTML_BODY, highlightField)
             .fields(ATTACHMENT_TEXT_CONTENT_FIELD, highlightField)
             .build();
     }
diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/html_body.eml
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/html_body.eml
new file mode 100644
index 0000000000..fb71b99374
--- /dev/null
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/html_body.eml
@@ -0,0 +1,240 @@
+Return-Path: <hm...@example.com>
+org.apache.james.rspamd.flag: NO
+org.apache.james.rspamd.status: No, actions=no action score=0.0 
requiredScore=15.0
+Delivered-To: dphamho...@example.com
+Received: from 172.17.0.1 (EHLO incoming.example.com) ([172.17.0.1])
+          by incoming.example.com (JAMES SMTP Server ) with ESMTP ID c8ca0690;
+          Wed, 10 May 2022 03:16:53 +0000 (UTC)
+Received: from smtp.example.com (smtp.example.com [54.36.8.78])
+       by incoming.example.com (Postfix) with ESMTPS id 48A1C9C401;
+       Wed, 10 May 2022 03:16:53 +0000 (UTC)
+Received: from ?Open?PaaS?SMTP?server?for?example? (unknown [51.83.109.124])
+       (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+       (No client certificate requested)
+       by smtp.example.com (Postfix) with ESMTPSA id 0F0B73EE62;
+       Wed, 10 May 2022 05:16:54 +0200 (CEST)
+DKIM-Signature: a=rsa-sha256; 
b=clyJAm7d7I1D+H1Q9461DlJT10TYuocQAkK0z1ybeYYKqrjax6BjH3t+Cxkq/B1qt5hibD6Hg9rSVKMn6nG8ye3ghzYSGJg5CYNl/ozEWIUM976+JVpf2qDmTlukRzs25GAESKeBt0UTmsn6lusiXtf0kR5hWr0j8ryT5Z8UpzaaLlnMtWBXvx3mQzVltj7OTyd4mx8JRiZE5bV65dS1S0SZOmp9iCEq9+vNQaL3M3m6N7s1xGV2J5Htz7tRVy3NWczJdDVtRHY0u3xJNetYjSVbzxCsciqPy+xSFYj1DHyPMVqVjLGxALBpJ953qFBZi4d17D9BfRONbg6yCmbxkg==;
 s=smtpoutjames; d=example.com; v=1; 
bh=A/3l3MmJvs/qsqAqSuiuPhfTOrrap3TVn5YAOKn155E=; h=from : reply-to : subject : 
[...]
+MIME-Version: 1.0
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+X-example-Copy-Delivery-Done: 1
+From: Ha Minh Anh VU <hm...@example.com>
+Sender: Ha Minh Anh VU <hm...@example.com>
+Reply-To: hm...@example.com
+To: Anton SHEPILOV <ashepi...@example.com>
+Cc: Dat PHAM HOANG <dphamho...@example.com>, The Dat VU
+ <t...@example.com>, VN HR <v...@example.com>,
+ =?ISO-8859-1?Q?Beno=EEt_TELLIER?= <btell...@example.com>
+Subject: Re: Cong hoa Xa Hoi Chu Nghia Viet Nam
+Message-ID: <mime4j.7a.a9c00d8d7ab83180.18803a95...@example.com>
+Date: Wed, 10 May 2022 03:16:50 +0000
+References: <mime4j.671.1acd13bc529da6f9.187fa2ec...@example.com>
+ <mime4j.49.89784d872ecab223.1880019b...@example.com>
+
+<p>Dear Anton, </p><p>Can we arrange an interview for you and XXXXXXXXXXXX =
+XXXXXXXXXXXX Developer at 04 p=2Em (Paris Time) on this Thursday (11/05/202=
+3)?</p><p>If you are not available at that time, kindly suggest us your ava=
+ilable time</p><p>Thank you &amp; Best regards,</p><div class=3D"openpaas-s=
+ignature">-- 
+<p><span style=3D"color:rgb(51, 51, 51);">Vu Ha Minh Anh (Ms)=
+&nbsp;</span><br style=3D"color:rgb(51, 51, 51);"><span style=3D"color:rgb(=
+51, 51, 51);">HR Department&nbsp;</span><br style=3D"color:rgb(51, 51, 51);=
+"><font color=3D"#9c0000"><b>example VIETNAM</b></font><br style=3D"color:=
+rgb(51, 51, 51);"><span style=3D"color:rgb(51, 51, 51);">5 Dien Bien Phu St=
+r=2E, Ba Dinh Dist=2E, Ha Noi</span><br style=3D"color:rgb(51, 51, 51);"><s=
+pan style=3D"color:rgb(51, 51, 51);">(+84) 901735987&nbsp;</span><br style=
+=3D"color:rgb(51, 51, 51);"><font color=3D"#424242">https://example=2Evn</=
+font><br></p></div><cite>On May 10, 2023 6:35 AM, from gagagagagaga@example=
+=2Ecom</cite><blockquote>Hi Anton,&nbsp;<div><br></div><div>Because at that=
+ time, before the barcamp, we was considering about the Matrix, about organ=
+ization, =E2=80=A6 so we postponed the process=2E&nbsp;</div><div>At the mo=
+ment, when we need people for TDrive, Twake and maybe Timex Yen re-launch t=
+he process with this potential candidate=2E</div><div><br></div><div>Thanks=
+ and BRs=2E<br><div><br><blockquote type=3D"cite"><div>On 9 May 2022, at 17=
+:41, Anton SHEPILOV &lt;ashepilov@example=2Ecom&gt; wrote:</div><br class=
+=3D"x_Apple-interchange-newline"><div><p>Yes, let's have an interview with =
+hime</p><p>@Dat and whats happened two months ago? Why we didn't hire him?<=
+/p><cite>On May 8, 2022 9:39 AM, from dphamhoang@example=2Ecom</cite><bloc=
+kquote>Hi Anton,<div><br></div><div>This is Minh, a candidate who we had th=
+e interview more than 2 months ago=2E</div><div>We scanned him on the skill=
+ of technical:</div><div>&nbsp;- More than 2 years experience in Flutter=2E=
+ But not too much experience in Flutter web</div><div>&nbsp;- Good knowledg=
+e in Android and React Native=2E</div><div>&nbsp;- Have good attitude in wo=
+rk</div><div><br></div><div>If you agree with this guys, please scan him mo=
+re in your side, IMO, it is a good candidate for not only TDrive, TMail and=
+ Twake=2E</div><div><br></div><div>Thanks and BRs=2E</div><div><div><br><bl=
+ockquote type=3D"cite"><div>On 8 May 2022, at 14:06, Hoang Yen &lt;tyhoang@=
+example=2Ecom&gt; wrote:</div><br class=3D"x_x_Apple-interchange-newline">=
+<div><p>Dear Anton,</p><p>Please check the CVs_Flutter below=2E He had alre=
+ady interviewed with Dat Pham &amp; Dat Pham says <b>big GO </b>with him</p=
+><p><b>He will replace Manh_Flutter dev (just resigned in company on April,=
+2022)=2E</b>&nbsp;</p><p>For more info, kindly check with Dat Pham=2E <b>@D=
+at:</b> kindly give us your feedback about techinal, culture,=2E=2E=2Eof th=
+is candidates to follow=2E</p><p><b>@Anton</b>: kindly give us your decisio=
+n soon!</p><p>Thank you so much!</p><div class=3D"x_x_tmail-signature">--<b=
+r><p><span style=3D"color: rgb(51, 51, 51); font-family: roboto; font-size:=
+ 13px; background-color: rgb(255, 255, 255);">HOANG Thi Yen (Ms)&nbsp;</spa=
+n><br style=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased;=
+ color: rgb(51, 51, 51); font-family: roboto; font-size: 13px; background-c=
+olor: rgb(255, 255, 255); outline: none !important; -webkit-tap-highlight-c=
+olor: rgba(0, 0, 0, 0) !important;"><span style=3D"color: rgb(51, 51, 51); =
+font-family: roboto; font-size: 13px; background-color: rgb(255, 255, 255);=
+">HR department&nbsp;</span><br style=3D"box-sizing: border-box; -webkit-fo=
+nt-smoothing: antialiased; color: rgb(51, 51, 51); font-family: roboto; fon=
+t-size: 13px; background-color: rgb(255, 255, 255); outline: none !importan=
+t; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;"><font color=
+=3D"#9c0000" style=3D"box-sizing: border-box; -webkit-font-smoothing: antia=
+liased; font-family: roboto; font-size: 13px; background-color: rgb(255, 25=
+5, 255); outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, =
+0, 0) !important;"><b style=3D"box-sizing: border-box; -webkit-font-smoothi=
+ng: antialiased; outline: none !important; -webkit-tap-highlight-color: rgb=
+a(0, 0, 0, 0) !important;">example VIETNAM</b></font><br style=3D"box-sizi=
+ng: border-box; -webkit-font-smoothing: antialiased; color: rgb(51, 51, 51)=
+; font-family: roboto; font-size: 13px; background-color: rgb(255, 255, 255=
+); outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) =
+!important;"><span style=3D"color: rgb(51, 51, 51); font-family: roboto; fo=
+nt-size: 13px; background-color: rgb(255, 255, 255);">5 Dien Bien Phu Str=
+=2E, Ba Dinh Dist=2E, Ha Noi</span><br style=3D"box-sizing: border-box; -we=
+bkit-font-smoothing: antialiased; color: rgb(51, 51, 51); font-family: robo=
+to; font-size: 13px; background-color: rgb(255, 255, 255); outline: none !i=
+mportant; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;"><span =
+style=3D"color: rgb(51, 51, 51); font-family: roboto; font-size: 13px; back=
+ground-color: rgb(255, 255, 255);">(+84) 372019465</span><br style=3D"box-s=
+izing: border-box; -webkit-font-smoothing: antialiased; color: rgb(51, 51, =
+51); font-family: roboto; font-size: 13px; background-color: rgb(255, 255, =
+255); outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, =
+0) !important;"><font color=3D"#424242" style=3D"box-sizing: border-box; -w=
+ebkit-font-smoothing: antialiased; font-family: roboto; font-size: 13px; ba=
+ckground-color: rgb(255, 255, 255); outline: none !important; -webkit-tap-h=
+ighlight-color: rgba(0, 0, 0, 0) !important;">https://example=2Evn</font><=
+br></p><br></div><cite>On Mar 15, 2022 4:08 PM, from Thi Yen Hoang </cite><=
+blockquote style=3D"margin-left:8px;margin-right:8px;padding-left:12px;padd=
+ing-right:12px;border-left:5px solid #eee;"><p><span style=3D"color: rgb(51=
+, 51, 51); font-size: 16=2E25px;">Dear Dat,</span><br></p><p style=3D"box-s=
+izing: border-box; -webkit-font-smoothing: antialiased; outline: none !impo=
+rtant; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; margin: 0p=
+x 0px 20px; font-family: roboto; font-size: 13px; font-style: normal; font-=
+variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; let=
+ter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-=
+transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit=
+-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoratio=
+n-style: initial; text-decoration-color: initial; color: rgb(51, 51, 51); b=
+ackground-color: rgb(255, 255, 255);"><span style=3D"box-sizing: border-box=
+; -webkit-font-smoothing: antialiased; outline: none !important; -webkit-ta=
+p-highlight-color: rgba(0, 0, 0, 0) !important; font-size: 16=2E25px; color=
+: hsl(var(--text-color-h), var(--text-color-s), var(--text-color-l));">Plea=
+se help to scan the profile attached and let me know your feedback soon=2E<=
+/span></p><p style=3D"box-sizing: border-box; -webkit-font-smoothing: antia=
+liased; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0=
+, 0) !important; margin: 0px 0px 20px; font-family: roboto; font-size: 13px=
+; font-style: normal; font-variant-ligatures: normal; font-variant-caps: no=
+rmal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: sta=
+rt; text-indent: 0px; text-transform: none; white-space: normal; widows: 2;=
+ word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickne=
+ss: initial; text-decoration-style: initial; text-decoration-color: initial=
+; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);"><span styl=
+e=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; outline: =
+none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; =
+color: rgb(51, 51, 51); font-size: 16=2E25px;">Please kindly refer to some =
+highlights:</span></p><ul style=3D"box-sizing: border-box; -webkit-font-smo=
+othing: antialiased; outline: none !important; -webkit-tap-highlight-color:=
+ rgba(0, 0, 0, 0) !important; margin-top: 0px; margin-bottom: 9px; font-fam=
+ily: roboto; font-size: 13px; font-style: normal; font-variant-ligatures: n=
+ormal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal;=
+ orphans: 2; text-align: start; text-indent: 0px; text-transform: none; whi=
+te-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: =
+0px; text-decoration-thickness: initial; text-decoration-style: initial; te=
+xt-decoration-color: initial; color: rgb(51, 51, 51); background-color: rgb=
+(255, 255, 255);"><li style=3D"box-sizing: border-box; -webkit-font-smoothi=
+ng: antialiased; outline: none !important; -webkit-tap-highlight-color: rgb=
+a(0, 0, 0, 0) !important; background-color: rgb(255, 255, 255);"><span styl=
+e=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; outline: =
+none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;"=
+><font style=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased=
+; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !=
+important; color: rgb(51, 51, 51); font-family: roboto; font-size: 13px; fo=
+nt-style: normal; font-variant-ligatures: normal; font-variant-caps: normal=
+; font-weight: 400; letter-spacing: normal; text-transform: none; white-spa=
+ce: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" color=3D"#3=
+33333"><span style=3D"box-sizing: border-box; -webkit-font-smoothing: antia=
+liased; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0=
+, 0) !important; font-size: 16=2E25px;"><b style=3D"box-sizing: border-box;=
+ -webkit-font-smoothing: antialiased; outline: none !important; -webkit-tap=
+-highlight-color: rgba(0, 0, 0, 0) !important; font-weight: bold;">He got B=
+achelor with major in Electronics and Telecommunications</b></span></font><=
+font style=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; =
+outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !im=
+portant;" color=3D"#333333"><span style=3D"box-sizing: border-box; -webkit-=
+font-smoothing: antialiased; outline: none !important; -webkit-tap-highligh=
+t-color: rgba(0, 0, 0, 0) !important;"><span style=3D"box-sizing: border-bo=
+x; -webkit-font-smoothing: antialiased; outline: none !important; -webkit-t=
+ap-highlight-color: rgba(0, 0, 0, 0) !important;"><span style=3D"box-sizing=
+: border-box; -webkit-font-smoothing: antialiased; outline: none !important=
+; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; font-size: 16=
+=2E25px;"><b style=3D"box-sizing: border-box; -webkit-font-smoothing: antia=
+liased; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0=
+, 0) !important; font-weight: bold;">- Hanoi University of science and tech=
+nology</b></span></span></span></font></span></li><li style=3D"box-sizing: =
+border-box; -webkit-font-smoothing: antialiased; outline: none !important; =
+-webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; color: rgb(51, 51=
+, 51); font-family: roboto; font-size: 13px; font-style: normal; font-varia=
+nt-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-s=
+pacing: normal; text-transform: none; white-space: normal; word-spacing: 0p=
+x; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);"><=
+b style=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; out=
+line: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !impor=
+tant; font-weight: bold; color: rgb(51, 51, 51); font-family: roboto; font-=
+size: 16=2E25px; font-style: normal; font-variant-ligatures: normal; font-v=
+ariant-caps: normal; letter-spacing: normal; text-transform: none; white-sp=
+ace: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">He has mor=
+e than 4 years of experience in MB development,&nbsp;especially in Android =
+native/Flutter/React native development=2E</b></li><li style=3D"box-sizing:=
+ border-box; -webkit-font-smoothing: antialiased; outline: none !important;=
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; color: rgb(51, 5=
+1, 51); font-family: roboto; font-size: 13px; font-style: normal; font-vari=
+ant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-=
+spacing: normal; text-transform: none; white-space: normal; word-spacing: 0=
+px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);">=
+<b style=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; ou=
+tline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !impo=
+rtant; font-weight: bold; font-size: 16=2E25px;">He opens to new opportunit=
+ies</b></li><li style=3D"box-sizing: border-box; -webkit-font-smoothing: an=
+tialiased; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0=
+, 0, 0) !important; color: rgb(51, 51, 51); font-family: roboto; font-size:=
+ 16=2E25px; font-style: normal; font-variant-ligatures: normal; font-varian=
+t-caps: normal; font-weight: 400; letter-spacing: normal; text-transform: n=
+one; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px=
+; background-color: rgb(255, 255, 255);"><b style=3D"box-sizing: border-box=
+; -webkit-font-smoothing: antialiased; outline: none !important; -webkit-ta=
+p-highlight-color: rgba(0, 0, 0, 0) !important; font-weight: bold;">He can =
+communicate in English (level: fluent)</b></li></ul><p><br></p><p style=3D"=
+box-sizing: border-box; -webkit-font-smoothing: antialiased; outline: none =
+!important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; margi=
+n: 0px 0px 20px; font-family: roboto; font-size: 13px; font-style: normal; =
+font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400=
+; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; =
+text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -w=
+ebkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-deco=
+ration-style: initial; text-decoration-color: initial; color: rgb(51, 51, 5=
+1); background-color: rgb(255, 255, 255);"><span style=3D"box-sizing: borde=
+r-box; -webkit-font-smoothing: antialiased; outline: none !important; -webk=
+it-tap-highlight-color: rgba(0, 0, 0, 0) !important; font-size: 16=2E25px;"=
+>If you need further information, please kindly let me know=2E</span><br st=
+yle=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; outline=
+: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important=
+;"></p><p style=3D"box-sizing: border-box; -webkit-font-smoothing: antialia=
+sed; outline: none !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0=
+) !important; margin: 0px 0px 20px; font-family: roboto; font-size: 13px; f=
+ont-style: normal; font-variant-ligatures: normal; font-variant-caps: norma=
+l; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start;=
+ text-indent: 0px; text-transform: none; white-space: normal; widows: 2; wo=
+rd-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness:=
+ initial; text-decoration-style: initial; text-decoration-color: initial; c=
+olor: rgb(51, 51, 51); background-color: rgb(255, 255, 255);"><span style=
+=3D"box-sizing: border-box; -webkit-font-smoothing: antialiased; outline: n=
+one !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; f=
+ont-size: 16=2E25px;">Best regards,</span></p></blockquote><span id=3D"x_x_=
+cid:3D4F0954-2788-487E-8533-2D6C65A93912">&lt;CV_2022=2E03_W11_XXXXXX XXXXX=
+ XXXX_Mobile_FB=2Epdf&gt;</span></div></blockquote></div><br></div></blockq=
+uote>
+</div></blockquote></div><br></div></blockquote>
diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SearchSnippetGetMethodContract.scala
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SearchSnippetGetMethodContract.scala
index f25a1d7d2c..7246e6a80e 100644
--- 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SearchSnippetGetMethodContract.scala
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SearchSnippetGetMethodContract.scala
@@ -36,9 +36,10 @@ import 
org.apache.james.jmap.rfc8621.contract.probe.DelegationProbe
 import org.apache.james.mailbox.MessageManager.AppendCommand
 import org.apache.james.mailbox.model.MailboxACL.Right
 import org.apache.james.mailbox.model.MailboxPath.inbox
-import org.apache.james.mailbox.model.{MailboxACL, MailboxPath, MessageId}
+import org.apache.james.mailbox.model.{MailboxACL, MailboxId, MailboxPath, 
MessageId}
 import org.apache.james.mime4j.dom.Message
 import org.apache.james.modules.{ACLProbeImpl, MailboxProbeImpl}
+import org.apache.james.util.ClassLoaderUtils
 import org.apache.james.utils.DataProbeImpl
 import org.assertj.core.api.Assertions.assertThat
 import org.awaitility.Awaitility
@@ -996,4 +997,94 @@ trait SearchSnippetGetMethodContract {
            |]""".stripMargin)
   }
 
+
+  @Test
+  def shouldReturnMatchingResultWhenSearchSnippetInHTMLBody(server: 
GuiceJamesServer): Unit = {
+    val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
+    val inboxId: MailboxId = mailboxProbe.createMailbox(MailboxPath.inbox(BOB))
+    val messageId1: MessageId = mailboxProbe
+      .appendMessage(BOB.asString(), MailboxPath.inbox(BOB), 
AppendCommand.from(
+        ClassLoaderUtils.getSystemResourceAsSharedStream("eml/html_body.eml")))
+      .getMessageId
+
+    val keywordSearch: String = "barcamp"
+
+    val request: String =
+      s"""{
+         |    "using": [
+         |        "urn:ietf:params:jmap:core",
+         |        "urn:ietf:params:jmap:mail"
+         |    ],
+         |    "methodCalls": [
+         |        [
+         |            "Email/query",
+         |            {
+         |                "accountId": "$ACCOUNT_ID",
+         |                "filter": {
+         |                    "body": "$keywordSearch"
+         |                },
+         |                "sort": [
+         |                    {
+         |                        "isAscending": false,
+         |                        "property": "receivedAt"
+         |                    }
+         |                ],
+         |                "limit": 20
+         |            },
+         |            "c0"
+         |        ],
+         |        [
+         |            "SearchSnippet/get",
+         |            {
+         |                "accountId": "$ACCOUNT_ID",
+         |                "filter": {
+         |                    "body": "$keywordSearch"
+         |                },
+         |                "#emailIds": {
+         |                    "resultOf": "c0",
+         |                    "name": "Email/query",
+         |                    "path": "/ids/*"
+         |                }
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
+         |}""".stripMargin
+
+    awaitAtMostTenSeconds.untilAsserted { () =>
+      val response: ResponseBodyExtractionOptions = `given`
+        .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+        .body(request)
+      .when
+        .post
+      .`then`
+        .statusCode(SC_OK)
+        .contentType(JSON)
+        .extract()
+        .body
+
+      assertThatJson(response.asString())
+        .withOptions(IGNORING_ARRAY_ORDER)
+        .inPath("methodResponses[1]")
+        .isEqualTo(
+          s"""[
+             |  "SearchSnippet/get",
+             |  {
+             |    "accountId": "$ACCOUNT_ID",
+             |    "list": [
+             |      {
+             |        "emailId": "${messageId1.serialize()}",
+             |        "subject": null,
+             |        "preview": "$${json-unit.ignore}"
+             |      }
+             |    ],
+             |    "notFound": []
+             |  },
+             |  "c1"
+             |]""".stripMargin)
+
+      
assertThat(response.jsonPath().get("methodResponses[1][1].list[0].preview").toString)
+        .contains(s"<mark>$keywordSearch</mark>")
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to