You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/08/25 08:32:39 UTC
[01/13] james-project git commit: JAMES-2110 Define keyword on JMAP
Repository: james-project
Updated Branches:
refs/heads/master 5accc88a1 -> 10d76ab6e
JAMES-2110 Define keyword on JMAP
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/20beee7a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/20beee7a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/20beee7a
Branch: refs/heads/master
Commit: 20beee7a17946b42d3464269af383338d76a463f
Parents: 5accc88
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:31:39 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:26 2017 +0200
----------------------------------------------------------------------
.../org/apache/james/jmap/model/Keyword.java | 126 +++++++
.../org/apache/james/jmap/model/Keywords.java | 202 ++++++++++++
.../org/apache/james/jmap/model/OldKeyword.java | 92 ++++++
.../apache/james/jmap/model/KeywordTest.java | 189 +++++++++++
.../apache/james/jmap/model/KeywordsTest.java | 328 +++++++++++++++++++
.../apache/james/jmap/model/OldKeywordTest.java | 31 ++
6 files changed, 968 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
new file mode 100644
index 0000000..ff1a2f0
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
@@ -0,0 +1,126 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import java.util.Optional;
+import javax.mail.Flags;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
+
+public class Keyword {
+ private final static int FLAG_NAME_MIN_LENGTH = 1;
+ private final static int FLAG_NAME_MAX_LENGTH = 255;
+ private final static CharMatcher FLAG_NAME_PATTERN = CharMatcher.JAVA_LETTER_OR_DIGIT.or(CharMatcher.is('$'));
+
+ public final static Keyword DRAFT = new Keyword("$Draft");
+ public final static Keyword SEEN = new Keyword("$Seen");
+ public final static Keyword FLAGGED = new Keyword("$Flagged");
+ public final static Keyword ANSWERED = new Keyword("$Answered");
+ public final static Keyword DELETED = new Keyword("$Deleted");
+ public final static Keyword RECENT = new Keyword("$Recent");
+ public final static Boolean FLAG_VALUE = true;
+
+ private final static ImmutableList<Keyword> NON_EXPOSED_IMAP_KEYWORDS = ImmutableList.of(Keyword.RECENT, Keyword.DELETED);
+ private final static ImmutableBiMap<Flags.Flag, Keyword> IMAP_SYSTEM_FLAGS = ImmutableBiMap.<Flags.Flag, Keyword>builder()
+ .put(Flags.Flag.DRAFT, DRAFT)
+ .put(Flags.Flag.SEEN, SEEN)
+ .put(Flags.Flag.FLAGGED, FLAGGED)
+ .put(Flags.Flag.ANSWERED, ANSWERED)
+ .put(Flags.Flag.RECENT, RECENT)
+ .put(Flags.Flag.DELETED, DELETED)
+ .build();
+
+ private final String flagName;
+
+ public static Keyword fromFlag(Flags.Flag flag) {
+ return IMAP_SYSTEM_FLAGS.get(flag);
+ }
+
+ public Keyword(String flagName) {
+ Preconditions.checkArgument(isValid(flagName),
+ "Flagname must not be null or empty, must have length form 1-255, must not contain charater with hex from '\u0000' to '\u00019' or {'(' ')' '{' ']' '%' '*' '\"' '\\'} ");
+ this.flagName = flagName;
+ }
+
+ private boolean isValid(String flagName) {
+ if (StringUtils.isBlank(flagName)) {
+ return false;
+ }
+ if (flagName.length() < FLAG_NAME_MIN_LENGTH || flagName.length() > FLAG_NAME_MAX_LENGTH) {
+ return false;
+ }
+ if (!FLAG_NAME_PATTERN.matchesAllOf(flagName)) {
+ return false;
+ }
+ return true;
+ }
+
+ public String getFlagName() {
+ return flagName;
+ }
+
+ public boolean isExposedImapKeyword() {
+ return !NON_EXPOSED_IMAP_KEYWORDS.contains(this);
+ }
+
+ public boolean isDraft() {
+ return DRAFT.equals(this);
+ }
+
+ public Optional<Flags.Flag> asSystemFlag() {
+ return Optional.ofNullable(IMAP_SYSTEM_FLAGS.inverse()
+ .get(this));
+ }
+
+ public Flags asFlags() {
+ return asSystemFlag()
+ .map(Flags::new)
+ .orElse(new Flags(flagName));
+ }
+
+ @Override
+ public final boolean equals(Object other) {
+ if (other instanceof Keyword) {
+ Keyword otherKeyword = (Keyword) other;
+ return Objects.equal(flagName, otherKeyword.flagName);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hashCode(flagName);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("flagName", flagName)
+ .toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
new file mode 100644
index 0000000..91aff31
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
@@ -0,0 +1,202 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.FlagsBuilder;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class Keywords {
+ public static final Keywords DEFAULT_VALUE = factory().fromSet(ImmutableSet.of());
+
+ public interface KeywordsValidator {
+ void validate(Set<Keyword> keywords);
+ }
+
+ private FlagsBuilder combiner(FlagsBuilder firstBuilder, FlagsBuilder secondBuilder) {
+ return firstBuilder.add(secondBuilder.build());
+ }
+
+ private FlagsBuilder accumulator(FlagsBuilder accumulator, Keyword keyword) {
+ return accumulator.add(keyword.asFlags());
+ }
+
+ public static class KeywordsFactory {
+ private Optional<KeywordsValidator> validator;
+ private Optional<Predicate<Keyword>> filter;
+
+ private KeywordsFactory() {
+ validator = Optional.empty();
+ filter = Optional.empty();
+ }
+
+ public KeywordsFactory throwOnImapNonExposedKeywords() {
+ validator = Optional.of(keywords -> Preconditions.checkArgument(
+ keywords.stream().allMatch(Keyword::isExposedImapKeyword), "Does not allow to update 'Deleted' or 'Recent' flag"));
+ return this;
+ }
+
+ public KeywordsFactory filterImapNonExposedKeywords() {
+ filter = Optional.of(keyword -> keyword.isExposedImapKeyword());
+ return this;
+ }
+
+ public Keywords fromSet(Set<Keyword> setKeywords) {
+ validator.orElse(keywords -> {})
+ .validate(setKeywords);
+
+ return new Keywords(setKeywords.stream()
+ .filter(filter.orElse(keyword -> true))
+ .collect(Guavate.toImmutableSet()));
+ }
+
+ public Keywords fromList(List<String> keywords) {
+ return fromSet(keywords.stream()
+ .map(Keyword::new)
+ .collect(Guavate.toImmutableSet()));
+ }
+
+ @VisibleForTesting
+ Keywords fromMap(Map<String, Boolean> mapKeywords) {
+ Preconditions.checkArgument(mapKeywords.values()
+ .stream()
+ .noneMatch(keywordValue -> keywordValue == false), "Keyword must be true");
+ Set<Keyword> setKeywords = mapKeywords.keySet()
+ .stream()
+ .map(Keyword::new)
+ .collect(Guavate.toImmutableSet());
+
+ return fromSet(setKeywords);
+ }
+
+ @VisibleForTesting
+ Keywords fromOldKeyword(OldKeyword oldKeyword) {
+ ImmutableSet.Builder<Keyword> builder = ImmutableSet.builder();
+ if (oldKeyword.isAnswered().orElse(false)) {
+ builder.add(Keyword.ANSWERED);
+ }
+ if (oldKeyword.isDraft().orElse(false)) {
+ builder.add(Keyword.DRAFT);
+ }
+ if (oldKeyword.isFlagged().orElse(false)) {
+ builder.add(Keyword.FLAGGED);
+ }
+ if (oldKeyword.isUnread().isPresent() && oldKeyword.isUnread().get() == false) {
+ builder.add(Keyword.SEEN);
+ }
+ return fromSet(builder.build());
+ }
+
+ public Keywords fromFlags(Flags flags) {
+ return fromSet(Stream.concat(
+ Stream.of(flags.getUserFlags())
+ .map(Keyword::new),
+ Stream.of(flags.getSystemFlags())
+ .map(Keyword::fromFlag))
+ .collect(Guavate.toImmutableSet()));
+ }
+
+ public Optional<Keywords> fromMapOrOldKeyword(Optional<Map<String, Boolean>> mapKeyword, Optional<OldKeyword> oldKeyword) {
+ Preconditions.checkArgument(!(mapKeyword.isPresent() && oldKeyword.isPresent()), "Does not support keyword and is* at the same time");
+
+ Keywords keywords = mapKeyword.map(this::fromMap)
+ .orElse(oldKeyword.map(this::fromOldKeyword)
+ .orElse(null));
+ return Optional.ofNullable(keywords);
+ }
+ }
+
+ public static KeywordsFactory factory() {
+ return new KeywordsFactory();
+ }
+
+ private final ImmutableSet<Keyword> keywords;
+
+ private Keywords(ImmutableSet<Keyword> keywords) {
+ this.keywords = keywords;
+ }
+
+ public Flags asFlags() {
+ return keywords.stream()
+ .reduce(FlagsBuilder.builder(), this::accumulator, this::combiner)
+ .build();
+ }
+
+ public Flags asFlagsWithRecentAndDeletedFrom(Flags originFlags) {
+ Flags flags = asFlags();
+ if (originFlags.contains(Flags.Flag.DELETED)) {
+ flags.add(Flags.Flag.DELETED);
+ }
+ if (originFlags.contains(Flags.Flag.RECENT)) {
+ flags.add(Flags.Flag.RECENT);
+ }
+
+ return flags;
+ }
+
+ public ImmutableMap<String, Boolean> asMap() {
+ return keywords.stream()
+ .collect(Guavate.toImmutableMap(Keyword::getFlagName, keyword -> Keyword.FLAG_VALUE));
+ }
+
+ public ImmutableSet<Keyword> getKeywords() {
+ return keywords;
+ }
+
+ public boolean contains(Keyword keyword) {
+ return keywords.contains(keyword);
+ }
+
+ @Override
+ public final boolean equals(Object other) {
+ if (other instanceof Keywords) {
+ Keywords otherKeyword = (Keywords) other;
+ return Objects.equal(keywords, otherKeyword.keywords);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hashCode(keywords);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("keywords", keywords)
+ .toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/OldKeyword.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/OldKeyword.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/OldKeyword.java
new file mode 100644
index 0000000..e2cb2b3
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/OldKeyword.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import java.util.Optional;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+
+public class OldKeyword {
+ private final Optional<Boolean> isUnread;
+ private final Optional<Boolean> isFlagged;
+ private final Optional<Boolean> isAnswered;
+ private final Optional<Boolean> isDraft;
+
+ @VisibleForTesting
+ OldKeyword(boolean isUnread, boolean isFlagged, boolean isAnswered, boolean isDraft) {
+ this.isUnread = Optional.of(isUnread);
+ this.isFlagged = Optional.of(isFlagged);
+ this.isAnswered = Optional.of(isAnswered);
+ this.isDraft = Optional.of(isDraft);
+ }
+
+ public OldKeyword(Optional<Boolean> isUnread, Optional<Boolean> isFlagged, Optional<Boolean> isAnswered, Optional<Boolean> isDraft) {
+ this.isUnread = isUnread;
+ this.isFlagged = isFlagged;
+ this.isAnswered = isAnswered;
+ this.isDraft = isDraft;
+ }
+
+ public Optional<Boolean> isUnread() {
+ return isUnread;
+ }
+
+ public Optional<Boolean> isFlagged() {
+ return isFlagged;
+ }
+
+ public Optional<Boolean> isAnswered() {
+ return isAnswered;
+ }
+
+ public Optional<Boolean> isDraft() {
+ return isDraft;
+ }
+
+ @Override
+ public final boolean equals(Object other) {
+ if (other instanceof OldKeyword) {
+ OldKeyword oldKeyword = (OldKeyword) other;
+ return Objects.equal(isUnread, oldKeyword.isUnread)
+ && Objects.equal(isFlagged, oldKeyword.isFlagged)
+ && Objects.equal(isAnswered, oldKeyword.isAnswered)
+ && Objects.equal(isDraft, oldKeyword.isDraft);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hashCode(isUnread, isFlagged, isAnswered, isDraft);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("isUnread", isUnread)
+ .add("isFlagged", isFlagged)
+ .add("isAnswered", isAnswered)
+ .add("isDraft", isDraft)
+ .toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
new file mode 100644
index 0000000..12fcf0a
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
@@ -0,0 +1,189 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import java.util.Optional;
+import javax.mail.Flags;
+
+import org.apache.commons.lang3.StringUtils;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class KeywordTest {
+ private final static String FORWARDED = "forwarded";
+ private final static int FLAG_NAME_MAX_LENTH = 255;
+ private final static String ANY_KEYWORD = "AnyKeyword";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(Keyword.class).verify();
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameLengthLessThanMinLength() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameLengthMoreThanMaxLength() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword(StringUtils.repeat("a", FLAG_NAME_MAX_LENTH + 1));
+ }
+
+ @Test
+ public void keywordShouldCreateNewOneWhenFlagNameLengthEqualsMaxLength() throws Exception {
+ String maxLengthFlagName = StringUtils.repeat("a", FLAG_NAME_MAX_LENTH);
+ Keyword keyword = new Keyword(maxLengthFlagName);
+
+ assertThat(keyword.getFlagName()).isEqualTo(maxLengthFlagName);
+ }
+
+ @Test
+ public void keywordShouldCreateNewOneWhenFlagNameLengthEqualsMinLength() throws Exception {
+ String minLengthFlagName = "a";
+ Keyword keyword = new Keyword(minLengthFlagName);
+
+ assertThat(keyword.getFlagName()).isEqualTo(minLengthFlagName);
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsPercentageCharacter() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a%");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsLeftBracket() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a[");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsRightBracket() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a]");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsLeftBrace() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a{");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsSlash() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a\\");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsStar() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a*");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsQuote() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a\"");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsOpeningParenthesis() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a(");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsClosingParenthesis() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a)");
+ }
+
+ @Test
+ public void keywordShouldThrowWhenFlagNameContainsSpaceCharacter() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ new Keyword("a b");
+ }
+
+ @Test
+ public void isNotNonExposedImapKeywordShouldReturnFalseWhenDeleted() throws Exception {
+ assertThat(Keyword.DELETED.isExposedImapKeyword()).isFalse();
+ }
+
+ @Test
+ public void isNotNonExposedImapKeywordShouldReturnFalseWhenRecent() throws Exception {
+ assertThat(Keyword.RECENT.isExposedImapKeyword()).isFalse();
+ }
+
+ @Test
+ public void isNotNonExposedImapKeywordShouldReturnTrueWhenOtherSystemFlag() throws Exception {
+ assertThat(Keyword.DRAFT.isExposedImapKeyword()).isTrue();
+ }
+
+ @Test
+ public void isNotNonExposedImapKeywordShouldReturnTrueWhenAnyUserFlag() throws Exception {
+ Keyword keyword = new Keyword(ANY_KEYWORD);
+ assertThat(keyword.isExposedImapKeyword()).isTrue();
+ }
+
+ @Test
+ public void isDraftShouldReturnTrueWhenDraft() throws Exception {
+ assertThat(Keyword.DRAFT.isDraft()).isTrue();
+ }
+
+ @Test
+ public void isDraftShouldReturnFalseWhenNonDraft() throws Exception {
+ assertThat(Keyword.DELETED.isDraft()).isFalse();
+ }
+
+ @Test
+ public void asSystemFlagShouldReturnSystemFlag() throws Exception {
+ assertThat(new Keyword("$Draft").asSystemFlag())
+ .isEqualTo(Optional.of(Flags.Flag.DRAFT));
+ }
+
+ @Test
+ public void asSystemFlagShouldReturnEmptyWhenNonSystemFlag() throws Exception {
+ assertThat(new Keyword(ANY_KEYWORD).asSystemFlag().isPresent())
+ .isFalse();
+ }
+
+ @Test
+ public void asFlagsShouldReturnFlagsWhenSystemFlag() throws Exception {
+ assertThat(Keyword.DELETED.asFlags())
+ .isEqualTo(new Flags(Flags.Flag.DELETED));
+ }
+
+ @Test
+ public void asFlagsShouldReturnFlagsWhenUserFlag() throws Exception {
+ Keyword keyword = new Keyword(ANY_KEYWORD);
+ assertThat(keyword.asFlags())
+ .isEqualTo(new Flags(ANY_KEYWORD));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordsTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordsTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordsTest.java
new file mode 100644
index 0000000..e992c59
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordsTest.java
@@ -0,0 +1,328 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import java.util.Map;
+import java.util.Optional;
+import javax.mail.Flags;
+import javax.mail.Flags.Flag;
+
+import org.apache.james.mailbox.FlagsBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class KeywordsTest {
+ public static final String ANY_KEYWORD = "AnyKeyword";
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(Keywords.class).verify();
+ }
+
+ @Test
+ public void fromMapShouldThrowWhenWrongKeywordValue() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ Keywords.factory()
+ .fromMap(ImmutableMap.of(ANY_KEYWORD, false));
+ }
+
+ @Test
+ public void fromMapShouldReturnKeywordsFromMapStringAndBoolean() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .fromMap(ImmutableMap.of(ANY_KEYWORD, Keyword.FLAG_VALUE));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(new Keyword(ANY_KEYWORD));
+ }
+
+ @Test
+ public void fromFlagsShouldReturnKeywordsFromAllFlag() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .fromFlags(new Flags(Flags.Flag.ANSWERED));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED);
+ }
+
+ @Test
+ public void fromSetShouldReturnKeywordsFromSetOfKeywords() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED);
+ }
+
+ @Test
+ public void fromOldKeywordsShouldReturnKeywordsFromIsAnswered() throws Exception {
+ Optional<Boolean> isAnswered = Optional.of(true);
+ Optional<Boolean> isUnread = Optional.empty();
+ Optional<Boolean> isFlagged = Optional.empty();
+ Optional<Boolean> isDraft = Optional.empty();
+ Keywords keywords = Keywords.factory()
+ .fromOldKeyword(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED);
+ }
+
+ @Test
+ public void fromOldKeywordsShouldReturnKeywordsFromIsDraft() throws Exception {
+ Optional<Boolean> isAnswered = Optional.empty();
+ Optional<Boolean> isUnread = Optional.empty();
+ Optional<Boolean> isFlagged = Optional.empty();
+ Optional<Boolean> isDraft = Optional.of(true);
+ Keywords keywords = Keywords.factory()
+ .fromOldKeyword(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.DRAFT);
+ }
+
+ @Test
+ public void fromOldKeywordsShouldReturnKeywordsFromIsFlagged() throws Exception {
+ Optional<Boolean> isAnswered = Optional.empty();
+ Optional<Boolean> isUnread = Optional.empty();
+ Optional<Boolean> isFlagged = Optional.of(true);
+ Optional<Boolean> isDraft = Optional.empty();
+ Keywords keywords = Keywords.factory()
+ .fromOldKeyword(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.FLAGGED);
+ }
+
+ @Test
+ public void fromOldKeywordsShouldReturnKeywordsFromIsUnread() throws Exception {
+ Optional<Boolean> isAnswered = Optional.empty();
+ Optional<Boolean> isUnread = Optional.of(false);
+ Optional<Boolean> isFlagged = Optional.empty();
+ Optional<Boolean> isDraft = Optional.empty();
+ Keywords keywords = Keywords.factory()
+ .fromOldKeyword(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.SEEN);
+ }
+
+ @Test
+ public void fromOldKeywordsShouldReturnKeywordsFromIsFlag() throws Exception {
+ Optional<Boolean> isAnswered = Optional.of(true);
+ Optional<Boolean> isUnread = Optional.of(true);
+ Optional<Boolean> isFlagged = Optional.of(true);
+ Optional<Boolean> isDraft = Optional.of(true);
+ Keywords keywords = Keywords.factory()
+ .fromOldKeyword(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED, Keyword.DRAFT, Keyword.FLAGGED);
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldReturnEmptyWhenBothAreEmpty() throws Exception {
+ assertThat(Keywords.factory()
+ .fromMapOrOldKeyword(Optional.empty(), Optional.empty()))
+ .isEmpty();
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldReturnKeywordsWhenMap() throws Exception {
+ assertThat(Keywords.factory()
+ .fromMapOrOldKeyword(Optional.of(ImmutableMap.of()), Optional.empty()))
+ .isPresent();
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldReturnKeywordsWhenOldKeyword() throws Exception {
+ Optional<Boolean> isAnswered = Optional.of(true);
+ Optional<Boolean> isUnread = Optional.of(true);
+ Optional<Boolean> isFlagged = Optional.of(true);
+ Optional<Boolean> isDraft = Optional.of(true);
+
+ OldKeyword oldKeyword = new OldKeyword(isUnread, isFlagged, isAnswered, isDraft);
+
+ assertThat(Keywords.factory()
+ .fromMapOrOldKeyword(Optional.empty(), Optional.of(oldKeyword)))
+ .isPresent();
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldThrownWhenBothMapAndOldKeyword() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ Optional<Boolean> isAnswered = Optional.of(true);
+ Optional<Boolean> isUnread = Optional.of(true);
+ Optional<Boolean> isFlagged = Optional.of(true);
+ Optional<Boolean> isDraft = Optional.of(true);
+
+ OldKeyword oldKeyword = new OldKeyword(isUnread, isFlagged, isAnswered, isDraft);
+
+ Keywords.factory()
+ .fromMapOrOldKeyword(Optional.of(ImmutableMap.of()), Optional.of(oldKeyword));
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldReturnKeywordsFromMap() throws Exception {
+ ImmutableMap<String, Boolean> mapKeywords = ImmutableMap.of(ANY_KEYWORD, Keyword.FLAG_VALUE);
+
+ assertThat(Keywords.factory()
+ .fromMapOrOldKeyword(Optional.of(mapKeywords), Optional.empty())
+ .get()
+ .getKeywords())
+ .containsOnly(new Keyword(ANY_KEYWORD));
+ }
+
+ @Test
+ public void fromMapOrOldKeywordShouldReturnKeywordsFromOldKeyword() throws Exception {
+ Optional<Boolean> isAnswered = Optional.of(true);
+ Optional<Boolean> isUnread = Optional.of(true);
+ Optional<Boolean> isFlagged = Optional.of(true);
+ Optional<Boolean> isDraft = Optional.of(true);
+
+ OldKeyword oldKeyword = new OldKeyword(isUnread, isFlagged, isAnswered, isDraft);
+
+ Keywords keywords = Keywords.factory()
+ .fromMapOrOldKeyword(Optional.empty(), Optional.of(oldKeyword))
+ .get();
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED, Keyword.DRAFT, Keyword.FLAGGED);
+ }
+
+ @Test
+ public void asFlagsShouldBuildFlagsFromKeywords() throws Exception {
+ assertThat(Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED))
+ .asFlags())
+ .isEqualTo(new Flags(Flags.Flag.ANSWERED));
+ }
+
+ @Test
+ public void asFlagsWithRecentAndDeletedFromShouldBuildFlagsFromKeywordsAndRecentOriginFlags() throws Exception {
+ Flags originFlags = FlagsBuilder.builder()
+ .add(Flag.RECENT, Flag.DRAFT)
+ .build();
+
+ Flags expectedFlags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.RECENT)
+ .build();
+
+ assertThat(Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED))
+ .asFlagsWithRecentAndDeletedFrom(originFlags))
+ .isEqualTo(expectedFlags);
+ }
+
+ @Test
+ public void asFlagsWithRecentAndDeletedFromShouldBuildFlagsFromKeywordsWithDeletedAndRecentOriginFlags() throws Exception {
+ Flags originFlags = FlagsBuilder.builder()
+ .add(Flag.RECENT, Flag.DELETED, Flag.DRAFT)
+ .build();
+
+ Flags expectedFlags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.RECENT, Flag.DELETED)
+ .build();
+
+ assertThat(Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED))
+ .asFlagsWithRecentAndDeletedFrom(originFlags))
+ .isEqualTo(expectedFlags);
+ }
+
+ @Test
+ public void asMapShouldReturnEmptyWhenEmptyMapOfStringAndBoolean() throws Exception {
+ assertThat(Keywords.factory()
+ .fromSet(ImmutableSet.of())
+ .asMap())
+ .isEmpty();;
+ }
+
+ @Test
+ public void asMapShouldReturnMapOfStringAndBoolean() throws Exception {
+ Map<String, Boolean> expectedMap = ImmutableMap.of("$Answered", Keyword.FLAG_VALUE);
+ assertThat(Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED))
+ .asMap())
+ .isEqualTo(expectedMap);
+ }
+
+ @Test
+ public void throwWhenUnsupportedKeywordShouldThrowWhenHaveUnsupportedKeywords() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ Keywords.factory()
+ .throwOnImapNonExposedKeywords()
+ .fromSet(ImmutableSet.of(Keyword.DRAFT, Keyword.DELETED));
+ }
+
+ @Test
+ public void throwWhenUnsupportedKeywordShouldNotThrowWhenHaveDraft() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .throwOnImapNonExposedKeywords()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED, Keyword.DRAFT));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED, Keyword.DRAFT);
+ }
+
+ @Test
+ public void filterUnsupportedShouldFilter() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .filterImapNonExposedKeywords()
+ .fromSet(ImmutableSet.of(Keyword.ANSWERED, Keyword.DELETED, Keyword.RECENT, Keyword.DRAFT));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED, Keyword.DRAFT);
+ }
+
+ @Test
+ public void containsShouldReturnTrueWhenKeywordsContainKeyword() {
+ Keywords keywords = Keywords.factory()
+ .fromSet(ImmutableSet.of(Keyword.SEEN));
+
+ assertThat(keywords.contains(Keyword.SEEN)).isTrue();
+ }
+
+ @Test
+ public void containsShouldReturnFalseWhenKeywordsDoNotContainKeyword() {
+ Keywords keywords = Keywords.factory()
+ .fromSet(ImmutableSet.of());
+
+ assertThat(keywords.contains(Keyword.SEEN)).isFalse();
+ }
+
+ @Test
+ public void fromListShouldReturnKeywordsFromListOfStrings() throws Exception {
+ Keywords keywords = Keywords.factory()
+ .fromList(ImmutableList.of("$Answered", "$Flagged"));
+
+ assertThat(keywords.getKeywords())
+ .containsOnly(Keyword.ANSWERED, Keyword.FLAGGED);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/20beee7a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/OldKeywordTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/OldKeywordTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/OldKeywordTest.java
new file mode 100644
index 0000000..024271a
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/OldKeywordTest.java
@@ -0,0 +1,31 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.Test;
+
+public class OldKeywordTest {
+ @Test
+ public void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(OldKeyword.class).verify();
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[02/13] james-project git commit: JAMES-2110 GetMessageList should
allow filtering by keywords
Posted by bt...@apache.org.
JAMES-2110 GetMessageList should allow filtering by keywords
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/a6f1c105
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/a6f1c105
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/a6f1c105
Branch: refs/heads/master
Commit: a6f1c1059d20dd179e9f5feb2e3374c38869cfed
Parents: 92365a2
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:45:26 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:27 2017 +0200
----------------------------------------------------------------------
.../james/jmap/model/FilterCondition.java | 48 ++++++++++--
.../james/jmap/utils/FilterToSearchQuery.java | 27 ++++++-
.../james/jmap/model/FilterConditionTest.java | 77 +++++++++++++++++++-
.../jmap/utils/FilterToSearchQueryTest.java | 52 +++++++++++++
4 files changed, 196 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/a6f1c105/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/FilterCondition.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/FilterCondition.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/FilterCondition.java
index 63663c5..334667d 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/FilterCondition.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/FilterCondition.java
@@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@JsonDeserialize(builder = FilterCondition.Builder.class)
@@ -60,10 +61,14 @@ public class FilterCondition implements Filter {
private String subject;
private String body;
private Header header;
+ private Optional<String> hasKeyword;
+ private Optional<String> notKeyword;
private Builder() {
inMailboxes = Optional.empty();
notInMailboxes = Optional.empty();
+ hasKeyword = Optional.empty();
+ notKeyword = Optional.empty();
}
public Builder inMailboxes(String... inMailboxes) {
@@ -88,6 +93,18 @@ public class FilterCondition implements Filter {
return this;
}
+ @JsonDeserialize
+ public Builder hasKeyword(Optional<String> hasKeyword) {
+ this.hasKeyword = hasKeyword;
+ return this;
+ }
+
+ @JsonDeserialize
+ public Builder notKeyword(Optional<String> notKeyword) {
+ this.notKeyword = notKeyword;
+ return this;
+ }
+
public Builder before(ZonedDateTime before) {
this.before = before;
return this;
@@ -174,9 +191,12 @@ public class FilterCondition implements Filter {
}
public FilterCondition build() {
+ Preconditions.checkArgument(!hasKeyword.isPresent() || (new Keyword(hasKeyword.get()) != null), "hasKeyword is not valid");
+ Preconditions.checkArgument(!notKeyword.isPresent() || (new Keyword(notKeyword.get()) != null), "notKeyword is not valid");
return new FilterCondition(inMailboxes, notInMailboxes, Optional.ofNullable(before), Optional.ofNullable(after), Optional.ofNullable(minSize), Optional.ofNullable(maxSize),
Optional.ofNullable(isFlagged), Optional.ofNullable(isUnread), Optional.ofNullable(isAnswered), Optional.ofNullable(isDraft), Optional.ofNullable(hasAttachment),
- Optional.ofNullable(text), Optional.ofNullable(from), Optional.ofNullable(to), Optional.ofNullable(cc), Optional.ofNullable(bcc), Optional.ofNullable(subject), Optional.ofNullable(body), Optional.ofNullable(header));
+ Optional.ofNullable(text), Optional.ofNullable(from), Optional.ofNullable(to), Optional.ofNullable(cc), Optional.ofNullable(bcc), Optional.ofNullable(subject),
+ Optional.ofNullable(body), Optional.ofNullable(header), hasKeyword, notKeyword);
}
}
@@ -199,10 +219,13 @@ public class FilterCondition implements Filter {
private final Optional<String> subject;
private final Optional<String> body;
private final Optional<Header> header;
+ private final Optional<String> hasKeyword;
+ private final Optional<String> notKeyword;
@VisibleForTesting FilterCondition(Optional<List<String>> inMailboxes, Optional<List<String>> notInMailboxes, Optional<ZonedDateTime> before, Optional<ZonedDateTime> after, Optional<Integer> minSize, Optional<Integer> maxSize,
- Optional<Boolean> isFlagged, Optional<Boolean> isUnread, Optional<Boolean> isAnswered, Optional<Boolean> isDraft, Optional<Boolean> hasAttachment,
- Optional<String> text, Optional<String> from, Optional<String> to, Optional<String> cc, Optional<String> bcc, Optional<String> subject, Optional<String> body, Optional<Header> header) {
+ Optional<Boolean> isFlagged, Optional<Boolean> isUnread, Optional<Boolean> isAnswered, Optional<Boolean> isDraft, Optional<Boolean> hasAttachment,
+ Optional<String> text, Optional<String> from, Optional<String> to, Optional<String> cc, Optional<String> bcc, Optional<String> subject,
+ Optional<String> body, Optional<Header> header, Optional<String> hasKeyword, Optional<String> notKeyword) {
this.inMailboxes = inMailboxes;
this.notInMailboxes = notInMailboxes;
@@ -223,6 +246,8 @@ public class FilterCondition implements Filter {
this.subject = subject;
this.body = body;
this.header = header;
+ this.hasKeyword = hasKeyword;
+ this.notKeyword = notKeyword;
}
public Optional<List<String>> getInMailboxes() {
@@ -301,6 +326,14 @@ public class FilterCondition implements Filter {
return header;
}
+ public Optional<String> getHasKeyword() {
+ return hasKeyword;
+ }
+
+ public Optional<String> getNotKeyword() {
+ return notKeyword;
+ }
+
@Override
public final boolean equals(Object obj) {
if (obj instanceof FilterCondition) {
@@ -323,14 +356,17 @@ public class FilterCondition implements Filter {
&& Objects.equals(this.bcc, other.bcc)
&& Objects.equals(this.subject, other.subject)
&& Objects.equals(this.body, other.body)
- && Objects.equals(this.header, other.header);
+ && Objects.equals(this.header, other.header)
+ && Objects.equals(this.hasKeyword, other.hasKeyword)
+ && Objects.equals(this.notKeyword, other.notKeyword);
}
return false;
}
@Override
public final int hashCode() {
- return Objects.hash(inMailboxes, notInMailboxes, before, after, minSize, maxSize, isFlagged, isUnread, isAnswered, isDraft, hasAttachment, text, from, to, cc, bcc, subject, body, header);
+ return Objects.hash(inMailboxes, notInMailboxes, before, after, minSize, maxSize, isFlagged, isUnread, isAnswered, isDraft, hasAttachment,
+ text, from, to, cc, bcc, subject, body, header, hasKeyword, notKeyword);
}
@Override
@@ -355,6 +391,8 @@ public class FilterCondition implements Filter {
subject.ifPresent(x -> helper.add("subject", x));
body.ifPresent(x -> helper.add("body", x));
header.ifPresent(x -> helper.add("header", x));
+ hasKeyword.ifPresent(x -> helper.add("hasKeyword", x));
+ notKeyword.ifPresent(x -> helper.add("notKeyword", x));
return helper.toString();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/a6f1c105/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/FilterToSearchQuery.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/FilterToSearchQuery.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/FilterToSearchQuery.java
index 95799e4..f619357 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/FilterToSearchQuery.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/FilterToSearchQuery.java
@@ -20,12 +20,13 @@
package org.apache.james.jmap.utils;
import java.util.Date;
-
+import java.util.Optional;
import javax.mail.Flags.Flag;
import org.apache.james.jmap.model.Filter;
import org.apache.james.jmap.model.FilterCondition;
import org.apache.james.jmap.model.FilterOperator;
+import org.apache.james.jmap.model.Keyword;
import org.apache.james.mailbox.model.SearchQuery;
import org.apache.james.mailbox.model.SearchQuery.AddressType;
import org.apache.james.mailbox.model.SearchQuery.Criterion;
@@ -75,9 +76,33 @@ public class FilterToSearchQuery {
filter.getMaxSize().ifPresent(maxSize -> searchQuery.andCriteria(SearchQuery.sizeLessThan(maxSize)));
filter.getMinSize().ifPresent(minSize -> searchQuery.andCriteria(SearchQuery.sizeGreaterThan(minSize)));
filter.getHasAttachment().ifPresent(hasAttachment -> searchQuery.andCriteria(SearchQuery.hasAttachment(hasAttachment)));
+ filter.getHasKeyword().ifPresent(hasKeyword -> {
+ keywordQuery(hasKeyword, true).ifPresent(hasKeywordCriterion
+ -> searchQuery.andCriteria(hasKeywordCriterion));
+ });
+ filter.getNotKeyword().ifPresent(notKeyword -> {
+ keywordQuery(notKeyword, false).ifPresent(notKeywordCriterion
+ -> searchQuery.andCriteria(notKeywordCriterion));
+ });
+
return searchQuery;
}
+ private Optional<Criterion> keywordQuery(String stringKeyword, boolean isSet) {
+ Keyword keyword = new Keyword(stringKeyword);
+ if (keyword.isExposedImapKeyword()) {
+ return Optional.of(getFlagCriterion(keyword, isSet));
+ }
+
+ return Optional.empty();
+ }
+
+ private Criterion getFlagCriterion(Keyword keyword, boolean isSet) {
+ return keyword.asSystemFlag()
+ .map(flag -> SearchQuery.flagSet(flag, isSet))
+ .orElse(SearchQuery.flagSet(keyword.getFlagName(), isSet));
+ }
+
private Criterion convertOperator(FilterOperator filter) {
switch (filter.getOperator()) {
case AND:
http://git-wip-us.apache.org/repos/asf/james-project/blob/a6f1c105/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/FilterConditionTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/FilterConditionTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/FilterConditionTest.java
index 5a518f0..5efaecc 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/FilterConditionTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/FilterConditionTest.java
@@ -23,15 +23,22 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.time.ZonedDateTime;
import java.util.Optional;
+import java.util.Set;
+import org.junit.Rule;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.rules.ExpectedException;
public class FilterConditionTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
@Test
public void buildShouldWorkWhenNoInMailboxes() {
FilterCondition filterCondition = FilterCondition.builder().build();
@@ -89,9 +96,13 @@ public class FilterConditionTest {
String subject = "subject";
String body = "body";
Header header = Header.from(ImmutableList.of("name", "value"));
- FilterCondition expectedFilterCondition = new FilterCondition(Optional.of(ImmutableList.of("1")), Optional.of(ImmutableList.of("2")), Optional.of(before), Optional.of(after), Optional.of(minSize), Optional.of(maxSize),
+ Optional<String> hasKeyword = Optional.of("$Draft");
+ Optional<String> notKeyword = Optional.of("$Flagged");
+
+ FilterCondition expectedFilterCondition = new FilterCondition(Optional.of(ImmutableList.of("1")), Optional.of(ImmutableList.of("2")), Optional.of(before), Optional.of(after), Optional.of(minSize), Optional.of(maxSize),
Optional.of(isFlagged), Optional.of(isUnread), Optional.of(isAnswered), Optional.of(isDraft), Optional.of(hasAttachment), Optional.of(text), Optional.of(from),
- Optional.of(to), Optional.of(cc), Optional.of(bcc), Optional.of(subject), Optional.of(body), Optional.of(header));
+ Optional.of(to), Optional.of(cc), Optional.of(bcc), Optional.of(subject), Optional.of(body), Optional.of(header),
+ hasKeyword, notKeyword);
FilterCondition filterCondition = FilterCondition.builder()
.inMailboxes(Optional.of(ImmutableList.of("1")))
@@ -113,6 +124,8 @@ public class FilterConditionTest {
.subject(subject)
.body(body)
.header(header)
+ .hasKeyword(hasKeyword)
+ .notKeyword(notKeyword)
.build();
assertThat(filterCondition).isEqualToComparingFieldByField(expectedFilterCondition);
@@ -122,4 +135,64 @@ public class FilterConditionTest {
public void shouldRespectJavaBeanContract() {
EqualsVerifier.forClass(FilterCondition.class).verify();
}
+
+ @Test
+ public void buildShouldBuildFilterConditionWithHasKeywordWhenGivenHasKeyword() {
+ String hasKeyword = "$Draft";
+
+ FilterCondition filterCondition = FilterCondition.builder()
+ .hasKeyword(Optional.of(hasKeyword))
+ .build();
+
+ assertThat(filterCondition.getHasKeyword().get())
+ .isEqualTo(hasKeyword);
+ }
+
+ @Test
+ public void buildShouldBuildFilterConditionWithoutHasKeywordWhenDoNotGivenHasKeyword() {
+ FilterCondition filterCondition = FilterCondition.builder()
+ .hasKeyword(Optional.empty())
+ .build();
+
+ assertThat(filterCondition.getHasKeyword().isPresent())
+ .isFalse();
+ }
+
+ @Test
+ public void buildShouldThrowWhenGivenInvalidKeywordAsHasKeyword() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ FilterCondition.builder()
+ .hasKeyword(Optional.of("$Draft%"))
+ .build();
+ }
+
+ @Test
+ public void buildShouldBuildFilterConditionWithNotKeywordWhenGivenNotKeyword() {
+ String notKeyword = "$Draft";
+
+ FilterCondition filterCondition = FilterCondition.builder()
+ .notKeyword(Optional.of(notKeyword))
+ .build();
+ assertThat(filterCondition.getNotKeyword().get()).isEqualTo(notKeyword);
+ }
+
+ @Test
+ public void buildShouldBuildFilterConditionWithoutNotKeywordWhenDoNotGivenNotKeyword() {
+ FilterCondition filterCondition = FilterCondition.builder()
+ .notKeyword(Optional.empty())
+ .build();
+
+ assertThat(filterCondition.getNotKeyword().isPresent())
+ .isFalse();
+ }
+
+ @Test
+ public void buildShouldThrowWhenGivenInvalidKeywordAsNotKeyword() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ FilterCondition.builder()
+ .notKeyword(Optional.of("$Draft%"))
+ .build();
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/a6f1c105/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/FilterToSearchQueryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/FilterToSearchQueryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/FilterToSearchQueryTest.java
index eb05436..aca9757 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/FilterToSearchQueryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/FilterToSearchQueryTest.java
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.time.ZonedDateTime;
import java.util.Date;
+import java.util.Optional;
import javax.mail.Flags.Flag;
@@ -31,14 +32,17 @@ import org.apache.james.jmap.model.Filter;
import org.apache.james.jmap.model.FilterCondition;
import org.apache.james.jmap.model.FilterOperator;
import org.apache.james.jmap.model.Header;
+import org.apache.james.jmap.model.Keyword;
import org.apache.james.mailbox.model.SearchQuery;
import org.apache.james.mailbox.model.SearchQuery.AddressType;
import org.apache.james.mailbox.model.SearchQuery.DateResolution;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
public class FilterToSearchQueryTest {
+ private final static String FORWARDED = "forwarded";
@Test
public void filterConditionShouldThrowWhenUnknownFilter() {
@@ -476,4 +480,52 @@ public class FilterToSearchQueryTest {
assertThat(searchQuery).isEqualTo(expectedSearchQuery);
}
+
+ @Test
+ public void filterConditionShouldMapWhenHasKeyword() {
+ SearchQuery expectedSearchQuery = new SearchQuery();
+ expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.FLAGGED));
+
+ SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
+ .hasKeyword(Optional.of("$Flagged"))
+ .build());
+
+ assertThat(searchQuery).isEqualTo(expectedSearchQuery);
+ }
+
+ @Test
+ public void filterConditionShouldMapWhenHasKeywordWithUserFlag() {
+ SearchQuery expectedSearchQuery = new SearchQuery();
+ expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(FORWARDED));
+
+ SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
+ .hasKeyword(Optional.of(FORWARDED))
+ .build());
+
+ assertThat(searchQuery).isEqualTo(expectedSearchQuery);
+ }
+
+ @Test
+ public void filterConditionShouldMapWhenNotKeyword() {
+ SearchQuery expectedSearchQuery = new SearchQuery();
+ expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.FLAGGED));
+
+ SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
+ .notKeyword(Optional.of("$Flagged"))
+ .build());
+
+ assertThat(searchQuery).isEqualTo(expectedSearchQuery);
+ }
+
+ @Test
+ public void filterConditionShouldMapWhenNotKeywordWithUserFlag() {
+ SearchQuery expectedSearchQuery = new SearchQuery();
+ expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(FORWARDED));
+
+ SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
+ .notKeyword(Optional.of(FORWARDED))
+ .build());
+
+ assertThat(searchQuery).isEqualTo(expectedSearchQuery);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[08/13] james-project git commit: JAMES-2110 IT for getMessages which
return keywords of imap flags
Posted by bt...@apache.org.
JAMES-2110 IT for getMessages which return keywords of imap flags
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/41e3d15d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/41e3d15d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/41e3d15d
Branch: refs/heads/master
Commit: 41e3d15d299a7d86dcc70a47eaab69f0d2c9c58c
Parents: 37cf8ff
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:48:11 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:28 2017 +0200
----------------------------------------------------------------------
.../cucumber/GetMessagesMethodStepdefs.java | 38 +++++-
.../test/resources/cucumber/GetMessages.feature | 33 +++++
.../jmap/methods/GetMessagesMethodTest.java | 135 ++++++++++++++++++-
3 files changed, 193 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/41e3d15d/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
index 13200f9..f42a071 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
@@ -42,6 +42,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Request;
import org.apache.james.jmap.DefaultMailboxes;
import org.apache.james.jmap.methods.integration.cucumber.util.TableRow;
+import org.apache.james.jmap.model.Keywords;
import org.apache.james.jmap.model.MessagePreviewGenerator;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
@@ -84,11 +85,11 @@ public class GetMessagesMethodStepdefs {
private final MainStepdefs mainStepdefs;
private final UserStepdefs userStepdefs;
private final Map<String, MessageId> messageIdsByName;
-
+
private HttpResponse response;
private DocumentContext jsonPath;
private List<MessageId> requestedMessageIds;
-
+
@Inject
private GetMessagesMethodStepdefs(MainStepdefs mainStepdefs, UserStepdefs userStepdefs) {
this.mainStepdefs = mainStepdefs;
@@ -147,9 +148,9 @@ public class GetMessagesMethodStepdefs {
private MessageId appendMessage(String mailbox, ContentType contentType, String subject, String content, Optional<Map<String, String>> headers) throws Exception {
ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z");
- return mainStepdefs.jmapServer.getProbe(MailboxProbeImpl.class).appendMessage(userStepdefs.lastConnectedUser,
+ return mainStepdefs.jmapServer.getProbe(MailboxProbeImpl.class).appendMessage(userStepdefs.lastConnectedUser,
new MailboxPath(MailboxConstants.USER_NAMESPACE, userStepdefs.lastConnectedUser, mailbox),
- new ByteArrayInputStream(message(contentType, subject, content, headers).getBytes(Charsets.UTF_8)),
+ new ByteArrayInputStream(message(contentType, subject, content, headers).getBytes(Charsets.UTF_8)),
Date.from(dateTime.toInstant()), false, new Flags()).getMessageId();
}
@@ -246,6 +247,25 @@ public class GetMessagesMethodStepdefs {
appendMessage(messageName, "eml/htmlWithLongAndComplicatedContent.eml");
}
+ @Given("^the user has a message \"([^\"]*)\" in the \"([^\"]*)\" mailbox with flags \"([^\"]*)\"$")
+ public void appendMessageWithFlags(String messageName, String mailbox, List<String> keywords) throws Exception {
+ Flags flags = Keywords.factory()
+ .fromList(keywords)
+ .asFlags();
+ appendMessage(messageName, flags);
+ }
+
+ private void appendMessage(String messageName, Flags flags) throws Exception {
+ ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z");
+ boolean isRecent = flags.contains(Flags.Flag.RECENT);
+ MessageId id = mainStepdefs.jmapServer.getProbe(MailboxProbeImpl.class).appendMessage(userStepdefs.lastConnectedUser,
+ new MailboxPath(MailboxConstants.USER_NAMESPACE, userStepdefs.lastConnectedUser, DefaultMailboxes.INBOX),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
+ Date.from(dateTime.toInstant()), isRecent, flags)
+ .getMessageId();
+ messageIdsByName.put(messageName, id);
+ }
+
private void appendMessage(String messageName, String emlFileName) throws Exception {
ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z");
MessageId id = mainStepdefs.jmapServer.getProbe(MailboxProbeImpl.class).appendMessage(userStepdefs.lastConnectedUser,
@@ -377,12 +397,12 @@ public class GetMessagesMethodStepdefs {
assertThat(jsonPath.<List<String>>read(ARGUMENTS + ".notFound")).containsExactlyElementsOf(elements);
}
-
+
@Then("^the list should contain (\\d+) message$")
public void assertListContains(int numberOfMessages) throws Exception {
assertThat(jsonPath.<List<String>>read(ARGUMENTS + ".list")).hasSize(numberOfMessages);
}
-
+
@Then("^the id of the message is \"([^\"]*)\"$")
public void assertIdOfTheFirstMessage(String messageName) throws Exception {
MessageId id = messageIdsByName.get(messageName);
@@ -503,6 +523,12 @@ public class GetMessagesMethodStepdefs {
assertThat(actual).contains(preview);
}
+ @Then("^the keywords of the message is (.*)$")
+ public void assertKeywordsOfMessageShouldDisplay(List<String> keywords) throws Exception {
+ assertThat(jsonPath.<Map<String, Boolean>>read(FIRST_MESSAGE + ".keywords").keySet())
+ .containsOnlyElementsOf(keywords);
+ }
+
private void assertAttachment(String attachment, DataTable attachmentProperties) {
attachmentProperties.asList(TableRow.class)
.forEach(entry -> assertThat(jsonPath.<Object>read(attachment + "." + entry.getKey())).isEqualTo(entry.getValue()));
http://git-wip-us.apache.org/repos/asf/james-project/blob/41e3d15d/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
index 9f0255f..78addb9 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
@@ -318,3 +318,36 @@ Feature: GetMessages method
Examples:
|content-type |tranfer-encoding |content |preview |
|"text/html; charset=iso-8859-1" |quoted-printable |"Dans le cadre du stage effectu=E9 Mlle 2017, =E0 sign=E9e d=E8s que possible, =E0, tr=E8s, journ=E9e.." |effectué, à , signée dès, très, journée |
+
+ Scenario Outline: Retrieving message should display keywords as jmap flag
+ Given the user has a message "m1" in the "inbox" mailbox with flags <flags>
+ When the user ask for messages "m1"
+ Then no error is returned
+ And the list should contain 1 message
+ And the keywords of the message is <keyword>
+
+ Examples:
+ |flags |keyword |
+ |"$Flagged,$Answered,$Draft" |$Flagged,$Answered,$Draft |
+
+ Scenario Outline: Retrieving message should display keywords without unsupported jmap flag
+ Given the user has a message "m1" in the "inbox" mailbox with flags <flags>
+ When the user ask for messages "m1"
+ Then no error is returned
+ And the list should contain 1 message
+ And the keywords of the message is <keyword>
+
+ Examples:
+ |flags |keyword |
+ |"$Flagged,$Answered,$Deleted,$Recent" |$Flagged,$Answered |
+
+ Scenario Outline: Retrieving message should display keywords with custom user jmap flag
+ Given the user has a message "m1" in the "inbox" mailbox with flags <flags>
+ When the user ask for messages "m1"
+ Then no error is returned
+ And the list should contain 1 message
+ And the keywords of the message is <keyword>
+
+ Examples:
+ |flags |keyword |
+ |"$Flagged,$Forwarded" |$Forwarded,$Flagged |
http://git-wip-us.apache.org/repos/asf/james-project/blob/41e3d15d/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
index c403251..6d7b06a 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
@@ -23,7 +23,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-
import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.List;
@@ -34,6 +33,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import javax.mail.Flags;
+import javax.mail.Flags.Flag;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang.NotImplementedException;
@@ -46,6 +46,7 @@ import org.apache.james.jmap.model.MessagePreviewGenerator;
import org.apache.james.jmap.model.MessageProperties.MessageProperty;
import org.apache.james.jmap.utils.HtmlTextExtractor;
import org.apache.james.jmap.utils.JsoupHtmlTextExtractor;
+import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageIdManager;
@@ -60,11 +61,6 @@ import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.metrics.logger.DefaultMetricFactory;
import org.apache.james.util.mime.MessageContentExtractor;
-import org.assertj.core.api.Condition;
-import org.assertj.core.data.MapEntry;
-import org.assertj.core.groups.Tuple;
-import org.junit.Before;
-import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
@@ -72,11 +68,18 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.github.steveash.guavate.Guavate;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.jayway.jsonpath.JsonPath;
-public class GetMessagesMethodTest {
+import org.assertj.core.api.Condition;
+import org.assertj.core.data.MapEntry;
+import org.assertj.core.groups.Tuple;
+import org.junit.Before;
+import org.junit.Test;
+public class GetMessagesMethodTest {
+ private final static String FORWARDED = "forwarded";
public static final Flags FLAGS = null;
public static final boolean NOT_RECENT = false;
private MessageIdManager messageIdManager;
@@ -495,4 +498,122 @@ public class GetMessagesMethodTest {
GetMessagesResponse getMessagesResponse = (GetMessagesResponse) response;
assertThat(getMessagesResponse.list()).hasSize(1);
}
+
+ @Test
+ public void processShouldReturnKeywordsForMessageFlags() throws MailboxException {
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DRAFT)
+ .build();
+ MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+ Date now = new Date();
+ ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message1 = inbox.appendMessage(message1Content, now, session, false, flags);
+ ByteArrayInputStream message2Content = new ByteArrayInputStream("Subject: message 2 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message2 = inbox.appendMessage(message2Content, now, session, false, flags);
+ ByteArrayInputStream message3Content = new ByteArrayInputStream("Great-Header: message 3 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message3 = inbox.appendMessage(message3Content, now, session, false, flags);
+
+ GetMessagesRequest request = GetMessagesRequest.builder()
+ .ids(ImmutableList.of(message1.getMessageId(),
+ message2.getMessageId(),
+ message3.getMessageId()))
+ .build();
+
+ List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+ assertThat(result).hasSize(1)
+ .extracting(JmapResponse::getResponse)
+ .hasOnlyElementsOfType(GetMessagesResponse.class)
+ .extracting(GetMessagesResponse.class::cast)
+ .flatExtracting(GetMessagesResponse::list)
+ .extracting(Message::getKeywords)
+ .containsOnly(
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true),
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true),
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true));
+
+ }
+
+
+ @Test
+ public void processShouldReturnKeywordsWithoutUnsupportedKeywordsForMessageFlags() throws MailboxException {
+ Flags flags1 = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DRAFT, Flag.DELETED)
+ .build();
+ Flags flags2 = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DRAFT)
+ .build();
+ Flags flags3 = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DRAFT, Flag.RECENT)
+ .build();
+ MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+ Date now = new Date();
+ ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message1 = inbox.appendMessage(message1Content, now, session, false, flags1);
+ ByteArrayInputStream message2Content = new ByteArrayInputStream("Subject: message 2 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message2 = inbox.appendMessage(message2Content, now, session, false, flags2);
+ ByteArrayInputStream message3Content = new ByteArrayInputStream("Great-Header: message 3 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message3 = inbox.appendMessage(message3Content, now, session, false, flags3);
+
+ GetMessagesRequest request = GetMessagesRequest.builder()
+ .ids(ImmutableList.of(message1.getMessageId(),
+ message2.getMessageId(),
+ message3.getMessageId()))
+ .build();
+
+ List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+ assertThat(result).hasSize(1)
+ .extracting(JmapResponse::getResponse)
+ .hasOnlyElementsOfType(GetMessagesResponse.class)
+ .extracting(GetMessagesResponse.class::cast)
+ .flatExtracting(GetMessagesResponse::list)
+ .extracting(Message::getKeywords)
+ .containsOnly(
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true),
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true),
+ ImmutableMap.of(
+ "$Answered", true,
+ "$Draft", true));
+
+ }
+
+ @Test
+ public void processShouldReturnKeywordsWithoutForwardedWhenForwardedUserFlagsMessages() throws MailboxException {
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DELETED)
+ .add(FORWARDED)
+ .build();
+ MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+ Date now = new Date();
+ ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
+ ComposedMessageId message1 = inbox.appendMessage(message1Content, now, session, false, flags);
+
+ GetMessagesRequest request = GetMessagesRequest.builder()
+ .ids(ImmutableList.of(message1.getMessageId()))
+ .build();
+
+ List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+ assertThat(result).hasSize(1)
+ .extracting(JmapResponse::getResponse)
+ .hasOnlyElementsOfType(GetMessagesResponse.class)
+ .extracting(GetMessagesResponse.class::cast)
+ .flatExtracting(GetMessagesResponse::list)
+ .extracting(Message::getKeywords)
+ .containsOnly(
+ ImmutableMap.of(
+ "$Answered", true,
+ FORWARDED, true));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[06/13] james-project git commit: JAMES-2110 GetMessage should
support keywords
Posted by bt...@apache.org.
JAMES-2110 GetMessage should support keywords
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c1387efa
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c1387efa
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c1387efa
Branch: refs/heads/master
Commit: c1387efaea253d6f29577d31f8938f1ec6008841
Parents: 53fdcbd
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:40:11 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:27 2017 +0200
----------------------------------------------------------------------
.../org/apache/james/jmap/model/Message.java | 65 +++++---------
.../apache/james/jmap/model/MessageFactory.java | 6 +-
.../james/jmap/model/MessageProperties.java | 1 +
.../james/jmap/model/MessageFactoryTest.java | 94 ++++++++++++++++++--
.../james/jmap/model/MessagePropertiesTest.java | 10 ++-
.../apache/james/jmap/model/MessageTest.java | 65 +++++++-------
6 files changed, 156 insertions(+), 85 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
index 969525d..86762fe 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
+import javax.mail.Flags;
import org.apache.james.jmap.methods.GetMessagesMethod;
import org.apache.james.jmap.methods.JmapResponseWriterImpl;
@@ -57,10 +58,6 @@ public class Message {
private String threadId;
private ImmutableList<MailboxId> mailboxIds;
private String inReplyToMessageId;
- private boolean isUnread;
- private boolean isFlagged;
- private boolean isAnswered;
- private boolean isDraft;
private ImmutableMap<String, String> headers;
private Emailer from;
private final ImmutableList.Builder<Emailer> to;
@@ -75,6 +72,7 @@ public class Message {
private Optional<String> htmlBody = Optional.empty();
private final ImmutableList.Builder<Attachment> attachments;
private final ImmutableMap.Builder<BlobId, SubMessage> attachedMessages;
+ private Optional<Flags> flags = Optional.empty();
private Builder() {
to = ImmutableList.builder();
@@ -120,23 +118,8 @@ public class Message {
return this;
}
- public Builder isUnread(boolean isUnread) {
- this.isUnread = isUnread;
- return this;
- }
-
- public Builder isFlagged(boolean isFlagged) {
- this.isFlagged = isFlagged;
- return this;
- }
-
- public Builder isAnswered(boolean isAnswered) {
- this.isAnswered = isAnswered;
- return this;
- }
-
- public Builder isDraft(boolean isDraft) {
- this.isDraft = isDraft;
+ public Builder flags(Flags flags) {
+ this.flags = Optional.ofNullable(flags);
return this;
}
@@ -223,9 +206,15 @@ public class Message {
ImmutableMap<BlobId, SubMessage> attachedMessages = this.attachedMessages.build();
Preconditions.checkState(areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachements'");
boolean hasAttachment = hasAttachment(attachments);
-
- return new Message(id, blobId, threadId, mailboxIds, Optional.ofNullable(inReplyToMessageId), isUnread, isFlagged, isAnswered, isDraft, hasAttachment, headers, Optional.ofNullable(from),
- to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size, preview, textBody, htmlBody, attachments, attachedMessages);
+ Keywords keywords = flags.map(flag -> Keywords.factory()
+ .filterImapNonExposedKeywords()
+ .fromFlags(flag))
+ .orElse(Keywords.DEFAULT_VALUE);
+
+ return new Message(id, blobId, threadId, mailboxIds, Optional.ofNullable(inReplyToMessageId),
+ hasAttachment, headers, Optional.ofNullable(from),
+ to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size, preview, textBody, htmlBody, attachments, attachedMessages,
+ keywords);
}
}
@@ -250,10 +239,6 @@ public class Message {
private final String threadId;
private final ImmutableList<MailboxId> mailboxIds;
private final Optional<String> inReplyToMessageId;
- private final boolean isUnread;
- private final boolean isFlagged;
- private final boolean isAnswered;
- private final boolean isDraft;
private final boolean hasAttachment;
@JsonFilter(GetMessagesMethod.HEADERS_FILTER)
private final ImmutableMap<String, String> headers;
@@ -270,16 +255,13 @@ public class Message {
private final Optional<String> htmlBody;
private final ImmutableList<Attachment> attachments;
private final ImmutableMap<BlobId, SubMessage> attachedMessages;
+ private final Keywords keywords;
@VisibleForTesting Message(MessageId id,
BlobId blobId,
String threadId,
ImmutableList<MailboxId> mailboxIds,
Optional<String> inReplyToMessageId,
- boolean isUnread,
- boolean isFlagged,
- boolean isAnswered,
- boolean isDraft,
boolean hasAttachment,
ImmutableMap<String, String> headers,
Optional<Emailer> from,
@@ -294,16 +276,13 @@ public class Message {
Optional<String> textBody,
Optional<String> htmlBody,
ImmutableList<Attachment> attachments,
- ImmutableMap<BlobId, SubMessage> attachedMessages) {
+ ImmutableMap<BlobId, SubMessage> attachedMessages,
+ Keywords keywords) {
this.id = id;
this.blobId = blobId;
this.threadId = threadId;
this.mailboxIds = mailboxIds;
this.inReplyToMessageId = inReplyToMessageId;
- this.isUnread = isUnread;
- this.isFlagged = isFlagged;
- this.isAnswered = isAnswered;
- this.isDraft = isDraft;
this.hasAttachment = hasAttachment;
this.headers = headers;
this.from = from;
@@ -319,6 +298,7 @@ public class Message {
this.htmlBody = htmlBody;
this.attachments = attachments;
this.attachedMessages = attachedMessages;
+ this.keywords = keywords;
}
public MessageId getId() {
@@ -342,19 +322,19 @@ public class Message {
}
public boolean isIsUnread() {
- return isUnread;
+ return !keywords.contains(Keyword.SEEN);
}
public boolean isIsFlagged() {
- return isFlagged;
+ return keywords.contains(Keyword.FLAGGED);
}
public boolean isIsAnswered() {
- return isAnswered;
+ return keywords.contains(Keyword.ANSWERED);
}
public boolean isIsDraft() {
- return isDraft;
+ return keywords.contains(Keyword.DRAFT);
}
public boolean isHasAttachment() {
@@ -417,4 +397,7 @@ public class Message {
return attachedMessages;
}
+ public ImmutableMap<String, Boolean> getKeywords() {
+ return keywords.asMap();
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
index b5e5e1d..a84085b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
@@ -30,7 +30,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
-
import javax.inject.Inject;
import javax.mail.Flags;
import javax.mail.internet.SharedInputStream;
@@ -94,10 +93,7 @@ public class MessageFactory {
.threadId(message.getMessageId().serialize())
.mailboxIds(message.getMailboxIds())
.inReplyToMessageId(getHeader(mimeMessage, "in-reply-to"))
- .isUnread(! message.getFlags().contains(Flags.Flag.SEEN))
- .isFlagged(message.getFlags().contains(Flags.Flag.FLAGGED))
- .isAnswered(message.getFlags().contains(Flags.Flag.ANSWERED))
- .isDraft(message.getFlags().contains(Flags.Flag.DRAFT))
+ .flags(message.getFlags())
.subject(Strings.nullToEmpty(mimeMessage.getSubject()).trim())
.headers(toMap(mimeMessage.getHeader().getFields()))
.from(firstFromMailboxList(mimeMessage.getFrom()))
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
index d8b23db..bf1bff5 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
@@ -143,6 +143,7 @@ public class MessageProperties {
htmlBody("htmlBody"),
attachments("attachments"),
attachedMessages("attachedMessages"),
+ keywords("keywords"),
body("body", PropertyType.INPUTONLY);
private final String property;
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
index 4e0141d..76a5e14 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
@@ -19,19 +19,16 @@
package org.apache.james.jmap.model;
import static org.assertj.core.api.Assertions.assertThat;
-
import java.io.ByteArrayInputStream;
import java.time.Instant;
import java.util.Optional;
-
import javax.mail.Flags;
import javax.mail.Flags.Flag;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
import org.apache.james.jmap.utils.HtmlTextExtractor;
import org.apache.james.jmap.utils.JsoupHtmlTextExtractor;
+import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.inmemory.InMemoryId;
import org.apache.james.mailbox.model.AttachmentId;
@@ -39,14 +36,18 @@ import org.apache.james.mailbox.model.Cid;
import org.apache.james.mailbox.model.MessageAttachment;
import org.apache.james.mailbox.model.TestMessageId;
import org.apache.james.util.mime.MessageContentExtractor;
-import org.junit.Before;
-import org.junit.Test;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+
public class MessageFactoryTest {
+ private static final String FORWARDED = "forwarded";
private static final InMemoryId MAILBOX_ID = InMemoryId.of(18L);
private static final Instant INTERNAL_DATE = Instant.parse("2012-02-03T14:30:42Z");
@@ -107,6 +108,7 @@ public class MessageFactoryTest {
@Test
public void headersShouldBeSetIntoMessage() throws Exception {
+ Flags flags = new Flags(Flag.SEEN);
String headers = "From: user <us...@domain>\n"
+ "Subject: test subject\n"
+ "To: user1 <us...@domain>, user2 <us...@domain>\n"
@@ -118,7 +120,7 @@ public class MessageFactoryTest {
+ "Other-header: other header value";
MetaDataWithContent testMail = MetaDataWithContent.builder()
.uid(MessageUid.of(2))
- .flags(new Flags(Flag.SEEN))
+ .flags(flags)
.size(headers.length())
.internalDate(INTERNAL_DATE)
.content(new ByteArrayInputStream(headers.getBytes(Charsets.UTF_8)))
@@ -145,6 +147,7 @@ public class MessageFactoryTest {
.put("Date", "Tue, 14 Jul 2015 12:30:42 +0000")
.put("MIME-Version", "1.0")
.build();
+
Message testee = messageFactory.fromMetaDataWithContent(testMail);
Message expected = Message.builder()
.id(TestMessageId.of(2))
@@ -164,12 +167,14 @@ public class MessageFactoryTest {
.preview("(Empty)")
.textBody(Optional.of(""))
.htmlBody(Optional.empty())
+ .flags(flags)
.build();
assertThat(testee).isEqualToComparingFieldByField(expected);
}
@Test
public void headersShouldBeUnfoldedAndDecoded() throws Exception {
+ Flags flags = new Flags(Flag.SEEN);
String headers = "From: user <us...@domain>\n"
+ "Subject: test subject\n"
+ "To: user1 <us...@domain>,\r\n"
@@ -177,7 +182,7 @@ public class MessageFactoryTest {
+ "Cc: =?UTF-8?Q?Beno=c3=aet_TELLIER?= <te...@linagora.com>";
MetaDataWithContent testMail = MetaDataWithContent.builder()
.uid(MessageUid.of(2))
- .flags(new Flags(Flag.SEEN))
+ .flags(flags)
.size(headers.length())
.internalDate(INTERNAL_DATE)
.content(new ByteArrayInputStream(headers.getBytes(Charsets.UTF_8)))
@@ -213,7 +218,9 @@ public class MessageFactoryTest {
.preview("(Empty)")
.textBody(Optional.of(""))
.htmlBody(Optional.empty())
+ .flags(flags)
.build();
+
assertThat(testee).isEqualToComparingFieldByField(expected);
}
@@ -674,4 +681,75 @@ public class MessageFactoryTest {
.extracting(Message::getPreview, Message::getHtmlBody, Message::getTextBody)
.containsExactly("My plain message", Optional.of("<html></html>"), Optional.of("My plain message"));
}
+
+ @Test
+ public void keywordShouldBeSetIntoMessage() throws Exception {
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DRAFT)
+ .build();
+ ImmutableMap<String, Boolean> keywords = Keywords.factory()
+ .fromFlags(flags)
+ .asMap();
+
+ MetaDataWithContent testMail = MetaDataWithContent.builder()
+ .uid(MessageUid.of(2))
+ .flags(flags)
+ .size(0)
+ .internalDate(INTERNAL_DATE)
+ .content(new ByteArrayInputStream("".getBytes(Charsets.UTF_8)))
+ .attachments(ImmutableList.of())
+ .mailboxId(MAILBOX_ID)
+ .messageId(TestMessageId.of(2))
+ .build();
+ Message testee = messageFactory.fromMetaDataWithContent(testMail);
+ assertThat(testee.getKeywords()).containsAllEntriesOf(keywords);
+ }
+
+ @Test
+ public void keywordWithUserFlagShouldBeSetIntoMessage() throws Exception {
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED)
+ .add(FORWARDED)
+ .build();
+ ImmutableMap<String, Boolean> keywords = Keywords.factory()
+ .fromFlags(flags)
+ .asMap();
+ MetaDataWithContent testMail = MetaDataWithContent.builder()
+ .uid(MessageUid.of(2))
+ .flags(flags)
+ .size(0)
+ .internalDate(INTERNAL_DATE)
+ .content(new ByteArrayInputStream("".getBytes(Charsets.UTF_8)))
+ .attachments(ImmutableList.of())
+ .mailboxId(MAILBOX_ID)
+ .messageId(TestMessageId.of(2))
+ .build();
+ Message testee = messageFactory.fromMetaDataWithContent(testMail);
+ assertThat(testee.getKeywords()).containsAllEntriesOf(keywords);
+ }
+
+ @Test
+ public void fromMetaDataWithContentShouldRemoveUnsupportedKeyword() throws Exception {
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DELETED, Flag.RECENT)
+ .add(FORWARDED)
+ .build();
+ ImmutableMap<String, Boolean> keywords = Keywords.factory()
+ .filterImapNonExposedKeywords()
+ .fromFlags(flags)
+ .asMap();
+
+ MetaDataWithContent testMail = MetaDataWithContent.builder()
+ .uid(MessageUid.of(2))
+ .flags(flags)
+ .size(0)
+ .internalDate(INTERNAL_DATE)
+ .content(new ByteArrayInputStream("".getBytes(Charsets.UTF_8)))
+ .attachments(ImmutableList.of())
+ .mailboxId(MAILBOX_ID)
+ .messageId(TestMessageId.of(2))
+ .build();
+ Message testee = messageFactory.fromMetaDataWithContent(testMail);
+ assertThat(testee.getKeywords()).containsAllEntriesOf(keywords);
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
index 89c5e41..3e38e60 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
@@ -50,7 +50,15 @@ public class MessagePropertiesTest {
.hasValueSatisfying(value ->
assertThat(value).contains(MessageProperty.textBody).doesNotContain(MessageProperty.body));
}
-
+
+ @Test
+ public void toOutputPropertiesShouldReturnIsUnread() {
+ MessageProperties actual = new MessageProperties(Optional.of(ImmutableSet.of("isUnread"))).toOutputProperties();
+ assertThat(actual.getOptionalMessageProperties())
+ .hasValueSatisfying(value ->
+ assertThat(value).contains(MessageProperty.isUnread));
+ }
+
@Test
public void toOutputPropertiesShouldReturnMandatoryPropertiesWhenEmptyRequest() {
MessageProperties actual = new MessageProperties(Optional.of(ImmutableSet.of())).toOutputProperties();
http://git-wip-us.apache.org/repos/asf/james-project/blob/c1387efa/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
index 494ae77..d1c0914 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
@@ -23,6 +23,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.time.Instant;
import java.util.Optional;
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.inmemory.InMemoryId;
import org.apache.james.mailbox.model.TestMessageId;
import org.junit.Test;
@@ -101,8 +104,9 @@ public class MessageTest {
@Test
public void buildShouldWorkWhenMandatoryFieldsArePresent() {
Instant currentDate = Instant.now();
- Message expected = new Message(TestMessageId.of(1), BlobId.of("blobId"), "threadId", ImmutableList.of(InMemoryId.of(456)), Optional.empty(), false, false, false, false, false, ImmutableMap.of("key", "value"), Optional.empty(),
- ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), "subject", currentDate, 123, "preview", Optional.empty(), Optional.empty(), ImmutableList.of(), ImmutableMap.of());
+ Message expected = new Message(TestMessageId.of(1), BlobId.of("blobId"), "threadId", ImmutableList.of(InMemoryId.of(456)), Optional.empty(), false, ImmutableMap.of("key", "value"), Optional.empty(),
+ ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), "subject", currentDate, 123, "preview", Optional.empty(), Optional.empty(),
+ ImmutableList.of(), ImmutableMap.of(), Keywords.DEFAULT_VALUE);
Message tested = Message.builder()
.id(TestMessageId.of(1))
.blobId(BlobId.of("blobId"))
@@ -158,41 +162,42 @@ public class MessageTest {
.date(currentDate)
.build();
ImmutableMap<BlobId, SubMessage> attachedMessages = ImmutableMap.of(BlobId.of("blobId"), simpleMessage);
+ Flags flags = FlagsBuilder.builder()
+ .add(Flags.Flag.DRAFT, Flags.Flag.ANSWERED, Flags.Flag.FLAGGED)
+ .build();
+
+ Keywords keywords = Keywords.factory()
+ .fromFlags(flags);
+
Message expected = new Message(
- TestMessageId.of(1),
- BlobId.of("blobId"),
- "threadId",
- ImmutableList.of(InMemoryId.of(456)),
- Optional.of("inReplyToMessageId"),
- true,
- true,
- true,
- true,
- true,
- ImmutableMap.of("key", "value"),
- Optional.of(from),
- to,
- cc,
- bcc,
- replyTo,
- "subject",
- currentDate,
- 123,
- "preview",
- Optional.of("textBody"),
- Optional.of("htmlBody"),
- attachments,
- attachedMessages);
+ TestMessageId.of(1),
+ BlobId.of("blobId"),
+ "threadId",
+ ImmutableList.of(InMemoryId.of(456)),
+ Optional.of("inReplyToMessageId"),
+ true,
+ ImmutableMap.of("key", "value"),
+ Optional.of(from),
+ to,
+ cc,
+ bcc,
+ replyTo,
+ "subject",
+ currentDate,
+ 123,
+ "preview",
+ Optional.of("textBody"),
+ Optional.of("htmlBody"),
+ attachments,
+ attachedMessages,
+ keywords);
Message tested = Message.builder()
.id(TestMessageId.of(1))
.blobId(BlobId.of("blobId"))
.threadId("threadId")
.mailboxId(InMemoryId.of(456))
.inReplyToMessageId("inReplyToMessageId")
- .isUnread(true)
- .isFlagged(true)
- .isAnswered(true)
- .isDraft(true)
+ .flags(flags)
.headers(ImmutableMap.of("key", "value"))
.from(from)
.to(to)
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[12/13] james-project git commit: JAMES-2046 Add a test for SentDent
ordering for MessageSearchIndexes
Posted by bt...@apache.org.
JAMES-2046 Add a test for SentDent ordering for MessageSearchIndexes
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5af0d27a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5af0d27a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5af0d27a
Branch: refs/heads/master
Commit: 5af0d27aad7f210a8b6245e84915f683937b51b8
Parents: df4d1d8
Author: benwa <bt...@linagora.com>
Authored: Thu Aug 24 14:07:03 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Fri Aug 25 15:31:47 2017 +0700
----------------------------------------------------------------------
.../search/AbstractMessageSearchIndexTest.java | 55 ++++++++++++++++++++
1 file changed, 55 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/5af0d27a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
index 5dbfe9a..fd9d173 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
@@ -21,6 +21,8 @@ package org.apache.james.mailbox.store.search;
import static org.assertj.core.api.Assertions.assertThat;
+import java.io.ByteArrayInputStream;
+import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@@ -29,6 +31,7 @@ import javax.mail.Flags;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.MailboxConstants;
@@ -1143,4 +1146,56 @@ public abstract class AbstractMessageSearchIndexTest {
assertThat(messageSearchIndex.search(otherSession, mailbox, searchQuery)).isEmpty();
}
+
+ @Test
+ public void searchShouldOrderByInternalDateWhenSortOnSentDateAndNoCorrespondingHeader() throws Exception {
+ MailboxPath mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "sentDate");
+ storeMailboxManager.createMailbox(mailboxPath, session);
+
+ MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+ boolean isRecent = false;
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ Date date1 = simpleDateFormat.parse("2017-08-24");
+ Date date2 = simpleDateFormat.parse("2017-08-23");
+ Date date3 = simpleDateFormat.parse("2017-08-25");
+ ComposedMessageId message1 = messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), date1, session, isRecent, new Flags());
+ ComposedMessageId message2 = messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), date2, session, isRecent, new Flags());
+ ComposedMessageId message3 = messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), date3, session, isRecent, new Flags());
+
+ await();
+
+ SearchQuery searchQuery = new SearchQuery();
+ searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.SentDate)));
+
+ assertThat(messageManager.search(searchQuery, session))
+ .containsExactly(message2.getUid(),
+ message1.getUid(),
+ message3.getUid());
+ }
+
+ @Test
+ public void searchShouldOrderBySentDateThenInternalDateWhenSortOnSentDateAndNonHomogeneousCorrespondingHeader() throws Exception {
+ MailboxPath mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "sentDate");
+ storeMailboxManager.createMailbox(mailboxPath, session);
+
+ MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+ boolean isRecent = false;
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ Date date1 = simpleDateFormat.parse("2017-08-24");
+ Date date2 = simpleDateFormat.parse("2017-08-26");
+ Date date3 = simpleDateFormat.parse("2017-08-25");
+ ComposedMessageId message1 = messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), date1, session, isRecent, new Flags());
+ ComposedMessageId message2 = messageManager.appendMessage(new ByteArrayInputStream("Date: Wed, 23 Aug 2017 00:00:00 +0200\r\nSubject: test\r\n\r\ntestmail".getBytes()), date2, session, isRecent, new Flags());
+ ComposedMessageId message3 = messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), date3, session, isRecent, new Flags());
+
+ await();
+
+ SearchQuery searchQuery = new SearchQuery();
+ searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.SentDate)));
+
+ assertThat(messageManager.search(searchQuery, session))
+ .containsExactly(message2.getUid(),
+ message1.getUid(),
+ message3.getUid());
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[04/13] james-project git commit: JAMES-2110 SetMessage with update
should support keywords for flags
Posted by bt...@apache.org.
JAMES-2110 SetMessage with update should support keywords for flags
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/92365a2e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/92365a2e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/92365a2e
Branch: refs/heads/master
Commit: 92365a2ee4813062a37f113a308ea172bc84025e
Parents: 78a4a57
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:43:27 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:27 2017 +0200
----------------------------------------------------------------------
.../methods/SetMessagesUpdateProcessor.java | 7 +
.../james/jmap/model/UpdateMessagePatch.java | 72 ++++----
.../jmap/model/UpdateMessagePatchTest.java | 184 +++++++++++++++++--
3 files changed, 206 insertions(+), 57 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/92365a2e/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java
index c303359..da7dceb 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java
@@ -111,6 +111,13 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor {
}
} catch (MailboxException e) {
handleMessageUpdateException(messageId, builder, e);
+ } catch (IllegalArgumentException e) {
+ ValidationResult invalidPropertyKeywords = ValidationResult.builder()
+ .property(MessageProperties.MessageProperty.keywords.asFieldName())
+ .message(e.getMessage())
+ .build();
+
+ handleInvalidRequest(builder, messageId, ImmutableList.of(invalidPropertyKeywords));
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/92365a2e/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java
index 32e3fe2..6a46bf8 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java
@@ -20,9 +20,9 @@
package org.apache.james.jmap.model;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
-
import javax.mail.Flags;
import org.apache.james.jmap.methods.ValidationResult;
@@ -31,6 +31,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -47,6 +48,7 @@ public class UpdateMessagePatch {
private Optional<Boolean> isFlagged = Optional.empty();
private Optional<Boolean> isUnread = Optional.empty();
private Optional<Boolean> isAnswered = Optional.empty();
+ private Optional<Map<String, Boolean>> keywords = Optional.empty();
private Set<ValidationResult> validationResult = Sets.newHashSet();
public Builder mailboxIds(List<String> mailboxIds) {
@@ -54,6 +56,11 @@ public class UpdateMessagePatch {
return this;
}
+ public Builder keywords(Map<String, Boolean> keywords) {
+ this.keywords = Optional.of(ImmutableMap.copyOf(keywords));
+ return this;
+ }
+
public Builder isFlagged(Boolean isFlagged) {
this.isFlagged = Optional.of(isFlagged);
return this;
@@ -81,28 +88,36 @@ public class UpdateMessagePatch {
.message("mailboxIds property is not supposed to be empty")
.build()));
}
- return new UpdateMessagePatch(mailboxIds, isUnread, isFlagged, isAnswered, ImmutableList.copyOf(validationResult));
+
+ Optional<Keywords> updateKeywords = Keywords.factory()
+ .throwOnImapNonExposedKeywords()
+ .fromMapOrOldKeyword(keywords, getOldKeywords());
+
+ return new UpdateMessagePatch(mailboxIds, updateKeywords, ImmutableList.copyOf(validationResult));
+ }
+
+ private Optional<OldKeyword> getOldKeywords() {
+ if (isAnswered.isPresent() || isFlagged.isPresent() || isUnread.isPresent()) {
+ Optional<Boolean> isDraft = Optional.empty();
+ return Optional.of(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+ }
+ return Optional.empty();
}
+
}
private final Optional<List<String>> mailboxIds;
- private final Optional<Boolean> isUnread;
- private final Optional<Boolean> isFlagged;
- private final Optional<Boolean> isAnswered;
+ private final Optional<Keywords> keywords;
private final ImmutableList<ValidationResult> validationErrors;
@VisibleForTesting
UpdateMessagePatch(Optional<List<String>> mailboxIds,
- Optional<Boolean> isUnread,
- Optional<Boolean> isFlagged,
- Optional<Boolean> isAnswered,
+ Optional<Keywords> keywords,
ImmutableList<ValidationResult> validationResults) {
this.mailboxIds = mailboxIds;
- this.isUnread = isUnread;
- this.isFlagged = isFlagged;
- this.isAnswered = isAnswered;
+ this.keywords = keywords;
this.validationErrors = validationResults;
}
@@ -110,22 +125,12 @@ public class UpdateMessagePatch {
return mailboxIds;
}
- public Optional<Boolean> isUnread() {
- return isUnread;
- }
-
- public Optional<Boolean> isFlagged() {
- return isFlagged;
- }
-
- public Optional<Boolean> isAnswered() {
- return isAnswered;
+ public Optional<Keywords> getKeywords() {
+ return keywords;
}
public boolean isFlagsIdentity() {
- return !isAnswered.isPresent()
- && !isFlagged.isPresent()
- && !isUnread.isPresent();
+ return !keywords.isPresent();
}
public ImmutableList<ValidationResult> getValidationErrors() {
@@ -137,19 +142,12 @@ public class UpdateMessagePatch {
}
public Flags applyToState(Flags currentFlags) {
- Flags newStateFlags = new Flags();
-
- if (isFlagged().orElse(currentFlags.contains(Flags.Flag.FLAGGED))) {
- newStateFlags.add(Flags.Flag.FLAGGED);
- }
- if (isAnswered().orElse(currentFlags.contains(Flags.Flag.ANSWERED))) {
- newStateFlags.add(Flags.Flag.ANSWERED);
- }
- boolean shouldMessageBeMarkSeen = isUnread().map(b -> !b).orElse(currentFlags.contains(Flags.Flag.SEEN));
- if (shouldMessageBeMarkSeen) {
- newStateFlags.add(Flags.Flag.SEEN);
- }
- return newStateFlags;
+ return keywords.map(keyword -> {
+ if (currentFlags.contains(Flags.Flag.DRAFT) != keyword.getKeywords().contains(Keyword.DRAFT)) {
+ throw new IllegalArgumentException("Cannot add or remove draft flag");
+ }
+ return keyword.asFlagsWithRecentAndDeletedFrom(currentFlags);
+ }).orElse(new Flags());
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/92365a2e/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/UpdateMessagePatchTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/UpdateMessagePatchTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/UpdateMessagePatchTest.java
index e97c49c..e227746 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/UpdateMessagePatchTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/UpdateMessagePatchTest.java
@@ -20,42 +20,52 @@
package org.apache.james.jmap.model;
import static org.assertj.core.api.Assertions.assertThat;
-
import java.util.Arrays;
import java.util.List;
-
import javax.mail.Flags;
+import org.apache.james.mailbox.FlagsBuilder;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
public class UpdateMessagePatchTest {
+ private final static String FORWARDED = "forwarded";
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
@Test
public void UnsetUpdatePatchShouldBeValid() {
UpdateMessagePatch emptyPatch = UpdateMessagePatch.builder().build();
assertThat(emptyPatch.isValid()).isTrue();
- assertThat(emptyPatch.isUnread()).isEmpty();
- assertThat(emptyPatch.isFlagged()).isEmpty();
- assertThat(emptyPatch.isAnswered()).isEmpty();
}
@Test
public void builderShouldSetUnreadFalseWhenBuiltWithIsUnreadFalse() {
UpdateMessagePatch testee = UpdateMessagePatch.builder().isUnread(false).build();
- assertThat(testee.isUnread()).isPresent();
- assertThat(testee.isUnread().get()).isFalse();
}
@Test
- public void applyStateShouldSetFlaggedOnlyWhenUnsetPatchAppliedToFlaggedState() {
- UpdateMessagePatch testee = UpdateMessagePatch.builder().build();
- Flags isFlaggedSet = new Flags(Flags.Flag.FLAGGED);
- List<Flags.Flag> updatedFlags = Arrays.asList(testee.applyToState(isFlaggedSet).getSystemFlags());
+ public void applyStateShouldSetFlaggedOnlyWhenIsFlagged() {
+ UpdateMessagePatch testee = UpdateMessagePatch.builder().isFlagged(true).build();
+ List<Flags.Flag> updatedFlags = Arrays.asList(testee.applyToState(new Flags()).getSystemFlags());
assertThat(updatedFlags).containsExactly(Flags.Flag.FLAGGED);
}
@Test
+ public void applyStateShouldRemoveFlaggedWhenEmptyIsFlaggedOnFlaggedMessage() {
+ UpdateMessagePatch testee = UpdateMessagePatch.builder().isAnswered(true).build();
+ Flags isFlagged = new Flags(Flags.Flag.FLAGGED);
+ List<Flags.Flag> updatedFlags = Arrays.asList(testee.applyToState(isFlagged).getSystemFlags());
+ assertThat(updatedFlags).doesNotContain(Flags.Flag.FLAGGED);
+ }
+
+ @Test
public void applyStateShouldReturnUnreadFlagWhenUnreadSetOnSeenMessage() {
UpdateMessagePatch testee = UpdateMessagePatch.builder().isUnread(true).build();
Flags isSeen = new Flags(Flags.Flag.SEEN);
@@ -64,14 +74,6 @@ public class UpdateMessagePatchTest {
}
@Test
- public void applyStateShouldReturnFlaggedWhenEmptyPatchOnFlaggedMessage() {
- UpdateMessagePatch testee = UpdateMessagePatch.builder().build();
- Flags isFlagged = new Flags(Flags.Flag.FLAGGED);
- List<Flags.Flag> updatedFlags = Arrays.asList(testee.applyToState(isFlagged).getSystemFlags());
- assertThat(updatedFlags).containsExactly(Flags.Flag.FLAGGED);
- }
-
- @Test
public void applyStateShouldReturnSeenWhenPatchSetsSeenOnSeenMessage() {
UpdateMessagePatch testee = UpdateMessagePatch.builder().isUnread(false).build();
Flags isSeen = new Flags(Flags.Flag.SEEN);
@@ -80,7 +82,116 @@ public class UpdateMessagePatchTest {
}
@Test
- public void isIdentityShouldReturnTrueWhenNoFlags() {
+ public void applyStateShouldReturnNewFlagsWhenKeywords() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", true,
+ "$Flagged", true);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+ Flags isSeen = new Flags(Flags.Flag.SEEN);
+ assertThat(testee.applyToState(isSeen).getSystemFlags())
+ .containsExactly(Flags.Flag.ANSWERED, Flags.Flag.FLAGGED);
+ }
+
+ @Test
+ public void applyStateShouldReturnRemoveFlagsWhenKeywords() {
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(ImmutableMap.of())
+ .build();
+ Flags isSeen = new Flags(Flags.Flag.SEEN);
+ assertThat(testee.applyToState(isSeen).getSystemFlags()).isEmpty();
+ }
+
+ @Test
+ public void applyStateShouldThrowWhenKeywordsContainDeletedFlag() {
+ expectedException.expect(IllegalArgumentException.class);
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Deleted", true);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+
+ Flags currentFlags = new Flags(Flags.Flag.SEEN);
+
+ testee.applyToState(currentFlags);
+ }
+
+ @Test
+ public void applyStateShouldThrowWhenKeywordsContainRecentFlag() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Recent", true);
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+
+ Flags currentFlags = new Flags(Flags.Flag.SEEN);
+
+ testee.applyToState(currentFlags);
+ }
+
+ @Test
+ public void applyStateShouldReturnFlagsWithoutUserFlagWhenKeywordsContainForwarded() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", Keyword.FLAG_VALUE,
+ FORWARDED, Keyword.FLAG_VALUE);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+ Flags isSeen = new Flags(Flags.Flag.SEEN);
+ assertThat(testee.applyToState(isSeen).getSystemFlags())
+ .doesNotContain(Flags.Flag.USER);
+ }
+
+ @Test
+ public void applyStateShouldReturnFlagsWithUserFlagStringWhenKeywordsContainForwarded() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", Keyword.FLAG_VALUE,
+ FORWARDED, Keyword.FLAG_VALUE);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+ Flags isSeen = new Flags(Flags.Flag.SEEN);
+ assertThat(testee.applyToState(isSeen).getUserFlags())
+ .containsExactly(FORWARDED);
+ }
+
+ @Test
+ public void applyStateShouldReturnFlagsWithDeletedFlagWhenKeywordsDoNotContainDeletedButOriginFlagsHaveDeleted() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", Keyword.FLAG_VALUE);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+ Flags isSeen = new Flags(Flags.Flag.DELETED);
+ assertThat(testee.applyToState(isSeen).getSystemFlags())
+ .containsOnly(Flags.Flag.DELETED, Flags.Flag.ANSWERED);
+ }
+
+ @Test
+ public void applyStateShouldReturnFlagsWithRecentFlagWhenKeywordsDoNotContainRecentButOriginFlagsHaveRecent() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", Keyword.FLAG_VALUE);
+
+ UpdateMessagePatch testee = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+ Flags flags = FlagsBuilder.builder()
+ .add(Flags.Flag.DELETED, Flags.Flag.RECENT)
+ .build();
+ assertThat(testee.applyToState(flags).getSystemFlags())
+ .containsOnly(Flags.Flag.DELETED, Flags.Flag.RECENT, Flags.Flag.ANSWERED);
+ }
+
+ @Test
+ public void isIdentityShouldReturnTrueWhenNoFlagsAndEmptyKeywords() {
UpdateMessagePatch messagePatch = UpdateMessagePatch.builder().build();
assertThat(messagePatch.isFlagsIdentity()).isTrue();
@@ -113,4 +224,37 @@ public class UpdateMessagePatchTest {
assertThat(messagePatch.isFlagsIdentity()).isFalse();
}
+ @Test
+ public void isIdentityShouldReturnFalseWhenKeywords() {
+ ImmutableMap<String, Boolean> keywords = ImmutableMap.of(
+ "$Answered", Keyword.FLAG_VALUE,
+ "$Flagged", Keyword.FLAG_VALUE);
+
+ UpdateMessagePatch messagePatch = UpdateMessagePatch.builder()
+ .keywords(keywords)
+ .build();
+
+ assertThat(messagePatch.isFlagsIdentity()).isFalse();
+ }
+
+ @Test
+ public void isIdentityShouldReturnFalseWhenEmptyKeywords() {
+ UpdateMessagePatch messagePatch = UpdateMessagePatch.builder()
+ .keywords(ImmutableMap.of())
+ .build();
+
+ assertThat(messagePatch.isFlagsIdentity()).isFalse();
+ }
+
+ @Test
+ public void isIdentityShouldThrowWhenBothIsFlagAndKeywords() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ UpdateMessagePatch messagePatch = UpdateMessagePatch.builder()
+ .keywords(ImmutableMap.of())
+ .isAnswered(false)
+ .build();
+
+ messagePatch.isFlagsIdentity();
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[07/13] james-project git commit: JAMES-2110 IT for setMessage with
keywords
Posted by bt...@apache.org.
JAMES-2110 IT for setMessage with keywords
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/37cf8ffc
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/37cf8ffc
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/37cf8ffc
Branch: refs/heads/master
Commit: 37cf8ffc389219c55793dffc5692f898dad331b1
Parents: a6f1c10
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:46:53 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:28 2017 +0200
----------------------------------------------------------------------
.../james/mailbox/store/probe/MailboxProbe.java | 2 +-
.../james/cli/probe/impl/JmxMailboxProbe.java | 9 +-
.../apache/james/modules/MailboxProbeImpl.java | 6 +-
.../modules/protocols/JMAPServerModule.java | 2 +
.../org/apache/james/utils/MessageIdProbe.java | 50 ++
.../integration/SetMessagesMethodTest.java | 587 +++++++++++++++++--
6 files changed, 593 insertions(+), 63 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java
index 6878bb5..b96671e 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java
@@ -41,7 +41,7 @@ public interface MailboxProbe {
void deleteMailbox(String namespace, String user, String name);
void importEmlFileToMailbox(String namespace, String user, String name, String emlpath) throws Exception;
-
+
ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate,
boolean isRecent, Flags flags) throws MailboxException;
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
----------------------------------------------------------------------
diff --git a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
index b3b5cc5..ab9005a 100644
--- a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
+++ b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Date;
-
import javax.mail.Flags;
import javax.management.MalformedObjectNameException;
@@ -37,15 +36,15 @@ import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.probe.MailboxProbe;
public class JmxMailboxProbe implements MailboxProbe, JmxProbe {
-
+
private final static String MAILBOXCOPIER_OBJECT_NAME = "org.apache.james:type=component,name=mailboxcopier";
private final static String MAILBOXMANAGER_OBJECT_NAME = "org.apache.james:type=component,name=mailboxmanagerbean";
private final static String REINDEXER_OBJECT_NAME = "org.apache.james:type=component,name=reindexerbean";
-
+
private MailboxCopierManagementMBean mailboxCopierManagement;
private MailboxManagerManagementMBean mailboxManagerManagement;
private ReIndexerManagementMBean reIndexerManagement;
-
+
public JmxMailboxProbe connect(JmxConnection jmxc) throws IOException {
try {
mailboxCopierManagement = jmxc.retrieveBean(MailboxCopierManagementMBean.class, MAILBOXCOPIER_OBJECT_NAME);
@@ -56,7 +55,7 @@ public class JmxMailboxProbe implements MailboxProbe, JmxProbe {
}
return this;
}
-
+
@Override
public void copyMailbox(String srcBean, String dstBean) throws Exception {
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
----------------------------------------------------------------------
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
index 73982a7..6dbfb05 100644
--- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
@@ -155,11 +155,11 @@ public class MailboxProbeImpl implements GuiceProbe, MailboxProbe {
mailboxManager.endProcessingRequest(mailboxSession);
mailboxSession.close();
}
-
+
@Override
- public ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate, boolean isRecent, Flags flags)
+ public ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate, boolean isRecent, Flags flags)
throws MailboxException {
-
+
MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
MessageManager messageManager = mailboxManager.getMailbox(mailboxPath, mailboxSession);
return messageManager.appendMessage(message, internalDate, mailboxSession, isRecent, flags);
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java
index aa1cc00..c601c44 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java
@@ -26,6 +26,7 @@ import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.james.jmap.JMAPConfiguration;
import org.apache.james.jmap.JMAPModule;
import org.apache.james.jmap.JMAPServer;
+import org.apache.james.utils.MessageIdProbe;
import org.apache.james.jmap.crypto.JamesSignatureHandler;
import org.apache.james.lifecycle.api.Configurable;
import org.apache.james.utils.ConfigurationPerformer;
@@ -49,6 +50,7 @@ public class JMAPServerModule extends AbstractModule {
install(new JMAPModule());
Multibinder.newSetBinder(binder(), ConfigurationPerformer.class).addBinding().to(JMAPModuleConfigurationPerformer.class);
Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(JmapGuiceProbe.class);
+ Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(MessageIdProbe.class);
}
@Singleton
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java
new file mode 100644
index 0000000..f6b97a2
--- /dev/null
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.utils;
+
+import java.util.List;
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.FetchGroupImpl;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.MessageResult;
+
+import com.google.common.collect.ImmutableList;
+
+public class MessageIdProbe implements GuiceProbe {
+ private final MailboxManager mailboxManager;
+ private final MessageIdManager messageIdManager;
+
+ @Inject
+ public MessageIdProbe(MailboxManager mailboxManager, MessageIdManager messageIdManager) {
+ this.mailboxManager = mailboxManager;
+ this.messageIdManager = messageIdManager;
+ }
+
+ public List<MessageResult> getMessages(MessageId messageId, String user) throws MailboxException {
+ MailboxSession mailboxSession = mailboxManager.createSystemSession(user);
+
+ return messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.FULL_CONTENT, mailboxSession);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
index f372583..3fe34bb 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
@@ -26,6 +26,7 @@ import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
@@ -38,7 +39,6 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.ZonedDateTime;
@@ -47,16 +47,15 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
-
import javax.mail.Flags;
+import javax.mail.Flags.Flag;
-import org.apache.commons.io.IOUtils;
-import org.apache.http.client.utils.URIBuilder;
import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.DefaultMailboxes;
import org.apache.james.jmap.HttpJmapAuthentication;
import org.apache.james.jmap.api.access.AccessToken;
import org.apache.james.jmap.model.mailbox.Role;
+import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MailboxListener;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.Attachment;
@@ -64,20 +63,18 @@ import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.MessageResult;
import org.apache.james.mailbox.store.event.EventFactory;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.probe.MailboxProbe;
import org.apache.james.modules.MailboxProbeImpl;
+import org.apache.james.utils.MessageIdProbe;
import org.apache.james.probe.DataProbe;
import org.apache.james.util.ZeroedInputStream;
-import org.apache.james.utils.JmapGuiceProbe;
import org.apache.james.utils.DataProbeImpl;
-import org.hamcrest.Matcher;
-import org.hamcrest.Matchers;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.apache.james.utils.JmapGuiceProbe;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.utils.URIBuilder;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
@@ -91,9 +88,16 @@ import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.ResponseSpecification;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
public abstract class SetMessagesMethodTest {
+ private final static String FORWARDED = "$Forwarded";
private static final int _1MB = 1024*1024;
private static final String NAME = "[0][0]";
private static final String ARGUMENTS = "[0][1]";
@@ -103,27 +107,30 @@ public abstract class SetMessagesMethodTest {
private static final String USERNAME = "username@" + USERS_DOMAIN;
public static final MailboxPath USER_MAILBOX = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
private static final String NOT_UPDATED = ARGUMENTS + ".notUpdated";
+ private static final String NOT_CREATED = ARGUMENTS + ".notCreated";
private ConditionFactory calmlyAwait;
protected abstract GuiceJamesServer createJmapServer();
protected abstract MessageId randomMessageId();
-
+
protected abstract void await();
private AccessToken accessToken;
private GuiceJamesServer jmapServer;
private MailboxProbe mailboxProbe;
private DataProbe dataProbe;
-
+ private MessageIdProbe messageProbe;
+
@Before
public void setup() throws Throwable {
jmapServer = createJmapServer();
jmapServer.start();
mailboxProbe = jmapServer.getProbe(MailboxProbeImpl.class);
dataProbe = jmapServer.getProbe(DataProbeImpl.class);
-
+ messageProbe = jmapServer.getProbe(MessageIdProbe.class);
+
RestAssured.requestSpecification = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
@@ -161,7 +168,7 @@ public abstract class SetMessagesMethodTest {
public void teardown() {
jmapServer.stop();
}
-
+
private String getOutboxId(AccessToken accessToken) {
return getMailboxId(accessToken, Role.OUTBOX);
}
@@ -172,7 +179,7 @@ public abstract class SetMessagesMethodTest {
.map(x -> x.get("id"))
.findFirst().get();
}
-
+
private List<Map<String, String>> getAllMailboxesIds(AccessToken accessToken) {
return with()
.header("Authorization", accessToken.serialize())
@@ -185,7 +192,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullAccountId() throws Exception {
+ public void setMessagesShouldReturnAnErrorNotSupportedWhenRequestContainsNonNullAccountId() throws Exception {
given()
.header("Authorization", accessToken.serialize())
.body("[[\"setMessages\", {\"accountId\": \"1\"}, \"#0\"]]")
@@ -199,7 +206,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullIfInState() throws Exception {
+ public void setMessagesShouldReturnAnErrorNotSupportedWhenRequestContainsNonNullIfInState() throws Exception {
given()
.header("Authorization", accessToken.serialize())
.body("[[\"setMessages\", {\"ifInState\": \"1\"}, \"#0\"]]")
@@ -369,7 +376,7 @@ public abstract class SetMessagesMethodTest {
randomMessageId().serialize(),
message3.getMessageId().serialize()))
.post("/jmap");
-
+
// Then
given()
.header("Authorization", accessToken.serialize())
@@ -396,7 +403,7 @@ public abstract class SetMessagesMethodTest {
await();
String serializedMessageId = message.getMessageId().serialize();
-
+
// When
given()
.header("Authorization", accessToken.serialize())
@@ -409,6 +416,322 @@ public abstract class SetMessagesMethodTest {
.spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId));
}
+ @Test
+ public void setMessagesWithUpdateShouldReturnAnErrorWhenBothIsFlagAndKeywordsArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags());
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"isUnread\" : false, \"keywords\": {\"$Seen\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .body(NOT_UPDATED, hasKey(messageId))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not support keyword and is* at the same time"))
+ .body(ARGUMENTS + ".updated", hasSize(0));
+ }
+
+ @Test
+ public void setMessagesShouldUpdateKeywordsWhenKeywordsArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags());
+ await();
+
+ String serializedMessageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Flagged\": true} } } }, \"#0\"]]", serializedMessageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId));
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]")
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messages"))
+ .body(ARGUMENTS + ".list", hasSize(1))
+ .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true))
+ .body(ARGUMENTS + ".list[0].keywords.$Flagged", equalTo(true));
+ }
+
+ @Test
+ public void setMessagesShouldAddForwardedFlagWhenKeywordsWithForwardedIsPassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags());
+ await();
+
+ String serializedMessageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Forwarded\": true} } } }, \"#0\"]]", serializedMessageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId));
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]")
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messages"))
+ .body(ARGUMENTS + ".list", hasSize(1))
+ .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true))
+ .body(ARGUMENTS + ".list[0].keywords.$Forwarded", equalTo(true));
+ }
+
+ @Test
+ public void setMessagesShouldRemoveForwardedFlagWhenKeywordsWithoutForwardedIsPassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.SEEN)
+ .add(FORWARDED)
+ .build();
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, flags);
+ await();
+
+ String serializedMessageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true} } } }, \"#0\"]]", serializedMessageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId));
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]")
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messages"))
+ .body(ARGUMENTS + ".list", hasSize(1))
+ .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true));
+ }
+
+ @Test
+ public void setMessagesShouldReturnAnErrorWhenKeywordsWithAddingDraftArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED));
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Draft\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .body(NOT_UPDATED, hasKey(messageId))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].properties[0]", equalTo("keywords"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].description", equalTo("keywords: Cannot add or remove draft flag"))
+ .body(ARGUMENTS + ".updated", hasSize(0));
+ }
+
+ @Test
+ public void setMessagesShouldReturnAnErrorWhenKeywordsWithDeletedArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED));
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Deleted\" : true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .body(NOT_UPDATED, hasKey(messageId))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not allow to update 'Deleted' or 'Recent' flag"))
+ .body(ARGUMENTS + ".updated", hasSize(0));
+ }
+
+ @Test
+ public void setMessagesShouldReturnAnErrorWhenKeywordsWithRecentArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED));
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Recent\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .body(NOT_UPDATED, hasKey(messageId))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not allow to update 'Deleted' or 'Recent' flag"))
+ .body(ARGUMENTS + ".updated", hasSize(0));
+ }
+
+ @Test
+ public void setMessagesShouldNotChangeOriginDeletedFlag() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.DELETED));
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Forwarded\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(messageId));
+
+ List<MessageResult> messages = messageProbe.getMessages(message.getMessageId(), USERNAME);
+ Flags expectedFlags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DELETED)
+ .add(FORWARDED)
+ .build();
+
+ assertThat(messages)
+ .hasSize(1)
+ .extracting(MessageResult::getFlags)
+ .containsOnly(expectedFlags);
+ }
+
+ @Test
+ public void setMessagesShouldNotChangeOriginRecentFlag() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+ Flags flags = FlagsBuilder.builder()
+ .add(Flag.DELETED, Flag.RECENT)
+ .build();
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, flags);
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Forwarded\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(messageId));
+
+ List<MessageResult> messages = messageProbe.getMessages(message.getMessageId(), USERNAME);
+
+ Flags expectedFlags = FlagsBuilder.builder()
+ .add(Flag.ANSWERED, Flag.DELETED, Flag.RECENT)
+ .add(FORWARDED)
+ .build();
+
+ assertThat(messages)
+ .hasSize(1)
+ .extracting(MessageResult::getFlags)
+ .containsOnly(expectedFlags);
+ }
+
+ @Test
+ public void setMessagesShouldReturnAnErrorWhenKeywordsWithRemoveDraftArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.DRAFT));
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .body(NOT_UPDATED, hasKey(messageId))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].properties[0]", equalTo("keywords"))
+ .body(NOT_UPDATED + "[\""+messageId+"\"].description", equalTo("keywords: Cannot add or remove draft flag"))
+ .body(ARGUMENTS + ".updated", hasSize(0));
+ }
+
+ @Test
+ public void setMessagesShouldReturnNewKeywordsWhenKeywordsArePassedToRemoveAndAddFlag() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ Flags currentFlags = FlagsBuilder.builder()
+ .add(Flag.DRAFT, Flag.ANSWERED)
+ .build();
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, currentFlags);
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Draft\": true, \"$Flagged\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .spec(getSetMessagesUpdateOKResponseAssertions(messageId));
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]")
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messages"))
+ .body(ARGUMENTS + ".list", hasSize(1))
+ .body(ARGUMENTS + ".list[0].keywords.$Draft", equalTo(true))
+ .body(ARGUMENTS + ".list[0].keywords.$Flagged", equalTo(true));
+ }
+
private ResponseSpecification getSetMessagesUpdateOKResponseAssertions(String messageId) {
ResponseSpecBuilder builder = new ResponseSpecBuilder()
.expectStatusCode(200)
@@ -656,7 +979,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldReturnNotFoundWhenUpdateUnknownMessage() {
+ public void setMessagesShouldReturnNotFoundWhenUpdateUnknownMessage() {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
String nonExistingMessageId = randomMessageId().serialize();
@@ -677,7 +1000,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldReturnCreatedMessageWhenSendingMessage() {
+ public void setMessagesShouldReturnCreatedMessageWhenSendingMessage() {
String messageCreationId = "creationId1337";
String fromAddress = USERNAME;
String requestBody = "[" +
@@ -717,10 +1040,10 @@ public abstract class SetMessagesMethodTest {
hasEntry(equalTo("threadId"), not(isEmptyOrNullString())),
hasEntry(equalTo("size"), not(isEmptyOrNullString()))
)))
- // assert that message flags are all unset
+ // assert that message FLAGS are all unset
.body(ARGUMENTS + ".created", hasEntry(equalTo(messageCreationId), Matchers.allOf(
hasEntry(equalTo("isDraft"), equalTo(false)),
- hasEntry(equalTo("isUnread"), equalTo(false)),
+ hasEntry(equalTo("isUnread"), equalTo(true)),
hasEntry(equalTo("isFlagged"), equalTo(false)),
hasEntry(equalTo("isAnswered"), equalTo(false))
)))
@@ -728,7 +1051,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsNull() {
+ public void setMessagesShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsNull() {
String messageCreationId = "creationId1337";
String fromAddress = USERNAME;
String requestBody = "[" +
@@ -762,7 +1085,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsEmpty() {
+ public void setMessagesShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsEmpty() {
String messageCreationId = "creationId1337";
String fromAddress = USERNAME;
String requestBody = "[" +
@@ -794,9 +1117,9 @@ public abstract class SetMessagesMethodTest {
.body(ARGUMENTS + ".created", hasKey(messageCreationId))
.body(ARGUMENTS + ".created[\""+messageCreationId+"\"].subject", equalTo(""));
}
-
+
@Test
- public void setMessageShouldReturnCreatedMessageWithNonASCIICharactersInSubjectWhenPresent() {
+ public void setMessagesShouldReturnCreatedMessageWithNonASCIICharactersInSubjectWhenPresent() {
String messageCreationId = "creationId1337";
String fromAddress = USERNAME;
String requestBody = "[" +
@@ -830,7 +1153,77 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldSupportArbitraryMessageId() {
+ public void setMessageWithCreatedMessageShouldReturnAnErrorWhenBothIsFlagAndKeywordsPresent() {
+ String messageCreationId = "creationId1337";
+ String fromAddress = USERNAME;
+ String requestBody = "[" +
+ " [" +
+ " \"setMessages\","+
+ " {" +
+ " \"create\": { \"" + messageCreationId + "\" : {" +
+ " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+ " \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+ " \"subject\": \"subject\"," +
+ " \"isDraft\": true," +
+ " \"keywords\": {\"$Draft\": true}," +
+ " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+ " }}" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", equalTo("invalidArguments"))
+ .body(ARGUMENTS + ".description", containsString("Does not support keyword and is* at the same time"));
+ }
+
+ @Test
+ public void setMessageWithCreatedMessageShouldSupportKeywordsForFlags() {
+ String messageCreationId = "creationId1337";
+ String fromAddress = USERNAME;
+ String requestBody = "[" +
+ " [" +
+ " \"setMessages\","+
+ " {" +
+ " \"create\": { \"" + messageCreationId + "\" : {" +
+ " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+ " \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+ " \"subject\": \"subject\"," +
+ " \"keywords\": {\"$Draft\": true, \"$Flagged\": true}," +
+ " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+ " }}" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messagesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(0))
+ .body(ARGUMENTS + ".created", aMapWithSize(1))
+ .body(ARGUMENTS + ".created", hasKey(messageCreationId))
+ .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Draft", equalTo(true))
+ .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Flagged", equalTo(true))
+ ;
+ }
+ @Test
+ public void setMessagesShouldSupportArbitraryMessageId() {
String messageCreationId = "1717fcd1-603e-44a5-b2a6-1234dbcd5723";
String fromAddress = USERNAME;
String requestBody = "[" +
@@ -1325,7 +1718,7 @@ public abstract class SetMessagesMethodTest {
.log().ifValidationFails()
.statusCode(200)
.body(SECOND_NAME, equalTo("messages"))
- .body(SECOND_ARGUMENTS + ".list", hasSize(1))
+ .body(SECOND_ARGUMENTS + ".list", hasSize(1))
.body(SECOND_ARGUMENTS + ".list[0].bcc", empty());
}
@@ -1380,7 +1773,7 @@ public abstract class SetMessagesMethodTest {
.log().ifValidationFails()
.statusCode(200)
.body(SECOND_NAME, equalTo("messages"))
- .body(SECOND_ARGUMENTS + ".list", hasSize(1))
+ .body(SECOND_ARGUMENTS + ".list", hasSize(1))
.body(SECOND_ARGUMENTS + ".list[0].bcc", hasSize(1));
}
@@ -1439,7 +1832,7 @@ public abstract class SetMessagesMethodTest {
.log().ifValidationFails()
.statusCode(200)
.body(SECOND_NAME, equalTo("messages"))
- .body(SECOND_ARGUMENTS + ".list", hasSize(1))
+ .body(SECOND_ARGUMENTS + ".list", hasSize(1))
.body(SECOND_ARGUMENTS + ".list[0].bcc", empty());
}
@@ -1455,7 +1848,7 @@ public abstract class SetMessagesMethodTest {
.body(NAME, equalTo("messageList"))
.body(ARGUMENTS + ".messageIds", hasSize(1));
return true;
-
+
} catch (AssertionError e) {
return false;
}
@@ -1591,7 +1984,7 @@ public abstract class SetMessagesMethodTest {
.body(ARGUMENTS + ".created", aMapWithSize(0));
}
-
+
private boolean isHtmlMessageReceived(AccessToken recipientToken) {
try {
with()
@@ -1609,7 +2002,7 @@ public abstract class SetMessagesMethodTest {
return false;
}
}
-
+
@Test
public void setMessagesShouldSendAReadableTextPlusHtmlMessage() throws Exception {
// Recipient
@@ -2152,7 +2545,7 @@ public abstract class SetMessagesMethodTest {
.body(ARGUMENTS + ".list", hasSize(1))
.body(firstMessage + ".mailboxIds", containsInAnyOrder(trashId, mailboxId));
}
-
+
@Test
public void setMessagesShouldReturnAttachmentsNotFoundWhenBlobIdDoesntExist() throws Exception {
String messageCreationId = "creationId";
@@ -2430,7 +2823,7 @@ public abstract class SetMessagesMethodTest {
String thirdAttachment = message + ".attachments[2]";
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2438,7 +2831,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
given()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessages\", {\"ids\": [\"" + receivedMessageId + "\"]}, \"#0\"]]")
@@ -2479,7 +2872,7 @@ public abstract class SetMessagesMethodTest {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,
50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127};
-
+
Attachment attachment = Attachment.builder()
.bytes(rawBytes)
.type("application/octet-stream")
@@ -2521,7 +2914,7 @@ public abstract class SetMessagesMethodTest {
calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2529,7 +2922,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
String firstMessage = ARGUMENTS + ".list[0]";
String firstAttachment = firstMessage + ".attachments[0]";
given()
@@ -2593,7 +2986,7 @@ public abstract class SetMessagesMethodTest {
calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2601,7 +2994,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
String firstMessage = ARGUMENTS + ".list[0]";
String firstAttachment = firstMessage + ".attachments[0]";
given()
@@ -2634,7 +3027,7 @@ public abstract class SetMessagesMethodTest {
.body(NAME, equalTo("messageList"))
.body(ARGUMENTS + ".messageIds", hasSize(1));
return true;
-
+
} catch (AssertionError e) {
return false;
}
@@ -2685,7 +3078,7 @@ public abstract class SetMessagesMethodTest {
calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2693,7 +3086,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
String firstMessage = ARGUMENTS + ".list[0]";
String firstAttachment = firstMessage + ".attachments[0]";
given()
@@ -2758,7 +3151,7 @@ public abstract class SetMessagesMethodTest {
calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2766,7 +3159,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
String firstMessage = ARGUMENTS + ".list[0]";
String firstAttachment = firstMessage + ".attachments[0]";
given()
@@ -2827,7 +3220,7 @@ public abstract class SetMessagesMethodTest {
calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
String inboxId = getMailboxId(accessToken, Role.INBOX);
- String receivedMessageId =
+ String receivedMessageId =
with()
.header("Authorization", accessToken.serialize())
.body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]")
@@ -2835,7 +3228,7 @@ public abstract class SetMessagesMethodTest {
.then()
.extract()
.path(ARGUMENTS + ".messageIds[0]");
-
+
String firstMessage = ARGUMENTS + ".list[0]";
String firstAttachment = firstMessage + ".attachments[0]";
given()
@@ -2856,7 +3249,7 @@ public abstract class SetMessagesMethodTest {
.body(firstAttachment + ".size", equalTo((int) attachment.getSize()));
}
@Test
- public void setMessageShouldVerifyHeaderOfMessageInInbox() throws Exception {
+ public void setMessagesShouldVerifyHeaderOfMessageInInbox() throws Exception {
String toUsername = "username1@" + USERS_DOMAIN;
String password = "password";
dataProbe.addUser(toUsername, password);
@@ -2893,7 +3286,7 @@ public abstract class SetMessagesMethodTest {
}
@Test
- public void setMessageShouldVerifyHeaderOfMessageInSent() throws Exception {
+ public void setMessagesShouldVerifyHeaderOfMessageInSent() throws Exception {
String toUsername = "username1@" + USERS_DOMAIN;
String password = "password";
dataProbe.addUser(toUsername, password);
@@ -2958,8 +3351,7 @@ public abstract class SetMessagesMethodTest {
.statusCode(200)
.body(ARGUMENTS + ".messageIds", hasSize(1))
.body(SECOND_NAME, equalTo("messages"))
- .body(SECOND_ARGUMENTS + ".list[0]", hasEntry(equalTo("headers"), allHeadersMatcher(expectedHeaders)))
- ;
+ .body(SECOND_ARGUMENTS + ".list[0]", hasEntry(equalTo("headers"), allHeadersMatcher(expectedHeaders)));
return true;
} catch(AssertionError e) {
e.printStackTrace();
@@ -3210,4 +3602,91 @@ public abstract class SetMessagesMethodTest {
.body(secondAttachment + ".cid", nullValue())
.body(secondAttachment + ".isInline", equalTo(true));
}
+
+ @Test
+ public void setMessageWithUpdateShouldBeOKWhenKeywordsWithCustomFlagArePassed() throws MailboxException {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+ ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX,
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags());
+ await();
+
+ String messageId = message.getMessageId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Unknown\": true} } } }, \"#0\"]]", messageId))
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .spec(getSetMessagesUpdateOKResponseAssertions(messageId));
+ }
+
+ @Test
+ public void setMessageWithCreationShouldBeOKWhenKeywordsWithCustomFlagArePassed() {
+ String messageCreationId = "creationId1337";
+ String fromAddress = USERNAME;
+ String requestBody = "[" +
+ " [" +
+ " \"setMessages\","+
+ " {" +
+ " \"create\": { \"" + messageCreationId + "\" : {" +
+ " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+ " \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+ " \"subject\": \"subject\"," +
+ " \"keywords\": {\"$Draft\": true, \"$Unknown\": true}," +
+ " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+ " }}" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("messagesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(0))
+ .body(ARGUMENTS + ".created", aMapWithSize(1));
+ }
+
+ @Test
+ public void setMessageWithCreationShouldThrowWhenKeywordsWithUnsupportedArePassed() {
+ String messageCreationId = "creationId1337";
+ String fromAddress = USERNAME;
+ String requestBody = "[" +
+ " [" +
+ " \"setMessages\","+
+ " {" +
+ " \"create\": { \"" + messageCreationId + "\" : {" +
+ " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+ " \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+ " \"subject\": \"subject\"," +
+ " \"keywords\": {\"$Draft\": true, \"$Deleted\": true}," +
+ " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+ " }}" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", equalTo("invalidArguments"))
+ .body(ARGUMENTS + ".description", containsString("Does not allow to update 'Deleted' or 'Recent' flag"));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[11/13] james-project git commit: JAMES-2046 Implement default use of
internalDate if no SentDate on Lucene
Posted by bt...@apache.org.
JAMES-2046 Implement default use of internalDate if no SentDate on Lucene
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/df4d1d80
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/df4d1d80
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/df4d1d80
Branch: refs/heads/master
Commit: df4d1d80c2a9211ac3aceb4978ab0683d5c42251
Parents: 21ce9e8
Author: benwa <bt...@linagora.com>
Authored: Thu Aug 24 14:06:26 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Fri Aug 25 15:31:46 2017 +0700
----------------------------------------------------------------------
.../james/mailbox/lucene/search/LuceneMessageSearchIndex.java | 3 +++
1 file changed, 3 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/df4d1d80/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
----------------------------------------------------------------------
diff --git a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
index 319ad7d..3227bef 100644
--- a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
+++ b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
@@ -610,6 +610,9 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex {
// This should never happen anyway fallback to the already parsed field
sentDate = ((DateTimeField) f).getDate();
}
+ if (sentDate == null) {
+ sentDate = membership.getInternalDate();
+ }
}
String field = null;
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[10/13] james-project git commit: JAMES-2046 Implement robust
SentDate parsing for Memory search
Posted by bt...@apache.org.
JAMES-2046 Implement robust SentDate parsing for Memory search
Reuse ElasticSearch code.
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/21ce9e82
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/21ce9e82
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/21ce9e82
Branch: refs/heads/master
Commit: 21ce9e82a5effac912841eede6fc54a09d7d0090
Parents: eaedcd2
Author: benwa <bt...@linagora.com>
Authored: Thu Aug 24 13:40:16 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Fri Aug 25 15:31:42 2017 +0700
----------------------------------------------------------------------
.../elasticsearch/json/HeaderCollection.java | 42 +----------
.../json/HeaderCollectionTest.java | 28 --------
.../search/comparator/CombinedComparator.java | 13 ++--
.../search/comparator/SentDateComparator.java | 73 +++++++++++++-------
.../comparator/SentDateComparatorTest.java | 68 ++++++++++++++++++
5 files changed, 124 insertions(+), 100 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/21ce9e82/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
index 2b26a66..85782ad 100644
--- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
+++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
@@ -24,23 +24,18 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.james.mailbox.store.search.SearchUtil;
+import org.apache.james.mailbox.store.search.comparator.SentDateComparator;
import org.apache.james.mime4j.dom.address.Address;
import org.apache.james.mime4j.dom.address.Group;
import org.apache.james.mime4j.dom.address.Mailbox;
import org.apache.james.mime4j.field.address.LenientAddressParser;
import org.apache.james.mime4j.stream.Field;
import org.apache.james.mime4j.util.MimeUtil;
-import org.apache.james.util.date.ImapDateTimeFormatter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMultimap;
@@ -51,14 +46,6 @@ public class HeaderCollection {
public static class Builder {
- // Some sent e-mail have this form : Wed, 3 Jun 2015 09:05:46 +0000 (UTC)
- // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed, 3 Jun 2015 09:05:46 +0000 only
- // This REGEXP is here to match ( in order to remove ) the possible invalid end of a header date
- // Example of matching patterns :
- // (UTC)
- // (CEST)
- private static final Pattern DATE_SANITIZING_PATTERN = Pattern.compile(" *\\(.*\\) *");
-
private final Set<EMailer> toAddressSet;
private final Set<EMailer> fromAddressSet;
private final Set<EMailer> ccAddressSet;
@@ -114,7 +101,7 @@ public class HeaderCollection {
subjectSet.add(headerValue);
break;
case DATE:
- sentDate = toISODate(headerValue);
+ sentDate = SentDateComparator.toISODate(headerValue);
break;
}
}
@@ -152,29 +139,6 @@ public class HeaderCollection {
}
throw new RuntimeException(headerName + " is not a address header name");
}
-
- private Optional<ZonedDateTime> toISODate(String value) {
- try {
- return Optional.of(ZonedDateTime.parse(
- sanitizeDateStringHeaderValue(value),
- ImapDateTimeFormatter.rfc5322()));
- } catch (Exception e) {
- LOGGER.info("Can not parse receive date " + value);
- return Optional.empty();
- }
- }
-
- @VisibleForTesting String sanitizeDateStringHeaderValue(String value) {
- // Some sent e-mail have this form : Wed, 3 Jun 2015 09:05:46 +0000 (UTC)
- // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed, 3 Jun 2015 09:05:46 +0000 only
- // This method is here to convert the first date into something parsable by RFC_1123_DATE_TIME DateTimeFormatter
- Matcher sanitizerMatcher = DATE_SANITIZING_PATTERN.matcher(value);
- if (sanitizerMatcher.find()) {
- return value.substring(0 , sanitizerMatcher.start());
- }
- return value;
- }
-
}
public static final String TO = "to";
@@ -185,8 +149,6 @@ public class HeaderCollection {
public static final String SUBJECT = "subject";
public static final String DATE = "date";
- private static final Logger LOGGER = LoggerFactory.getLogger(HeaderCollection.class);
-
public static Builder builder() {
return new Builder();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/21ce9e82/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
index b1f8fae..93a7b02 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
@@ -267,32 +267,4 @@ public class HeaderCollectionTest {
HeaderCollection.builder().add(null).build();
}
- @Test
- public void sanitizeDateStringHeaderValueShouldRemoveCESTPart() {
- assertThat(HeaderCollection.builder()
- .sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200 (CEST)"))
- .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
- }
-
- @Test
- public void sanitizeDateStringHeaderValueShouldRemoveUTCPart() {
- assertThat(HeaderCollection.builder()
- .sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200 (UTC) "))
- .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
- }
-
- @Test
- public void sanitizeDateStringHeaderValueShouldNotChangeAcceptableString() {
- assertThat(HeaderCollection.builder()
- .sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200"))
- .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
- }
-
- @Test
- public void sanitizeDateStringHeaderValueShouldNotChangeEmptyString() {
- assertThat(HeaderCollection.builder()
- .sanitizeDateStringHeaderValue(""))
- .isEqualTo("");
- }
-
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/21ce9e82/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/CombinedComparator.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/CombinedComparator.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/CombinedComparator.java
index 38bae1d..53d270f 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/CombinedComparator.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/CombinedComparator.java
@@ -95,14 +95,11 @@ public class CombinedComparator implements Comparator<MailboxMessage>{
@Override
public int compare(MailboxMessage o1, MailboxMessage o2) {
- int i = 0;
- for (Comparator<MailboxMessage> comparator : comparators) {
- i = comparator.compare(o1, o2);
- if (i != 0) {
- break;
- }
- }
- return i;
+ return comparators.stream()
+ .map(comparator -> comparator.compare(o1, o2))
+ .filter(result -> result != 0)
+ .findFirst()
+ .orElse(0);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/21ce9e82/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/SentDateComparator.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/SentDateComparator.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/SentDateComparator.java
index 8a1373e..3a897f7 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/SentDateComparator.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/comparator/SentDateComparator.java
@@ -18,44 +18,69 @@
****************************************************************/
package org.apache.james.mailbox.store.search.comparator;
-import java.io.StringReader;
+import java.time.Instant;
+import java.time.ZonedDateTime;
import java.util.Comparator;
-import java.util.Date;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.james.mailbox.store.mail.model.MailboxMessage;
-import org.apache.james.mime4j.dom.datetime.DateTime;
-import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
-import org.apache.james.mime4j.field.datetime.parser.ParseException;
+import org.apache.james.util.date.ImapDateTimeFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
/**
* {@link Comparator} which works like stated in RFC5256 2.2 Sent Date
- *
*/
public class SentDateComparator extends AbstractHeaderComparator {
+
public final static Comparator<MailboxMessage> SENTDATE = new SentDateComparator();
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentDateComparator.class);
+ // Some sent e-mail have this form : Wed, 3 Jun 2015 09:05:46 +0000 (UTC)
+ // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed, 3 Jun 2015 09:05:46 +0000 only
+ // This REGEXP is here to match ( in order to remove ) the possible invalid end of a header date
+ // Example of matching patterns :
+ // (UTC)
+ // (CEST)
+ private static final Pattern DATE_SANITIZING_PATTERN = Pattern.compile(" *\\(.*\\) *");
+
+ public static Optional<ZonedDateTime> toISODate(String value) {
+ try {
+ return Optional.of(ZonedDateTime.parse(
+ sanitizeDateStringHeaderValue(value),
+ ImapDateTimeFormatter.rfc5322()));
+ } catch (Exception e) {
+ LOGGER.info("Can not parse receive date " + value);
+ return Optional.empty();
+ }
+ }
+
+ @VisibleForTesting
+ static String sanitizeDateStringHeaderValue(String value) {
+ // Some sent e-mail have this form : Wed, 3 Jun 2015 09:05:46 +0000 (UTC)
+ // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed, 3 Jun 2015 09:05:46 +0000 only
+ // This method is here to convert the first date into something parsable by RFC_1123_DATE_TIME DateTimeFormatter
+ Matcher sanitizerMatcher = DATE_SANITIZING_PATTERN.matcher(value);
+ if (sanitizerMatcher.find()) {
+ return value.substring(0 , sanitizerMatcher.start());
+ }
+ return value;
+ }
@Override
public int compare(MailboxMessage o1, MailboxMessage o2) {
- Date date1 = getSentDate(o1);
- Date date2 = getSentDate(o2);
- int i = date1.compareTo(date2);
-
- // sent date was the same so use the uid as tie-breaker
- if (i == 0) {
- return UidComparator.UID.compare(o1, o2);
- }
- return 0;
+ Instant date1 = getSentDate(o1);
+ Instant date2 = getSentDate(o2);
+ return date1.compareTo(date2);
}
- private Date getSentDate(MailboxMessage message) {
+ private Instant getSentDate(MailboxMessage message) {
final String value = getHeaderValue("Date", message);
- final StringReader reader = new StringReader(value);
- try {
- DateTime dateTime = new DateTimeParser(reader).parseAll();
- return dateTime.getDate();
- } catch (ParseException e) {
- // if we can not parse the date header we should use the internaldate as fallback
- return message.getInternalDate();
- }
+ return toISODate(value)
+ .map(ZonedDateTime::toInstant)
+ .orElse(message.getInternalDate().toInstant());
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/21ce9e82/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/comparator/SentDateComparatorTest.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/comparator/SentDateComparatorTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/comparator/SentDateComparatorTest.java
new file mode 100644
index 0000000..ddd5a63
--- /dev/null
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/comparator/SentDateComparatorTest.java
@@ -0,0 +1,68 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.mailbox.store.search.comparator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class SentDateComparatorTest {
+ @Test
+ public void sanitizeDateStringHeaderValueShouldRemoveCESTPart() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200 (CEST)"))
+ .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
+ }
+
+ @Test
+ public void sanitizeDateStringHeaderValueShouldRemoveUTCPart() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200 (UTC) "))
+ .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
+ }
+
+ @Test
+ public void sanitizeDateStringHeaderValueShouldNotChangeAcceptableString() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue("Thu, 18 Jun 2015 04:09:35 +0200"))
+ .isEqualTo("Thu, 18 Jun 2015 04:09:35 +0200");
+ }
+
+ @Test
+ public void sanitizeDateStringHeaderValueShouldRemoveBrackets() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue("invalid (removeMe)"))
+ .isEqualTo("invalid");
+ }
+
+ @Test
+ public void sanitizeDateStringHeaderValueShouldKeepUnclosedBrackets() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue("invalid (removeMe"))
+ .isEqualTo("invalid (removeMe");
+ }
+
+ @Test
+ public void sanitizeDateStringHeaderValueShouldNotChangeEmptyString() {
+ assertThat(
+ SentDateComparator.sanitizeDateStringHeaderValue(""))
+ .isEqualTo("");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[13/13] james-project git commit: JAMES-2046 integration test for
GetMessageList date ordering without sent date
Posted by bt...@apache.org.
JAMES-2046 integration test for GetMessageList date ordering without sent date
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/10d76ab6
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/10d76ab6
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/10d76ab6
Branch: refs/heads/master
Commit: 10d76ab6eed59eb5cf5ae3d18772a33437d82053
Parents: 5af0d27
Author: benwa <bt...@linagora.com>
Authored: Thu Aug 24 13:11:12 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Fri Aug 25 15:31:51 2017 +0700
----------------------------------------------------------------------
.../integration/GetMessageListMethodTest.java | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/10d76ab6/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
index 38ef074..df53f63 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
@@ -1582,6 +1582,29 @@ public abstract class GetMessageListMethodTest {
containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize())));
}
+ @Test
+ public void getMessageListShouldSortUsingInternalDateWhenNoDateHeader() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ LocalDate date = LocalDate.now();
+ ComposedMessageId message1 = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), convertToDate(date.plusDays(1)), false, new Flags());
+ ComposedMessageId message2 = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test2\r\n\r\ntestmail".getBytes()), convertToDate(date), false, new Flags());
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"sort\":[\"date asc\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", contains(message2.getMessageId().serialize(), message1.getMessageId().serialize()));
+ }
+
private Date convertToDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[05/13] james-project git commit: JAMES-2110 SetMessage with creation
should support keywords for flags
Posted by bt...@apache.org.
JAMES-2110 SetMessage with creation should support keywords for flags
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/78a4a57d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/78a4a57d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/78a4a57d
Branch: refs/heads/master
Commit: 78a4a57de45038e63011e867e9a46419540cb4e5
Parents: c1387ef
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:42:17 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:27 2017 +0200
----------------------------------------------------------------------
.../methods/SetMessagesCreationProcessor.java | 30 +++-----
.../james/jmap/model/CreationMessage.java | 73 ++++++++++----------
.../SetMessagesCreationProcessorTest.java | 57 ++++++++++++++-
3 files changed, 101 insertions(+), 59 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
index 34bd029..bb9f189 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
@@ -20,14 +20,12 @@
package org.apache.james.jmap.methods;
import static org.apache.james.jmap.methods.Method.JMAP_PREFIX;
-
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
-
import javax.inject.Inject;
import javax.mail.Flags;
import javax.mail.MessagingException;
@@ -40,6 +38,7 @@ import org.apache.james.jmap.model.Attachment;
import org.apache.james.jmap.model.BlobId;
import org.apache.james.jmap.model.CreationMessage;
import org.apache.james.jmap.model.CreationMessageId;
+import org.apache.james.jmap.model.Keywords;
import org.apache.james.jmap.model.Message;
import org.apache.james.jmap.model.MessageFactory;
import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
@@ -70,6 +69,7 @@ import org.apache.james.metrics.api.MetricFactory;
import org.apache.james.metrics.api.TimeMetric;
import org.apache.james.util.OptionalConverter;
import org.apache.mailet.Mail;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -82,6 +82,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
+
public class SetMessagesCreationProcessor implements SetMessagesProcessor {
private static final Logger LOG = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class);
@@ -290,16 +291,20 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent);
Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant());
- Flags flags = getMessageFlags(createdEntry.getValue());
+
+ Flags flags = createdEntry.getValue()
+ .getKeywords()
+ .map(Keywords::asFlags)
+ .orElse(new Flags());
ComposedMessageId message = outbox.appendMessage(content, internalDate, session, flags.contains(Flags.Flag.RECENT), flags);
return MetaDataWithContent.builder()
.uid(message.getUid())
.flags(flags)
- .size(messageContent.length)
.internalDate(internalDate.toInstant())
.sharedContent(content)
+ .size(messageContent.length)
.attachments(messageAttachments)
.mailboxId(outbox.getId())
.messageId(message.getMessageId())
@@ -332,23 +337,6 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
}
}
- private Flags getMessageFlags(CreationMessage message) {
- Flags result = new Flags();
- if (!message.isIsUnread()) {
- result.add(Flags.Flag.SEEN);
- }
- if (message.isIsFlagged()) {
- result.add(Flags.Flag.FLAGGED);
- }
- if (message.isIsAnswered() || message.getInReplyToMessageId().isPresent()) {
- result.add(Flags.Flag.ANSWERED);
- }
- if (message.isIsDraft()) {
- result.add(Flags.Flag.DRAFT);
- }
- return result;
- }
-
private MessageWithId sendMessage(CreationMessageId creationId, MetaDataWithContent message, MailboxSession session) throws MailboxException, MessagingException {
Message jmapMessage = messageFactory.fromMetaDataWithContent(message);
sendMessage(message, jmapMessage, session);
http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
index 791b383..f67185d 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
@@ -27,7 +27,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
@@ -59,10 +58,10 @@ public class CreationMessage {
public static class Builder {
private ImmutableList<String> mailboxIds;
private String inReplyToMessageId;
- private boolean isUnread;
- private boolean isFlagged;
- private boolean isAnswered;
- private boolean isDraft;
+ private Optional<Boolean> isUnread = Optional.empty();
+ private Optional<Boolean> isFlagged = Optional.empty();
+ private Optional<Boolean> isAnswered = Optional.empty();
+ private Optional<Boolean> isDraft = Optional.empty();
private final ImmutableMap.Builder<String, String> headers;
private Optional<DraftEmailer> from = Optional.empty();
private final ImmutableList.Builder<DraftEmailer> to;
@@ -75,6 +74,7 @@ public class CreationMessage {
private String htmlBody;
private final ImmutableList.Builder<Attachment> attachments;
private final ImmutableMap.Builder<BlobId, SubMessage> attachedMessages;
+ private Optional<Map<String, Boolean>> keywords = Optional.empty();
private Builder() {
to = ImmutableList.builder();
@@ -101,22 +101,22 @@ public class CreationMessage {
return this;
}
- public Builder isUnread(boolean isUnread) {
+ public Builder isUnread(Optional<Boolean> isUnread) {
this.isUnread = isUnread;
return this;
}
- public Builder isFlagged(boolean isFlagged) {
+ public Builder isFlagged(Optional<Boolean> isFlagged) {
this.isFlagged = isFlagged;
return this;
}
- public Builder isAnswered(boolean isAnswered) {
+ public Builder isAnswered(Optional<Boolean> isAnswered) {
this.isAnswered = isAnswered;
return this;
}
- public Builder isDraft(boolean isDraft) {
+ public Builder isDraft(Optional<Boolean> isDraft) {
this.isDraft = isDraft;
return this;
}
@@ -186,6 +186,11 @@ public class CreationMessage {
return this;
}
+ public Builder keywords(Map<String, Boolean> keywords) {
+ this.keywords = Optional.of(ImmutableMap.copyOf(keywords));
+ return this;
+ }
+
private static boolean areAttachedMessagesKeysInAttachments(ImmutableList<Attachment> attachments, ImmutableMap<BlobId, SubMessage> attachedMessages) {
return attachedMessages.isEmpty() || attachedMessages.keySet().stream()
.anyMatch(inAttachments(attachments));
@@ -206,21 +211,29 @@ public class CreationMessage {
ImmutableMap<BlobId, SubMessage> attachedMessages = this.attachedMessages.build();
Preconditions.checkState(areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachments'");
+ Optional<Keywords> creationKeywords = Keywords.factory()
+ .throwOnImapNonExposedKeywords()
+ .fromMapOrOldKeyword(keywords, getOldKeywords());
+
if (date == null) {
date = ZonedDateTime.now();
}
- return new CreationMessage(mailboxIds, Optional.ofNullable(inReplyToMessageId), isUnread, isFlagged, isAnswered, isDraft, headers.build(), from,
- to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody), attachments, attachedMessages);
+ return new CreationMessage(mailboxIds, Optional.ofNullable(inReplyToMessageId), headers.build(), from,
+ to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody),
+ attachments, attachedMessages, creationKeywords);
+ }
+
+ private Optional<OldKeyword> getOldKeywords() {
+ if (isAnswered.isPresent() || isFlagged.isPresent() || isUnread.isPresent() || isDraft.isPresent()) {
+ return Optional.of(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft));
+ }
+ return Optional.empty();
}
}
private final ImmutableList<String> mailboxIds;
private final Optional<String> inReplyToMessageId;
- private final boolean isUnread;
- private final boolean isFlagged;
- private final boolean isAnswered;
- private final boolean isDraft;
private final ImmutableMap<String, String> headers;
private final Optional<DraftEmailer> from;
private final ImmutableList<DraftEmailer> to;
@@ -233,17 +246,14 @@ public class CreationMessage {
private final Optional<String> htmlBody;
private final ImmutableList<Attachment> attachments;
private final ImmutableMap<BlobId, SubMessage> attachedMessages;
+ private final Optional<Keywords> keywords;
@VisibleForTesting
- CreationMessage(ImmutableList<String> mailboxIds, Optional<String> inReplyToMessageId, boolean isUnread, boolean isFlagged, boolean isAnswered, boolean isDraft, ImmutableMap<String, String> headers, Optional<DraftEmailer> from,
+ CreationMessage(ImmutableList<String> mailboxIds, Optional<String> inReplyToMessageId, ImmutableMap<String, String> headers, Optional<DraftEmailer> from,
ImmutableList<DraftEmailer> to, ImmutableList<DraftEmailer> cc, ImmutableList<DraftEmailer> bcc, ImmutableList<DraftEmailer> replyTo, String subject, ZonedDateTime date, Optional<String> textBody, Optional<String> htmlBody, ImmutableList<Attachment> attachments,
- ImmutableMap<BlobId, SubMessage> attachedMessages) {
+ ImmutableMap<BlobId, SubMessage> attachedMessages, Optional<Keywords> keywords) {
this.mailboxIds = mailboxIds;
this.inReplyToMessageId = inReplyToMessageId;
- this.isUnread = isUnread;
- this.isFlagged = isFlagged;
- this.isAnswered = isAnswered;
- this.isDraft = isDraft;
this.headers = headers;
this.from = from;
this.to = to;
@@ -256,6 +266,7 @@ public class CreationMessage {
this.htmlBody = htmlBody;
this.attachments = attachments;
this.attachedMessages = attachedMessages;
+ this.keywords = keywords;
}
public ImmutableList<String> getMailboxIds() {
@@ -266,22 +277,6 @@ public class CreationMessage {
return inReplyToMessageId;
}
- public boolean isIsUnread() {
- return isUnread;
- }
-
- public boolean isIsFlagged() {
- return isFlagged;
- }
-
- public boolean isIsAnswered() {
- return isAnswered;
- }
-
- public boolean isIsDraft() {
- return isDraft;
- }
-
public ImmutableMap<String, String> getHeaders() {
return headers;
}
@@ -334,6 +329,10 @@ public class CreationMessage {
return validate().isEmpty();
}
+ public Optional<Keywords> getKeywords() {
+ return keywords;
+ }
+
public List<ValidationResult> validate() {
ImmutableList.Builder<ValidationResult> errors = ImmutableList.builder();
assertValidFromProvided(errors);
http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
index cc10186..c2c36e6 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
@@ -42,6 +42,7 @@ import org.apache.james.jmap.model.BlobId;
import org.apache.james.jmap.model.CreationMessage;
import org.apache.james.jmap.model.CreationMessage.DraftEmailer;
import org.apache.james.jmap.model.CreationMessageId;
+import org.apache.james.jmap.model.Keyword;
import org.apache.james.jmap.model.MessageFactory;
import org.apache.james.jmap.model.MessagePreviewGenerator;
import org.apache.james.jmap.model.MessageProperties.MessageProperty;
@@ -72,9 +73,12 @@ import org.apache.james.util.mime.MessageContentExtractor;
import org.apache.mailet.Mail;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public class SetMessagesCreationProcessorTest {
@@ -115,7 +119,8 @@ public class SetMessagesCreationProcessorTest {
private Optional<MessageManager> optionalOutbox;
private Optional<MessageManager> optionalDrafts;
-
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
@Before
public void setUp() throws MailboxException {
HtmlTextExtractor htmlTextExtractor = mock(HtmlTextExtractor.class);
@@ -157,6 +162,56 @@ public class SetMessagesCreationProcessorTest {
}
@Test
+ public void processShouldThrowWhenBothIsFlagAndKeywords() {
+ expectedException.expect(IllegalArgumentException.class);
+ SetMessagesRequest createMessageWithError = SetMessagesRequest.builder()
+ .create(
+ creationMessageId,
+ creationMessageBuilder
+ .mailboxId(OUTBOX_ID.serialize())
+ .isAnswered(Optional.of(true))
+ .keywords(ImmutableMap.of("$Answered", true))
+ .build())
+ .build();
+
+ sut.process(createMessageWithError, session);
+ }
+
+ @Test
+ public void processShouldCreateWhenKeywords() {
+ SetMessagesRequest createMessageWithKeywords = SetMessagesRequest.builder()
+ .create(
+ creationMessageId,
+ creationMessageBuilder
+ .mailboxId(OUTBOX_ID.serialize())
+ .keywords(ImmutableMap.of("$Answered", true))
+ .build())
+ .build();
+
+ SetMessagesResponse result = sut.process(createMessageWithKeywords, session);
+
+ assertThat(result.getCreated()).isNotEmpty();
+ assertThat(result.getNotCreated()).isEmpty();
+ }
+
+ @Test
+ public void processShouldCreateWhenIsFlag() {
+ SetMessagesRequest createMessageWithKeywords = SetMessagesRequest.builder()
+ .create(
+ creationMessageId,
+ creationMessageBuilder
+ .mailboxId(OUTBOX_ID.serialize())
+ .isAnswered(Optional.of(true))
+ .build())
+ .build();
+
+ SetMessagesResponse result = sut.process(createMessageWithKeywords, session);
+
+ assertThat(result.getCreated()).isNotEmpty();
+ assertThat(result.getNotCreated()).isEmpty();
+ }
+
+ @Test
public void processShouldReturnNonEmptyCreatedWhenRequestHasNonEmptyCreate() throws MailboxException {
// Given
sut = new SetMessagesCreationProcessor(mimeMessageConverter, mockedMailSpool, mockedMailFactory, messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory());
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[03/13] james-project git commit: JAMES-2110 Parser message should
not care json message deserilization such as we had CreationMessage and
UpdateMessagePath
Posted by bt...@apache.org.
JAMES-2110 Parser message should not care json message deserilization such as we had CreationMessage and UpdateMessagePath
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/53fdcbdd
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/53fdcbdd
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/53fdcbdd
Branch: refs/heads/master
Commit: 53fdcbdd86d35e55d075fa0ad79ebd69b11ec735
Parents: 20beee7
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:35:50 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:27 2017 +0200
----------------------------------------------------------------------
.../james/jmap/json/ParsingWritingObjects.java | 18 ++++++++++--------
.../jmap/json/ParsingWritingObjectsTest.java | 10 ----------
.../jmap/src/test/resources/json/message.json | 5 +++--
3 files changed, 13 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/53fdcbdd/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
index 144e144..f84b91e 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
@@ -22,10 +22,14 @@ package org.apache.james.jmap.json;
import java.time.Instant;
import java.util.Optional;
+import javax.mail.Flags;
+
import org.apache.james.jmap.model.BlobId;
import org.apache.james.jmap.model.Emailer;
+import org.apache.james.jmap.model.Keyword;
import org.apache.james.jmap.model.Message;
import org.apache.james.jmap.model.SubMessage;
+import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.inmemory.InMemoryId;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageId;
@@ -33,6 +37,7 @@ import org.apache.james.mailbox.model.TestMessageId;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
public interface ParsingWritingObjects {
@@ -42,10 +47,10 @@ public interface ParsingWritingObjects {
String THREAD_ID = "myThreadId";
ImmutableList<MailboxId> MAILBOX_IDS = ImmutableList.of(InMemoryId.of(1), InMemoryId.of(2));
String IN_REPLY_TO_MESSAGE_ID = "myInReplyToMessageId";
- boolean IS_UNREAD = true;
- boolean IS_FLAGGED = true;
- boolean IS_ANSWERED = true;
- boolean IS_DRAFT = true;
+ Flags FLAGS = FlagsBuilder.builder()
+ .add(Flags.Flag.FLAGGED, Flags.Flag.ANSWERED, Flags.Flag.DRAFT, Flags.Flag.SEEN)
+ .build();
+ ImmutableSet<Keyword> KEYWORDS = ImmutableSet.of(Keyword.DRAFT, Keyword.FLAGGED, Keyword.ANSWERED, Keyword.SEEN);
boolean HAS_ATTACHMENT = true;
ImmutableMap<String, String> HEADERS = ImmutableMap.of("h1", "h1Value", "h2", "h2Value");
Emailer FROM = Emailer.builder().name("myName").email("myEmail@james.org").build();
@@ -71,10 +76,7 @@ public interface ParsingWritingObjects {
.threadId(Common.THREAD_ID)
.mailboxIds(Common.MAILBOX_IDS)
.inReplyToMessageId(Common.IN_REPLY_TO_MESSAGE_ID)
- .isUnread(Common.IS_UNREAD)
- .isFlagged(Common.IS_FLAGGED)
- .isAnswered(Common.IS_ANSWERED)
- .isDraft(Common.IS_DRAFT)
+ .flags(Common.FLAGS)
.headers(Common.HEADERS)
.from(Common.FROM)
.to(Common.TO)
http://git-wip-us.apache.org/repos/asf/james-project/blob/53fdcbdd/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjectsTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjectsTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjectsTest.java
index 0cd3a1f..bed119d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjectsTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjectsTest.java
@@ -73,16 +73,6 @@ public class ParsingWritingObjectsTest {
}
@Test
- public void parsingJsonShouldWorkOnMessage() throws Exception {
- Message expected = MESSAGE;
-
- Message message = testee.forParsing()
- .readValue(IOUtils.toString(ClassLoader.getSystemResource("json/message.json"), StandardCharsets.UTF_8), Message.class);
-
- assertThat(message).isEqualToComparingFieldByField(expected);
- }
-
- @Test
public void writingJsonShouldWorkOnMessage() throws Exception {
String expected = IOUtils.toString(ClassLoader.getSystemResource("json/message.json"), StandardCharsets.UTF_8);
http://git-wip-us.apache.org/repos/asf/james-project/blob/53fdcbdd/server/protocols/jmap/src/test/resources/json/message.json
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/resources/json/message.json b/server/protocols/jmap/src/test/resources/json/message.json
index e036384..ba0c82f 100644
--- a/server/protocols/jmap/src/test/resources/json/message.json
+++ b/server/protocols/jmap/src/test/resources/json/message.json
@@ -4,7 +4,7 @@
"threadId": "myThreadId",
"mailboxIds": ["1", "2"],
"inReplyToMessageId": "myInReplyToMessageId",
- "isUnread": true,
+ "isUnread": false,
"isFlagged": true,
"isAnswered": true,
"isDraft": true,
@@ -22,5 +22,6 @@
"textBody": "myTextBody",
"htmlBody": "<h1>myHtmlBody</h1>",
"attachments": [ ],
- "attachedMessages": { }
+ "attachedMessages": { },
+ "keywords": {"$Draft" : true, "$Flagged" : true, "$Answered" : true, "$Seen" : true}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[09/13] james-project git commit: JAMES-2110 IT for getMessageList
which supports filter by hasKeyword and notKeyword
Posted by bt...@apache.org.
JAMES-2110 IT for getMessageList which supports filter by hasKeyword and notKeyword
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/eaedcd21
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/eaedcd21
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/eaedcd21
Branch: refs/heads/master
Commit: eaedcd2182fbc39578f81eaf4a1ab07983ec6e06
Parents: 41e3d15
Author: quynhn <qn...@linagora.com>
Authored: Tue Aug 15 16:49:13 2017 +0700
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Aug 24 15:47:28 2017 +0200
----------------------------------------------------------------------
.../integration/GetMessageListMethodTest.java | 286 +++++++++++++++++--
1 file changed, 268 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/eaedcd21/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
index 06bf60b..38ef074 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
@@ -29,15 +29,12 @@ import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not;
-
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
-
import javax.mail.Flags;
-import org.apache.http.client.utils.URIBuilder;
import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.HttpJmapAuthentication;
import org.apache.james.jmap.api.access.AccessToken;
@@ -53,16 +50,19 @@ import org.apache.james.probe.DataProbe;
import org.apache.james.util.date.ImapDateTimeFormatter;
import org.apache.james.utils.DataProbeImpl;
import org.apache.james.utils.JmapGuiceProbe;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import org.apache.http.client.utils.URIBuilder;
import com.google.common.base.Charsets;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
public abstract class GetMessageListMethodTest {
+ private final static String FORWARDED = "$Forwarded";
private static final String NAME = "[0][0]";
private static final String ARGUMENTS = "[0][1]";
private static final ZoneId ZONE_ID = ZoneId.of("Europe/Paris");
@@ -140,7 +140,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListSetFlaggedFilterShouldWork() throws Exception {
+ public void getMessageListSetFlaggedFilterShouldResultFlaggedMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -164,7 +164,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListUnsetFlaggedFilterShouldWork() throws Exception {
+ public void getMessageListUnsetFlaggedFilterShouldReturnNotFlaggedMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -188,7 +188,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListReadFilterShouldWork() throws Exception {
+ public void getMessageListReadFilterShouldReturnOnlyReadMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotRead = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -212,7 +212,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListUnreadFilterShouldWork() throws Exception {
+ public void getMessageListUnreadFilterShouldReturnOnlyUnreadMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotRead = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -236,7 +236,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListSetDraftFilterShouldWork() throws Exception {
+ public void getMessageListSetDraftFilterShouldReturnOnlyDraftMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotDraft = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -260,7 +260,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListUnsetDraftFilterShouldWork() throws Exception {
+ public void getMessageListUnsetDraftFilterShouldReturnOnlyNonDraftMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotDraft = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -284,7 +284,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListSetAnsweredFilterShouldWork() throws Exception {
+ public void getMessageListSetAnsweredFilterShouldReturnOnlyAnsweredMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotAnswered = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -308,7 +308,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListUnsetAnsweredFilterShouldWork() throws Exception {
+ public void getMessageListUnsetAnsweredFilterShouldReturnOnlyNotAnsweredMessages() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotAnswered = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -332,7 +332,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListANDOperatorShouldWork() throws Exception {
+ public void getMessageListANDOperatorShouldReturnMessagesWhichMatchAllConditions() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotSeenNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -362,7 +362,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListOROperatorShouldWork() throws Exception {
+ public void getMessageListOROperatorShouldReturnMessagesWhichMatchOneOfAllConditions() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotSeenNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -392,7 +392,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListNOTOperatorShouldWork() throws Exception {
+ public void getMessageListNOTOperatorShouldReturnMessagesWhichNotMatchAnyCondition() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotSeenNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -422,7 +422,7 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListNestedOperatorsShouldWork() throws Exception {
+ public void getMessageListNestedOperatorsShouldReturnMessagesWhichMatchConditions() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
ComposedMessageId messageNotSeenNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
@@ -1332,6 +1332,256 @@ public abstract class GetMessageListMethodTest {
;
}
+ @Test
+ public void getMessageListHasKeywordFilterShouldReturnMessagesWithKeywords() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.FLAGGED));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"hasKeyword\":\"$Flagged\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize()),
+ not(containsInAnyOrder(messageNotFlagged.getMessageId().serialize()))));
+ }
+
+ @Test
+ public void getMessageListHasKeywordFilterShouldReturnMessagesWithUserKeywords() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ Flags flags = FlagsBuilder.builder()
+ .add(Flags.Flag.FLAGGED)
+ .add(FORWARDED)
+ .build();
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, flags);
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"operator\":\"AND\",\"conditions\":[{\"hasKeyword\":\"$Flagged\"},{\"hasKeyword\":\"$Forwarded\"}]}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize()),
+ not(containsInAnyOrder(messageNotFlagged.getMessageId().serialize()))));
+ }
+
+ @Test
+ public void getMessageListNotKeywordFilterShouldReturnMessagesWithoutKeywords() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.FLAGGED));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"notKeyword\":\"$Flagged\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageNotFlagged.getMessageId().serialize()),
+ not(containsInAnyOrder(messageFlagged.getMessageId().serialize()))));
+ }
+
+ @Test
+ public void getMessageListNotKeywordFilterShouldReturnMessagesWithoutUserKeywords() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ Flags flags = FlagsBuilder.builder()
+ .add(Flags.Flag.FLAGGED)
+ .add(FORWARDED)
+ .build();
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, flags);
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"operator\":\"AND\",\"conditions\":[{\"notKeyword\":\"$Flagged\"},{\"notKeyword\":\"$Forwarded\"}]}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageNotFlagged.getMessageId().serialize()),
+ not(containsInAnyOrder(messageFlagged.getMessageId().serialize()))));
+ }
+
+ @Test
+ public void getMessageListNotKeywordFilterShouldReturnMessagesWithoutKeywordsWhenMultipleNotKeywordAndFilterOperator() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ Flags flags = FlagsBuilder.builder()
+ .add(FORWARDED)
+ .add(Flags.Flag.DRAFT)
+ .build();
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.FLAGGED));
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, flags);
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"operator\":\"OR\",\"conditions\":[{\"notKeyword\":\"$Flagged\"},{\"notKeyword\":\"$Forwarded\"}]}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageNotFlagged.getMessageId().serialize(), messageFlagged.getMessageId().serialize())));
+ }
+
+ @Test
+ public void getMessageListHasKeywordAndNotKeywordFilterShouldReturnMessagesWithAndWithoutKeywords() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.FLAGGED));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"hasKeyword\":\"$Flagged\", \"notKeyword\":\"$Draft\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize()),
+ not(containsInAnyOrder(messageNotFlagged.getMessageId().serialize()))));
+ }
+
+ @Test
+ public void getMessageListHasKeywordShouldIgnoreDeleted() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.DELETED));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"hasKeyword\":\"$Deleted\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize())));
+ }
+
+ @Test
+ public void getMessageListHasKeywordShouldIgnoreRecent() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.RECENT));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"hasKeyword\":\"$Recent\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize())));
+ }
+
+ @Test
+ public void getMessageListNotKeywordShouldIgnoreDeleted() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.DELETED));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"notKeyword\":\"$Deleted\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize())));
+ }
+
+ @Test
+ public void getMessageListNotKeywordShouldIgnoreRecent() throws Exception {
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+ ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
+ ComposedMessageId messageFlagged = mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+ new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.RECENT));
+
+ await();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMessageList\", {\"filter\":{\"notKeyword\":\"$Recent\"}}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("messageList"))
+ .body(ARGUMENTS + ".messageIds", allOf(
+ containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize())));
+ }
+
private Date convertToDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org