You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/05/18 10:33:12 UTC
[james-project] branch master updated: JAMES-3491 Implement more actions for filters (#1563)
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 de87ddfbeb JAMES-3491 Implement more actions for filters (#1563)
de87ddfbeb is described below
commit de87ddfbeb4f778f95af4dc6d47e1d748d471498
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Thu May 18 17:33:06 2023 +0700
JAMES-3491 Implement more actions for filters (#1563)
---
.../java/org/apache/mailet/StorageDirective.java | 40 +++++--
.../james/jmap/cassandra/filtering/RuleDTO.java | 41 ++++++-
.../james/jmap/cassandra/filtering/DTOTest.java | 33 +++++-
.../src/test/resources/json/event-v2.json | 43 ++++++++
.../src/test/resources/json/eventComplex-v2.json | 79 ++++++++++++++
.../src/test/resources/json/increment-v2.json | 31 ++++++
.../org/apache/james/jmap/api/filtering/Rule.java | 45 +++++++-
.../james/jmap/mailet/filter/ActionApplier.java | 56 +++++++---
.../james/jmap/mailet/filter/JMAPFiltering.java | 27 +++--
.../jmap/mailet/filter/JMAPFilteringTest.java | 118 +++++++++++++++++++++
10 files changed, 465 insertions(+), 48 deletions(-)
diff --git a/mailet/api/src/main/java/org/apache/mailet/StorageDirective.java b/mailet/api/src/main/java/org/apache/mailet/StorageDirective.java
index a55f46764e..2d0fe928de 100644
--- a/mailet/api/src/main/java/org/apache/mailet/StorageDirective.java
+++ b/mailet/api/src/main/java/org/apache/mailet/StorageDirective.java
@@ -19,6 +19,7 @@
package org.apache.mailet;
import java.util.Collection;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
@@ -84,16 +85,26 @@ public class StorageDirective {
}
public StorageDirective build() {
- Preconditions.checkState(
- Booleans.countTrue(
- seen.isPresent(),
- important.isPresent(),
- targetFolder.isPresent(),
- keywords.isPresent()) > 0,
+ Preconditions.checkState(hasChanges(),
"Expecting one of the storage directives to be specified: [targetFolder, seen, important, keywords]");
return new StorageDirective(targetFolder, seen, important, keywords);
}
+
+ private boolean hasChanges() {
+ return Booleans.countTrue(
+ seen.isPresent(),
+ important.isPresent(),
+ targetFolder.isPresent(),
+ keywords.isPresent()) > 0;
+ }
+
+ public Optional<StorageDirective> buildOptional() {
+ if (!hasChanges()) {
+ return Optional.empty();
+ }
+ return Optional.of(build());
+ }
}
private static final String DELIVERY_PATH_PREFIX = "DeliveryPath_";
@@ -209,4 +220,21 @@ public class StorageDirective {
public Optional<String> getTargetFolder() {
return targetFolder;
}
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof StorageDirective) {
+ StorageDirective other = (StorageDirective) o;
+ return Objects.equals(targetFolder, other.targetFolder)
+ && Objects.equals(seen, other.seen)
+ && Objects.equals(important, other.important)
+ && Objects.equals(keywords, other.keywords);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(targetFolder, seen, important, keywords);
+ }
}
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
index c3d8c54fd8..86a39ac00a 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
@@ -131,20 +131,49 @@ public class RuleDTO {
}
public static ActionDTO from(Rule.Action action) {
- return new ActionDTO(AppendInMailboxesDTO.from(action.getAppendInMailboxes()));
+ return new ActionDTO(AppendInMailboxesDTO.from(action.getAppendInMailboxes()),
+ action.isMarkAsSeen(), action.isMarkAsImportant(), action.isReject(), ImmutableList.copyOf(action.getWithKeywords()));
}
@JsonCreator
- public ActionDTO(@JsonProperty("appendIn") AppendInMailboxesDTO appendIn) {
+ public ActionDTO(@JsonProperty("appendIn") AppendInMailboxesDTO appendIn,
+ @JsonProperty("seen") boolean seen,
+ @JsonProperty("important") boolean important,
+ @JsonProperty("reject") boolean reject,
+ @JsonProperty("keywords") List<String> keyworkds) {
this.appendIn = appendIn;
+ this.keyworkds = keyworkds;
+ this.seen = seen;
+ this.important = important;
+ this.reject = reject;
}
private final AppendInMailboxesDTO appendIn;
+ private final boolean seen;
+ private final boolean important;
+ private final boolean reject;
+ private final List<String> keyworkds;
public AppendInMailboxesDTO getAppendIn() {
return appendIn;
}
+ public boolean isSeen() {
+ return seen;
+ }
+
+ public boolean isImportant() {
+ return important;
+ }
+
+ public boolean isReject() {
+ return reject;
+ }
+
+ public List<String> getKeyworkds() {
+ return keyworkds;
+ }
+
public Rule.Action toAction() {
return Rule.Action.of(appendIn.toAppendInMailboxes());
}
@@ -154,14 +183,18 @@ public class RuleDTO {
if (o instanceof ActionDTO) {
ActionDTO actionDTO = (ActionDTO) o;
- return Objects.equals(this.appendIn, actionDTO.appendIn);
+ return Objects.equals(this.appendIn, actionDTO.appendIn)
+ && Objects.equals(this.seen, actionDTO.seen)
+ && Objects.equals(this.important, actionDTO.important)
+ && Objects.equals(this.reject, actionDTO.reject)
+ && Objects.equals(this.keyworkds, actionDTO.keyworkds);
}
return false;
}
@Override
public final int hashCode() {
- return Objects.hash(appendIn);
+ return Objects.hash(appendIn, reject, seen, important, keyworkds);
}
}
diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
index 3130a5bfd9..25ca063d4a 100644
--- a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
+++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
@@ -27,6 +27,7 @@ import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_SUBJECT;
import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_TO;
import static org.apache.james.jmap.cassandra.filtering.FilteringRuleSetDefineDTOModules.FILTERING_INCREMENT;
import static org.apache.james.jmap.cassandra.filtering.FilteringRuleSetDefineDTOModules.FILTERING_RULE_SET_DEFINED;
+import static org.assertj.core.api.Assertions.assertThat;
import java.util.Optional;
@@ -39,15 +40,19 @@ import org.apache.james.jmap.api.filtering.impl.IncrementalRuleChange;
import org.apache.james.jmap.api.filtering.impl.RuleSetDefined;
import org.apache.james.json.JsonGenericSerializer;
import org.apache.james.util.ClassLoaderUtils;
+import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
+import com.github.fge.lambdas.Throwing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
class DTOTest {
static final String EVENT_JSON = ClassLoaderUtils.getSystemResourceAsString("json/event.json");
+ static final String EVENT_JSON_2 = ClassLoaderUtils.getSystemResourceAsString("json/event-v2.json");
static final String EVENT_EMPTY_JSON = ClassLoaderUtils.getSystemResourceAsString("json/eventEmpty.json");
static final String EVENT_COMPLEX_JSON = ClassLoaderUtils.getSystemResourceAsString("json/eventComplex.json");
+ static final String EVENT_COMPLEX_JSON_2 = ClassLoaderUtils.getSystemResourceAsString("json/eventComplex-v2.json");
static final RuleSetDefined SIMPLE_RULE = new RuleSetDefined(
new FilteringAggregateId(Username.of("Bart")),
@@ -73,15 +78,37 @@ class DTOTest {
void shouldSerializeRule() throws Exception {
JsonSerializationVerifier.dtoModule(FILTERING_RULE_SET_DEFINED)
.testCase(EMPTY_RULE, EVENT_EMPTY_JSON)
- .testCase(SIMPLE_RULE, EVENT_JSON)
- .testCase(COMPLEX_RULE, EVENT_COMPLEX_JSON)
+ .testCase(SIMPLE_RULE, EVENT_JSON_2)
+ .testCase(COMPLEX_RULE, EVENT_COMPLEX_JSON_2)
.verify();
}
+ @Test
+ void shouldDeserializeV1() {
+ JsonGenericSerializer<RuleSetDefined, FilteringRuleSetDefinedDTO> serializer = JsonGenericSerializer
+ .forModules(FILTERING_RULE_SET_DEFINED)
+ .withoutNestedType();
+
+ SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+ softly.assertThat(serializer.deserialize(EVENT_JSON)).isEqualToComparingFieldByFieldRecursively(SIMPLE_RULE);
+ softly.assertThat(serializer.deserialize(EVENT_COMPLEX_JSON)).isEqualToComparingFieldByFieldRecursively(COMPLEX_RULE);
+ }));
+ }
+
@Test
void shouldSerializeIncrements() throws Exception {
JsonSerializationVerifier.dtoModule(FILTERING_INCREMENT)
- .testCase(INCREMENT, ClassLoaderUtils.getSystemResourceAsString("json/increment.json"))
+ .testCase(INCREMENT, ClassLoaderUtils.getSystemResourceAsString("json/increment-v2.json"))
.verify();
}
+
+ @Test
+ void shouldDeserializeV1ForIncrements() throws Exception {
+ JsonGenericSerializer<IncrementalRuleChange, FilteringIncrementalRuleChangeDTO> serializer = JsonGenericSerializer
+ .forModules(FILTERING_INCREMENT)
+ .withoutNestedType();
+
+ assertThat(serializer.deserialize(ClassLoaderUtils.getSystemResourceAsString("json/increment.json")))
+ .isEqualToComparingFieldByFieldRecursively(INCREMENT);
+ }
}
diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/event-v2.json b/server/data/data-jmap-cassandra/src/test/resources/json/event-v2.json
new file mode 100644
index 0000000000..903a7b877b
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/event-v2.json
@@ -0,0 +1,43 @@
+{
+ "type":"filtering-rule-set-defined",
+ "eventId":0,
+ "aggregateId":"FilteringRule/bart",
+ "rules":[
+ {
+ "id":"1",
+ "name":"a name",
+ "condition": {
+ "field": "cc",
+ "comparator": "contains",
+ "value": "something"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["id-01"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ },
+ {
+ "id":"2",
+ "name":"a name",
+ "condition": {
+ "field": "cc",
+ "comparator": "contains",
+ "value": "something"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["id-01"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex-v2.json b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex-v2.json
new file mode 100644
index 0000000000..93b1c258eb
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex-v2.json
@@ -0,0 +1,79 @@
+{
+ "type":"filtering-rule-set-defined",
+ "eventId":0,
+ "aggregateId":"FilteringRule/bart",
+ "rules":[
+ {
+ "id":"id-from",
+ "name":"a name",
+ "condition": {
+ "field": "from",
+ "comparator": "contains",
+ "value": "A value to match 4"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["mbx1"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ },
+ {
+ "id":"id-rcpt",
+ "name":"a name",
+ "condition": {
+ "field": "recipient",
+ "comparator": "not-exactly-equals",
+ "value": "A value to match 3"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["mbx1"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ },
+ {
+ "id":"id-subject",
+ "name":"a name",
+ "condition": {
+ "field": "subject",
+ "comparator": "not-contains",
+ "value": "A value to match 2"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["mbx1"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ },
+ {
+ "id":"id-to",
+ "name":"a name",
+ "condition": {
+ "field": "to",
+ "comparator": "exactly-equals",
+ "value": "A value to match 1"
+ },
+ "action": {
+ "appendIn": {
+ "mailboxIds":["mbx1"]
+ },
+ "important":false,
+ "keyworkds":[],
+ "reject":false,
+ "seen":false
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/increment-v2.json b/server/data/data-jmap-cassandra/src/test/resources/json/increment-v2.json
new file mode 100644
index 0000000000..dd3b5832b1
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/increment-v2.json
@@ -0,0 +1,31 @@
+{
+ "type":"filtering-increment",
+ "eventId":0,
+ "aggregateId":"FilteringRule/bart",
+ "prepended":[
+ {
+ "id":"id-from",
+ "name":"a name",
+ "condition":{"field":"from","comparator":"contains","value":"A value to match 4"},
+ "action":{"appendIn":{"mailboxIds":["mbx1"]},"important":false,"keyworkds":[],"reject":false,"seen":false}
+ },
+ {
+ "id":"id-to",
+ "name":"a name",
+ "condition":{"field":"to","comparator":"exactly-equals","value":"A value to match 1"},
+ "action":{"appendIn":{"mailboxIds":["mbx1"]},"important":false,"keyworkds":[],"reject":false,"seen":false}
+ }],
+ "postpended":[{
+ "id":"id-rcpt",
+ "name":"a name",
+ "condition":{"field":"recipient","comparator":"not-exactly-equals","value":"A value to match 3"},
+ "action":{"appendIn":{"mailboxIds":["mbx1"]},"important":false,"keyworkds":[],"reject":false,"seen":false}
+ }],
+ "updated":[{
+ "id":"id-subject",
+ "name":"a name",
+ "condition":{"field":"subject","comparator":"not-contains","value":"A value to match 2"},
+ "action":{"appendIn":{"mailboxIds":["mbx1"]},"important":false,"keyworkds":[],"reject":false,"seen":false}
+ }],
+ "deleted":["abdcd"]
+}
\ No newline at end of file
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 3d9af273f0..91c79317fa 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
@@ -20,6 +20,7 @@
package org.apache.james.jmap.api.filtering;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -230,37 +231,73 @@ public class Rule {
}
public static Action of(AppendInMailboxes appendInMailboxes) {
- return new Action(appendInMailboxes);
+ return new Action(appendInMailboxes, false, false, false, ImmutableList.of());
+ }
+
+ public static Action of(AppendInMailboxes appendInMailboxes, boolean markAsSeen, boolean markAsImportant, boolean reject, List<String> withKeywords) {
+ return new Action(appendInMailboxes, markAsSeen, markAsImportant, reject, withKeywords);
}
private final AppendInMailboxes appendInMailboxes;
+ private final boolean markAsSeen;
+ private final boolean markAsImportant;
+ private final boolean reject;
+ private final List<String> withKeywords;
- private Action(AppendInMailboxes appendInMailboxes) {
+ private Action(AppendInMailboxes appendInMailboxes, boolean markAsSeen, boolean markAsImportant, boolean reject, List<String> withKeywords) {
this.appendInMailboxes = appendInMailboxes;
+ this.markAsSeen = markAsSeen;
+ this.markAsImportant = markAsImportant;
+ this.reject = reject;
+ this.withKeywords = withKeywords;
}
public AppendInMailboxes getAppendInMailboxes() {
return appendInMailboxes;
}
+ public boolean isMarkAsSeen() {
+ return markAsSeen;
+ }
+
+ public boolean isMarkAsImportant() {
+ return markAsImportant;
+ }
+
+ public boolean isReject() {
+ return reject;
+ }
+
+ public Collection<String> getWithKeywords() {
+ return withKeywords;
+ }
+
@Override
public final boolean equals(Object o) {
if (o instanceof Action) {
Action action = (Action) o;
- return Objects.equals(appendInMailboxes, action.appendInMailboxes);
+ return Objects.equals(appendInMailboxes, action.appendInMailboxes)
+ && Objects.equals(markAsSeen, action.markAsSeen)
+ && Objects.equals(markAsImportant, action.markAsImportant)
+ && Objects.equals(reject, action.reject)
+ && Objects.equals(withKeywords, action.withKeywords);
}
return false;
}
@Override
public final int hashCode() {
- return Objects.hash(appendInMailboxes);
+ return Objects.hash(appendInMailboxes, markAsImportant, markAsSeen, reject, withKeywords);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("appendInMailboxes", appendInMailboxes)
+ .add("markAsImportant", markAsImportant)
+ .add("markAsSeen", markAsSeen)
+ .add("reject", reject)
+ .add("withKeywords", withKeywords)
.toString();
}
}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/ActionApplier.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/ActionApplier.java
index e9ce7b9954..6f21a0a0cd 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/ActionApplier.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/ActionApplier.java
@@ -19,10 +19,12 @@
package org.apache.james.jmap.mailet.filter;
+import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
+import org.apache.james.core.MailAddress;
import org.apache.james.core.Username;
import org.apache.james.jmap.api.filtering.Rule;
import org.apache.james.mailbox.MailboxManager;
@@ -36,6 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
public class ActionApplier {
static final String DELIVERY_PATH_PREFIX = "DeliveryPath_";
@@ -63,8 +66,8 @@ public class ActionApplier {
this.mail = mail;
}
- public ActionApplier forUser(Username username) {
- return new ActionApplier(mailboxManager, mailboxIdFactory, mail, username);
+ public ActionApplier forRecipient(MailAddress mailAddress, Username username) {
+ return new ActionApplier(mailboxManager, mailboxIdFactory, mail, mailAddress, username);
}
}
}
@@ -72,6 +75,7 @@ public class ActionApplier {
private final MailboxManager mailboxManager;
private final MailboxId.Factory mailboxIdFactory;
private final Mail mail;
+ private final MailAddress mailAddress;
private final Username username;
@VisibleForTesting
@@ -79,35 +83,55 @@ public class ActionApplier {
return new Factory(mailboxManager, mailboxIdFactory);
}
- private ActionApplier(MailboxManager mailboxManager, MailboxId.Factory mailboxIdFactory, Mail mail, Username username) {
+ private ActionApplier(MailboxManager mailboxManager, MailboxId.Factory mailboxIdFactory, Mail mail, MailAddress mailAddress, Username username) {
this.mailboxManager = mailboxManager;
this.mailboxIdFactory = mailboxIdFactory;
this.mail = mail;
+ this.mailAddress = mailAddress;
this.username = username;
}
public void apply(Stream<Rule.Action> actions) {
- actions.flatMap(action -> action.getAppendInMailboxes().getMailboxIds().stream())
- .map(mailboxIdFactory::fromString)
- .forEach(this::addStorageDirective);
+ actions.forEach(this::addStorageDirective);
}
- private void addStorageDirective(MailboxId mailboxId) {
+ private void addStorageDirective(Rule.Action action) {
+ if (action.isReject()) {
+ mail.setRecipients(mail.getRecipients().stream()
+ .filter(recipient -> !recipient.equals(mailAddress))
+ .collect(ImmutableList.toImmutableList()));
+ return;
+ }
+ Optional<String> targetMailbox = action.getAppendInMailboxes().getMailboxIds()
+ .stream()
+ .flatMap(this::asMailboxName)
+ .reduce((first, second) -> second);
+
+ StorageDirective.Builder storageDirective = StorageDirective.builder();
+ targetMailbox.ifPresent(storageDirective::targetFolder);
+ storageDirective
+ .seen(Optional.of(action.isMarkAsSeen()).filter(seen -> seen))
+ .important(Optional.of(action.isMarkAsImportant()).filter(seen -> seen))
+ .keywords(Optional.of(action.getWithKeywords()).filter(c -> !c.isEmpty()))
+ .buildOptional()
+ .map(a -> a.encodeAsAttributes(username))
+ .orElse(Stream.of())
+ .forEach(mail::setAttribute);
+ }
+
+ private Stream<String> asMailboxName(String mailboxIdString) {
try {
+ MailboxId mailboxId = mailboxIdFactory.fromString(mailboxIdString);
MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
MessageManager messageManager = mailboxManager.getMailbox(mailboxId, mailboxSession);
- String mailboxName = messageManager.getMailboxPath().getName();
-
- StorageDirective.builder()
- .targetFolder(mailboxName)
- .build()
- .encodeAsAttributes(username)
- .forEach(mail::setAttribute);
+ return Stream.of(messageManager.getMailboxPath().getName());
} catch (MailboxNotFoundException e) {
- LOGGER.info("Mailbox {} does not exist, but it was mentioned in a JMAP filtering rule", mailboxId, e);
+ LOGGER.info("Mailbox {} does not exist, but it was mentioned in a JMAP filtering rule", mailboxIdString, e);
+ return Stream.empty();
} catch (Exception e) {
- LOGGER.error("Unexpected failure while resolving mailbox name for {}", mailboxId, e);
+ LOGGER.error("Unexpected failure while resolving mailbox name for {}", mailboxIdString, e);
+ return Stream.empty();
}
}
}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
index d7ddd315dc..e22a48336f 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
@@ -69,24 +69,21 @@ public class JMAPFiltering extends GenericMailet {
@Override
public void service(Mail mail) {
mail.getRecipients()
- .forEach(recipient -> filteringForRecipient(mail, recipient));
+ .forEach(recipient -> applyFirstApplicableRule(recipient, mail));
}
- private void filteringForRecipient(Mail mail, MailAddress recipient) {
- Optional<Username> maybeUser = retrieveUser(recipient);
- maybeUser
- .ifPresent(user -> findFirstApplicableRule(user, mail));
- }
-
- private void findFirstApplicableRule(Username username, Mail mail) {
- Rules filteringRules = Mono.from(filteringManagement.listRulesForUser(username))
- .block();
- RuleMatcher ruleMatcher = new RuleMatcher(filteringRules.getRules());
- Stream<Rule> matchingRules = ruleMatcher.findApplicableRules(mail);
+ private void applyFirstApplicableRule(MailAddress recipient, Mail mail) {
+ retrieveUser(recipient)
+ .ifPresent(username -> {
+ Rules filteringRules = Mono.from(filteringManagement.listRulesForUser(username))
+ .block();
+ RuleMatcher ruleMatcher = new RuleMatcher(filteringRules.getRules());
+ Stream<Rule> matchingRules = ruleMatcher.findApplicableRules(mail);
- actionApplierFactory.forMail(mail)
- .forUser(username)
- .apply(matchingRules.map(Rule::getAction));
+ actionApplierFactory.forMail(mail)
+ .forRecipient(recipient, username)
+ .apply(matchingRules.map(Rule::getAction));
+ });
}
private Optional<Username> retrieveUser(MailAddress recipient) {
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
index 4ae01a30ae..86d60a78b3 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
@@ -35,6 +35,7 @@ import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.EMPTY;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.FRED_MARTIN_FULLNAME;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.FRED_MARTIN_FULL_SCRAMBLED_ADDRESS;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.GA_BOU_ZO_MEU_FULL_ADDRESS;
+import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.RECIPIENT_1;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.RECIPIENT_1_MAILBOX_1;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.RECIPIENT_1_USERNAME;
import static org.apache.james.jmap.mailet.filter.JMAPFilteringFixture.SCRAMBLED_SUBJECT;
@@ -57,6 +58,9 @@ import java.util.Locale;
import java.util.Optional;
import java.util.stream.Stream;
+import javax.mail.Flags;
+
+import org.apache.james.core.Username;
import org.apache.james.core.builder.MimeMessageBuilder;
import org.apache.james.jmap.api.filtering.Rule;
import org.apache.james.jmap.api.filtering.Rule.Condition.Field;
@@ -66,6 +70,7 @@ import org.apache.james.util.StreamUtils;
import org.apache.mailet.Attribute;
import org.apache.mailet.AttributeName;
import org.apache.mailet.AttributeValue;
+import org.apache.mailet.StorageDirective;
import org.apache.mailet.base.RFC2822Headers;
import org.apache.mailet.base.test.FakeMail;
import org.junit.jupiter.api.Nested;
@@ -915,4 +920,117 @@ class JMAPFilteringTest {
.contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
}
}
+
+ @Test
+ void actionShouldSupportReject(JMAPFilteringTestSystem testSystem) throws Exception {
+ Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+ .condition(Rule.Condition.of(FROM, CONTAINS, FRED_MARTIN_FULLNAME))
+ .action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(),
+ false, false, true, ImmutableList.of()))
+ .build())).block();
+
+ FakeMail mail = testSystem.asMail(mimeMessageBuilder()
+ .addFrom(FRED_MARTIN_FULL_SCRAMBLED_ADDRESS));
+
+ testSystem.getJmapFiltering().service(mail);
+
+ assertThat(mail.getRecipients()).isEmpty();
+ }
+
+ @Test
+ void actionShouldSupportSeen(JMAPFilteringTestSystem testSystem) throws Exception {
+ Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+ .condition(Rule.Condition.of(FROM, CONTAINS, FRED_MARTIN_FULLNAME))
+ .action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(),
+ true, false, false, ImmutableList.of()))
+ .build())).block();
+
+ FakeMail mail = testSystem.asMail(mimeMessageBuilder()
+ .addFrom(FRED_MARTIN_FULL_SCRAMBLED_ADDRESS));
+
+ testSystem.getJmapFiltering().service(mail);
+
+ assertThat(StorageDirective.fromMail(Username.of("recipient1"), mail))
+ .isEqualTo(StorageDirective.builder()
+ .seen(Optional.of(true))
+ .build());
+ }
+
+ @Test
+ void actionShouldSupportImportant(JMAPFilteringTestSystem testSystem) throws Exception {
+ Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+ .condition(Rule.Condition.of(FROM, CONTAINS, FRED_MARTIN_FULLNAME))
+ .action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(),
+ false, true, false, ImmutableList.of()))
+ .build())).block();
+
+ FakeMail mail = testSystem.asMail(mimeMessageBuilder()
+ .addFrom(FRED_MARTIN_FULL_SCRAMBLED_ADDRESS));
+
+ testSystem.getJmapFiltering().service(mail);
+
+ assertThat(StorageDirective.fromMail(Username.of("recipient1"), mail))
+ .isEqualTo(StorageDirective.builder()
+ .important(Optional.of(true))
+ .build());
+ }
+
+ @Test
+ void actionShouldSupportKeywords(JMAPFilteringTestSystem testSystem) throws Exception {
+ Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+ .condition(Rule.Condition.of(FROM, CONTAINS, FRED_MARTIN_FULLNAME))
+ .action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(),
+ false, false, false, ImmutableList.of("abc", "def")))
+ .build())).block();
+
+ FakeMail mail = testSystem.asMail(mimeMessageBuilder()
+ .addFrom(FRED_MARTIN_FULL_SCRAMBLED_ADDRESS));
+
+ testSystem.getJmapFiltering().service(mail);
+
+ assertThat(StorageDirective.fromMail(Username.of("recipient1"), mail).getFlags().get().getUserFlags())
+ .containsOnly("abc", "def");
+ }
+
+ @Test
+ void actionShouldCombineFlags(JMAPFilteringTestSystem testSystem) throws Exception {
+ Mono.from(testSystem.getFilteringManagement().defineRulesForUser(RECIPIENT_1_USERNAME,
+ Optional.empty(),
+ Rule.builder()
+ .id(Rule.Id.of("1"))
+ .name("rule 1")
+ .condition(Rule.Condition.of(FROM, CONTAINS, FRED_MARTIN_FULLNAME))
+ .action(Rule.Action.of(Rule.Action.AppendInMailboxes.withMailboxIds(),
+ true, true, false, ImmutableList.of("abc", "def")))
+ .build())).block();
+
+ FakeMail mail = testSystem.asMail(mimeMessageBuilder()
+ .addFrom(FRED_MARTIN_FULL_SCRAMBLED_ADDRESS));
+
+ testSystem.getJmapFiltering().service(mail);
+
+ Flags expectedFlags = new Flags();
+ expectedFlags.add("abc");
+ expectedFlags.add("def");
+ expectedFlags.add(Flags.Flag.SEEN);
+ expectedFlags.add(Flags.Flag.FLAGGED);
+ assertThat(StorageDirective.fromMail(Username.of("recipient1"), mail).getFlags().get())
+ .isEqualTo(expectedFlags);
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org