This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 05bb02970d JAMES-4148 Implement ANY comparator for custom header
(#2832)
05bb02970d is described below
commit 05bb02970de8e13de20994b7b11ea8ba5c8f2878
Author: Trần Hồng Quân <[email protected]>
AuthorDate: Fri Oct 3 14:09:03 2025 +0700
JAMES-4148 Implement ANY comparator for custom header (#2832)
---
.../src/test/resources/json/event-v4.json | 5 ++
.../org/apache/james/jmap/api/filtering/Rule.java | 3 +-
.../james/jmap/api/filtering/RuleFixture.java | 3 +-
.../james/jmap/mailet/filter/ContentMatcher.java | 2 +
.../jmap/mailet/filter/JMAPFilteringTest.java | 66 ++++++++++++++++++++++
.../data/jmap/RunRulesOnMailboxRoutesTest.java | 15 ++---
6 files changed, 83 insertions(+), 11 deletions(-)
diff --git
a/server/data/data-jmap-cassandra/src/test/resources/json/event-v4.json
b/server/data/data-jmap-cassandra/src/test/resources/json/event-v4.json
index bb54fd57fa..63264aec34 100644
--- a/server/data/data-jmap-cassandra/src/test/resources/json/event-v4.json
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/event-v4.json
@@ -18,6 +18,11 @@
"field": "header:custom",
"comparator": "contains",
"value": "another thing"
+ },
+ {
+ "field": "header:anotherCustom",
+ "comparator": "any",
+ "value": "disregard me"
}
]
},
diff --git
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
index bd64c8fb56..067f8b8a6a 100644
---
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
+++
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
@@ -189,7 +189,8 @@ public class Rule {
NOT_EXACTLY_EQUALS("not-exactly-equals"),
START_WITH("start-with"),
IS_SET("isSet"),
- IS_UNSET("isUnset");
+ IS_UNSET("isUnset"),
+ ANY("any");
public static Optional<Comparator> find(String comparatorName) {
return Arrays.stream(values())
diff --git
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
index 3b946e3758..c3a93a5603 100644
---
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
+++
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
@@ -57,7 +57,8 @@ public interface RuleFixture {
Rule RULE_3 = RULE_BUILDER.id(Rule.Id.of("3")).build();
Rule RULE_4 = Rule.builder()
.conditionGroup(Rule.ConditionCombiner.AND, CONDITION,
- Rule.Condition.of(new Rule.Condition.CustomHeaderField("custom"),
Rule.Condition.Comparator.CONTAINS, "another thing"))
+ Rule.Condition.of(new Rule.Condition.CustomHeaderField("custom"),
Rule.Condition.Comparator.CONTAINS, "another thing"),
+ Rule.Condition.of(new
Rule.Condition.CustomHeaderField("anotherCustom"),
Rule.Condition.Comparator.ANY, "disregard me"))
.action(ACTION_2)
.id(Rule.Id.of("1"))
.name(NAME)
diff --git
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
index 4ca7e5ca55..f0b55e3569 100644
---
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
+++
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
@@ -167,6 +167,7 @@ public interface ContentMatcher {
ContentMatcher STRING_EXACTLY_EQUALS_MATCHER = (contents, valueToMatch) ->
contents.anyMatch(content -> StringUtils.equals(content, valueToMatch));
ContentMatcher STRING_NOT_EXACTLY_EQUALS_MATCHER =
negate(STRING_EXACTLY_EQUALS_MATCHER);
ContentMatcher STRING_START_WITH_MATCHER = (contents, valueToMatch) ->
contents.anyMatch(content -> content.startsWith(valueToMatch));
+ ContentMatcher ANY_MATCHER = (contents, valueToMatch) ->
contents.anyMatch(StringUtils::isNotBlank);
ContentMatcher ADDRESS_CONTAINS_MATCHER = (contents, valueToMatch) ->
contents
.map(ContentMatcher::asAddressHeader)
@@ -201,6 +202,7 @@ public interface ContentMatcher {
.put(Rule.Condition.Comparator.EXACTLY_EQUALS,
STRING_EXACTLY_EQUALS_MATCHER)
.put(Rule.Condition.Comparator.NOT_EXACTLY_EQUALS,
STRING_NOT_EXACTLY_EQUALS_MATCHER)
.put(Rule.Condition.Comparator.START_WITH, STRING_START_WITH_MATCHER)
+ .put(Rule.Condition.Comparator.ANY, ANY_MATCHER)
.build();
Map<Rule.Condition.Field, Map<Rule.Condition.Comparator, ContentMatcher>>
CONTENT_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Field,
Map<Rule.Condition.Comparator, ContentMatcher>>builder()
diff --git
a/server/protocols/jmap-rfc-8621/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
b/server/protocols/jmap-rfc-8621/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
index 7ea7ed1a5c..937c6fe14d 100644
---
a/server/protocols/jmap-rfc-8621/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
+++
b/server/protocols/jmap-rfc-8621/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
@@ -20,6 +20,7 @@
package org.apache.james.jmap.mailet.filter;
import static
org.apache.james.core.builder.MimeMessageBuilder.mimeMessageBuilder;
+import static
org.apache.james.jmap.api.filtering.Rule.Condition.Comparator.ANY;
import static
org.apache.james.jmap.api.filtering.Rule.Condition.Comparator.CONTAINS;
import static
org.apache.james.jmap.api.filtering.Rule.Condition.Comparator.EXACTLY_EQUALS;
import static
org.apache.james.jmap.api.filtering.Rule.Condition.Comparator.IS_NEWER_THAN;
@@ -1191,6 +1192,71 @@ class JMAPFilteringTest {
.isEmpty();
}
+ @Test
+ void customHeaderShouldSupportAnyComparator(JMAPFilteringTestSystem
testSystem) throws Exception {
+
Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+
.conditionGroup(Rule.Condition.of(Rule.Condition.CustomHeaderField.find("header:X-Github").get(),
ANY, "disregarded"))
+
.action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(testSystem.getRecipient1MailboxId().serialize())))
+ .build())).block();
+
+ FakeMail matchMail = testSystem.asMail(mimeMessageBuilder()
+ .addHeader(FROM.asString(), USER_2_ADDRESS)
+ .addHeader(SUBJECT.asString(), "subject")
+ .addHeader("X-Github", "I am Github header"));
+
+ testSystem.getJmapFiltering().service(matchMail);
+
+
assertThatAttribute(matchMail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+ .isEqualTo(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
+ }
+
+ @Test
+ void
nonExistingCustomHeaderShouldNotMatchAnyComparator(JMAPFilteringTestSystem
testSystem) throws Exception {
+
Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+
.conditionGroup(Rule.Condition.of(Rule.Condition.CustomHeaderField.find("header:X-Github").get(),
ANY, "disregarded"))
+
.action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(testSystem.getRecipient1MailboxId().serialize())))
+ .build())).block();
+
+ FakeMail nonMatchMail = testSystem.asMail(mimeMessageBuilder()
+ .addHeader(FROM.asString(), USER_2_ADDRESS)
+ .addHeader(SUBJECT.asString(), "subject"));
+
+ testSystem.getJmapFiltering().service(nonMatchMail);
+
+
assertThat(nonMatchMail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+ .isEmpty();
+ }
+
+ @Test
+ void emptyCustomHeaderShouldNotMatchAnyComparator(JMAPFilteringTestSystem
testSystem) throws Exception {
+
Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+
.conditionGroup(Rule.Condition.of(Rule.Condition.CustomHeaderField.find("header:X-Github").get(),
ANY, "disregarded"))
+
.action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(testSystem.getRecipient1MailboxId().serialize())))
+ .build())).block();
+
+ FakeMail nonMatchMail = testSystem.asMail(mimeMessageBuilder()
+ .addHeader(FROM.asString(), USER_2_ADDRESS)
+ .addHeader(SUBJECT.asString(), "subject")
+ .addHeader("X-Github", ""));
+
+ testSystem.getJmapFiltering().service(nonMatchMail);
+
+
assertThat(nonMatchMail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+ .isEmpty();
+ }
+
@Test
void orShouldNotMatchWhenNoConditionsAreMet(JMAPFilteringTestSystem
testSystem) throws Exception {
Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
diff --git
a/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RunRulesOnMailboxRoutesTest.java
b/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RunRulesOnMailboxRoutesTest.java
index f65955ecc6..3d36c605f8 100644
---
a/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RunRulesOnMailboxRoutesTest.java
+++
b/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RunRulesOnMailboxRoutesTest.java
@@ -52,6 +52,7 @@ import
org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.stream.RawField;
import org.apache.james.task.Hostname;
import org.apache.james.task.MemoryTaskManager;
import org.apache.james.user.api.UsersRepository;
@@ -329,7 +330,8 @@ public class RunRulesOnMailboxRoutesTest {
.build(Message.Builder.of()
.setSubject("plop")
.setFrom("[email protected]")
- .setBody("body", StandardCharsets.UTF_8)),
+ .setBody("body", StandardCharsets.UTF_8)
+ .addField(new RawField("X-Custom-Header", "value"))),
systemSession);
String taskId = given()
@@ -354,14 +356,9 @@ public class RunRulesOnMailboxRoutesTest {
"conditionCombiner": "OR",
"conditions": [
{
- "comparator": "contains",
- "field": "subject",
- "value": "plop"
- },
- {
- "comparator": "exactly-equals",
- "field": "from",
- "value": "[email protected]"
+ "comparator": "any",
+ "field": "header:X-Custom-Header",
+ "value": "disregarded"
}
]
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]