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 <btell...@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-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to