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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5ccc59b3e3 JAMES-4052 Add optional user property to OpenSearch index 
(#2363)
5ccc59b3e3 is described below

commit 5ccc59b3e3582bf0d8fc86494f187e8f85ea52f8
Author: Benoit TELLIER <btell...@linagora.com>
AuthorDate: Fri Jul 26 10:20:43 2024 +0200

    JAMES-4052 Add optional user property to OpenSearch index (#2363)
---
 .../pages/distributed/configure/opensearch.adoc    |  4 +++
 .../mailbox/opensearch/MailboxMappingFactory.java  |  3 ++
 .../opensearch/OpenSearchMailboxConfiguration.java | 35 +++++++++++++++---
 .../OpenSearchListeningMessageSearchIndex.java     |  4 +--
 .../mailbox/opensearch/json/IndexableMessage.java  | 23 ++++++++++--
 .../opensearch/json/JsonMessageConstants.java      |  1 +
 .../opensearch/json/MessageToOpenSearchJson.java   | 41 +++++++++++++++++++++-
 src/site/xdoc/server/config-opensearch.xml         |  2 ++
 upgrade-instructions.md                            | 26 +++++++++++++-
 9 files changed, 128 insertions(+), 11 deletions(-)

diff --git a/docs/modules/servers/pages/distributed/configure/opensearch.adoc 
b/docs/modules/servers/pages/distributed/configure/opensearch.adoc
index 0b70fd3b43..fd061b4407 100644
--- a/docs/modules/servers/pages/distributed/configure/opensearch.adoc
+++ b/docs/modules/servers/pages/distributed/configure/opensearch.adoc
@@ -99,6 +99,10 @@ Default to false.
 
 | opensearch.indexBody
 | Indicates if you wish to index body or not (default: true). This can be used 
to decrease the performance cost associated with indexing.
+
+| opensearch.indexUser
+| Indicates if you wish to index user or not (default: false). This can be 
used to have per user reports in OpenSearch Dashboards.
+
 |===
 
 === Quota search
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/MailboxMappingFactory.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/MailboxMappingFactory.java
index 9d97e9fd9e..84a61f9b9b 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/MailboxMappingFactory.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/MailboxMappingFactory.java
@@ -251,6 +251,9 @@ public class MailboxMappingFactory {
             .put(JsonMessageConstants.MIME_MESSAGE_ID, new Property.Builder()
                 .keyword(new KeywordProperty.Builder().build())
                 .build())
+            .put(JsonMessageConstants.USER, new Property.Builder()
+                .keyword(new KeywordProperty.Builder().build())
+                .build())
             .put(JsonMessageConstants.TEXT_BODY, new Property.Builder()
                 .text(new TextProperty.Builder().analyzer(STANDARD).build())
                 .build())
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java
index 6fa68d0286..16958f6411 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java
@@ -26,6 +26,7 @@ import org.apache.commons.configuration2.Configuration;
 import org.apache.james.backends.opensearch.IndexName;
 import org.apache.james.backends.opensearch.ReadAliasName;
 import org.apache.james.backends.opensearch.WriteAliasName;
+import 
org.apache.james.mailbox.opensearch.json.MessageToOpenSearchJson.IndexUser;
 
 public class OpenSearchMailboxConfiguration {
 
@@ -37,6 +38,7 @@ public class OpenSearchMailboxConfiguration {
         private Optional<IndexHeaders> indexHeaders;
         private Optional<Boolean> optimiseMoves;
         private Optional<IndexBody> indexBody;
+        private Optional<IndexUser> indexUser;
 
         Builder() {
             indexMailboxName = Optional.empty();
@@ -46,6 +48,7 @@ public class OpenSearchMailboxConfiguration {
             indexHeaders = Optional.empty();
             optimiseMoves = Optional.empty();
             indexBody = Optional.empty();
+            indexUser = Optional.empty();
         }
 
         public Builder indexMailboxName(Optional<IndexName> indexMailboxName) {
@@ -83,6 +86,11 @@ public class OpenSearchMailboxConfiguration {
             return this;
         }
 
+        public Builder indexUser(IndexUser indexUser) {
+            this.indexUser = Optional.ofNullable(indexUser);
+            return this;
+        }
+
         public OpenSearchMailboxConfiguration build() {
             return new OpenSearchMailboxConfiguration(
                 
indexMailboxName.orElse(MailboxOpenSearchConstants.DEFAULT_MAILBOX_INDEX),
@@ -91,7 +99,8 @@ public class OpenSearchMailboxConfiguration {
                 indexAttachment.orElse(IndexAttachments.YES),
                 indexHeaders.orElse(IndexHeaders.YES),
                 optimiseMoves.orElse(DEFAULT_OPTIMIZE_MOVES),
-                indexBody.orElse(IndexBody.YES));
+                indexBody.orElse(IndexBody.YES),
+                indexUser.orElse(IndexUser.NO));
         }
     }
 
@@ -109,10 +118,12 @@ public class OpenSearchMailboxConfiguration {
     private static final String OPENSEARCH_INDEX_HEADERS = 
"opensearch.indexHeaders";
     private static final String OPENSEARCH_MESSAGE_INDEX_OPTIMIZE_MOVE = 
"opensearch.message.index.optimize.move";
     private static final String OPENSEARCH_INDEX_BODY = "opensearch.indexBody";
+    private static final String OPENSEARCH_INDEX_USER = "opensearch.indexUser";
     private static final boolean DEFAULT_INDEX_ATTACHMENTS = true;
     private static final boolean DEFAULT_INDEX_HEADERS = true;
     public static final boolean DEFAULT_OPTIMIZE_MOVES = false;
     public static final boolean DEFAULT_INDEX_BODY = true;
+    public static final boolean DEFAULT_INDEX_USER = false;
     public static final OpenSearchMailboxConfiguration DEFAULT_CONFIGURATION = 
builder().build();
 
     public static OpenSearchMailboxConfiguration fromProperties(Configuration 
configuration) {
@@ -124,6 +135,7 @@ public class OpenSearchMailboxConfiguration {
             .indexHeaders(provideIndexHeaders(configuration))
             
.optimiseMoves(configuration.getBoolean(OPENSEARCH_MESSAGE_INDEX_OPTIMIZE_MOVE, 
null))
             .indexBody(provideIndexBody(configuration))
+            .indexUser(provideIndexUser(configuration))
             .build();
     }
 
@@ -169,6 +181,13 @@ public class OpenSearchMailboxConfiguration {
         return IndexBody.NO;
     }
 
+    private static IndexUser provideIndexUser(Configuration configuration) {
+        if (configuration.getBoolean(OPENSEARCH_INDEX_USER, 
DEFAULT_INDEX_USER)) {
+            return IndexUser.YES;
+        }
+        return IndexUser.NO;
+    }
+
     private final IndexName indexMailboxName;
     private final ReadAliasName readAliasMailboxName;
     private final WriteAliasName writeAliasMailboxName;
@@ -176,10 +195,12 @@ public class OpenSearchMailboxConfiguration {
     private final IndexHeaders indexHeaders;
     private final boolean optimiseMoves;
     private final IndexBody indexBody;
+    private final IndexUser indexUser;
 
     private OpenSearchMailboxConfiguration(IndexName indexMailboxName, 
ReadAliasName readAliasMailboxName,
                                            WriteAliasName 
writeAliasMailboxName, IndexAttachments indexAttachment,
-                                           IndexHeaders indexHeaders, boolean 
optimiseMoves, IndexBody indexBody) {
+                                           IndexHeaders indexHeaders, boolean 
optimiseMoves, IndexBody indexBody,
+                                           IndexUser indexUser) {
         this.indexMailboxName = indexMailboxName;
         this.readAliasMailboxName = readAliasMailboxName;
         this.writeAliasMailboxName = writeAliasMailboxName;
@@ -187,6 +208,7 @@ public class OpenSearchMailboxConfiguration {
         this.indexHeaders = indexHeaders;
         this.optimiseMoves = optimiseMoves;
         this.indexBody = indexBody;
+        this.indexUser = indexUser;
     }
 
     public IndexName getIndexMailboxName() {
@@ -217,6 +239,10 @@ public class OpenSearchMailboxConfiguration {
         return indexBody;
     }
 
+    public IndexUser getIndexUser() {
+        return indexUser;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof OpenSearchMailboxConfiguration) {
@@ -228,7 +254,8 @@ public class OpenSearchMailboxConfiguration {
                 && Objects.equals(this.readAliasMailboxName, 
that.readAliasMailboxName)
                 && Objects.equals(this.optimiseMoves, that.optimiseMoves)
                 && Objects.equals(this.writeAliasMailboxName, 
that.writeAliasMailboxName)
-                && Objects.equals(this.indexBody, that.indexBody);
+                && Objects.equals(this.indexBody, that.indexBody)
+                && Objects.equals(this.indexUser, that.indexUser);
         }
         return false;
     }
@@ -236,6 +263,6 @@ public class OpenSearchMailboxConfiguration {
     @Override
     public final int hashCode() {
         return Objects.hash(indexMailboxName, readAliasMailboxName, 
writeAliasMailboxName, indexAttachment, indexHeaders,
-            writeAliasMailboxName, optimiseMoves, indexBody);
+            writeAliasMailboxName, optimiseMoves, indexBody, indexUser);
     }
 }
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
index 1ec770400b..1dbc729adc 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
@@ -357,7 +357,7 @@ public class OpenSearchListeningMessageSearchIndex extends 
ListeningMessageSearc
     }
 
     private Mono<String> generateIndexedJson(Mailbox mailbox, MailboxMessage 
message, MailboxSession session) {
-        return messageToOpenSearchJson.convertToJson(message)
+        return messageToOpenSearchJson.convertToJson(message, session)
             .onErrorResume(e -> {
                 LOGGER.warn("Indexing mailbox {}-{} of user {} on message {} 
without attachments ",
                     mailbox.getName(),
@@ -365,7 +365,7 @@ public class OpenSearchListeningMessageSearchIndex extends 
ListeningMessageSearc
                     session.getUser().asString(),
                     message.getUid(),
                     e);
-                return 
messageToOpenSearchJson.convertToJsonWithoutAttachment(message);
+                return 
messageToOpenSearchJson.convertToJsonWithoutAttachment(message, session);
             });
     }
 
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java
index f068801a5e..23569aed72 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java
@@ -38,6 +38,7 @@ import 
org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.search.SearchUtil;
 import org.apache.james.mime4j.MimeException;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -64,6 +65,7 @@ public class IndexableMessage {
         private MailboxMessage message;
         private TextExtractor textExtractor;
         private ZoneId zoneId;
+        private String user = null;
 
         private Builder() {
         }
@@ -112,6 +114,13 @@ public class IndexableMessage {
             return this;
         }
 
+        public Builder user(MessageToOpenSearchJson.IndexUser indexUser, 
String user) {
+            if (indexUser == MessageToOpenSearchJson.IndexUser.YES) {
+                this.user = user;
+            }
+            return this;
+        }
+
         private Mono<IndexableMessage> instantiateIndexedMessage() throws 
IOException, MimeException {
             String messageId = 
SearchUtil.getSerializedMessageIdIfSupportedByUnderlyingStorageOrNull(message);
             String threadId = 
SearchUtil.getSerializedThreadIdIfSupportedByUnderlyingStorageOrNull(message);
@@ -175,6 +184,7 @@ public class IndexableMessage {
                         mediaType,
                         messageId,
                         threadId,
+                        user,
                         modSeq,
                         sentDate,
                         saveDate,
@@ -183,8 +193,7 @@ public class IndexableMessage {
                         subType,
                         to,
                         uid,
-                        userFlags,
-                        mimeMessageID);
+                        userFlags, mimeMessageID);
                 });
         }
 
@@ -236,6 +245,7 @@ public class IndexableMessage {
     private final String mediaType;
     private final String messageId;
     private final String threadId;
+    private final String user;
     private final long modSeq;
     private final String sentDate;
     private final Optional<String> saveDate;
@@ -264,7 +274,7 @@ public class IndexableMessage {
                              boolean isUnRead,
                              String mailboxId,
                              String mediaType, String messageId,
-                             String threadId,
+                             String threadId, String user,
                              ModSeq modSeq,
                              String sentDate,
                              Optional<String> saveDate, long size,
@@ -293,6 +303,7 @@ public class IndexableMessage {
         this.mediaType = mediaType;
         this.messageId = messageId;
         this.threadId = threadId;
+        this.user = user;
         this.modSeq = modSeq.asLong();
         this.sentDate = sentDate;
         this.saveDate = saveDate;
@@ -445,6 +456,12 @@ public class IndexableMessage {
         return isUnRead;
     }
 
+    @JsonProperty(JsonMessageConstants.USER)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public String getUser() {
+        return user;
+    }
+
     @JsonProperty(JsonMessageConstants.MIME_MESSAGE_ID)
     public Optional<String> getMimeMessageID() {
         return mimeMessageID;
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/JsonMessageConstants.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/JsonMessageConstants.java
index 798f4e6455..65cef55261 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/JsonMessageConstants.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/JsonMessageConstants.java
@@ -47,6 +47,7 @@ public interface JsonMessageConstants {
     String ATTACHMENTS = "attachments";
     String TEXT = "text";
     String MIME_MESSAGE_ID = "mimeMessageID";
+    String USER = "user";
 
     String MODSEQ = "modSeq";
     String USER_FLAGS = "userFlags";
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java
index fa47d7ac87..4253dfa9dd 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java
@@ -28,6 +28,7 @@ import java.util.Date;
 import jakarta.inject.Inject;
 import jakarta.mail.Flags;
 
+import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
 import org.apache.james.mailbox.extractor.TextExtractor;
@@ -49,6 +50,9 @@ import com.google.common.base.Preconditions;
 import reactor.core.publisher.Mono;
 
 public class MessageToOpenSearchJson {
+    public enum IndexUser {
+        YES, NO
+    }
 
     private final ObjectMapper mapper;
     private final TextExtractor textExtractor;
@@ -56,12 +60,17 @@ public class MessageToOpenSearchJson {
     private final IndexAttachments indexAttachments;
     private final IndexHeaders indexHeaders;
     private final IndexBody indexBody;
+    private final IndexUser indexUser;
 
     public MessageToOpenSearchJson(TextExtractor textExtractor, ZoneId zoneId, 
IndexAttachments indexAttachments, IndexHeaders indexHeaders) {
         this(textExtractor, zoneId, indexAttachments, indexHeaders, 
IndexBody.YES);
     }
 
     public MessageToOpenSearchJson(TextExtractor textExtractor, ZoneId zoneId, 
IndexAttachments indexAttachments, IndexHeaders indexHeaders, IndexBody 
indexBody) {
+        this(textExtractor, zoneId, indexAttachments, indexHeaders, indexBody, 
IndexUser.YES);
+    }
+
+    public MessageToOpenSearchJson(TextExtractor textExtractor, ZoneId zoneId, 
IndexAttachments indexAttachments, IndexHeaders indexHeaders, IndexBody 
indexBody, IndexUser indexUser) {
         this.textExtractor = textExtractor;
         this.zoneId = zoneId;
         this.indexAttachments = indexAttachments;
@@ -70,11 +79,41 @@ public class MessageToOpenSearchJson {
         this.mapper.registerModule(new GuavaModule());
         this.mapper.registerModule(new Jdk8Module());
         this.indexBody = indexBody;
+        this.indexUser = indexUser;
     }
 
     @Inject
     public MessageToOpenSearchJson(TextExtractor textExtractor, 
OpenSearchMailboxConfiguration configuration) {
-        this(textExtractor, ZoneId.systemDefault(), 
configuration.getIndexAttachment(), configuration.getIndexHeaders(), 
configuration.getIndexBody());
+        this(textExtractor, ZoneId.systemDefault(), 
configuration.getIndexAttachment(), configuration.getIndexHeaders(),
+            configuration.getIndexBody(), configuration.getIndexUser());
+    }
+
+    public Mono<String> convertToJson(MailboxMessage message, MailboxSession 
session) {
+        Preconditions.checkNotNull(message);
+
+        return IndexableMessage.builder()
+            .message(message)
+            .extractor(textExtractor)
+            .zoneId(zoneId)
+            .indexAttachments(indexAttachments)
+            .indexHeaders(indexHeaders)
+            .indexBody(indexBody)
+            .user(indexUser, session.getUser().asString())
+            .build()
+            .map(Throwing.function(mapper::writeValueAsString));
+    }
+
+    public Mono<String> convertToJsonWithoutAttachment(MailboxMessage message, 
MailboxSession session) {
+        return IndexableMessage.builder()
+            .message(message)
+            .extractor(textExtractor)
+            .zoneId(zoneId)
+            .indexAttachments(IndexAttachments.NO)
+            .indexHeaders(indexHeaders)
+            .user(indexUser, session.getUser().asString())
+            .indexBody(indexBody)
+            .build()
+            .map(Throwing.function(mapper::writeValueAsString));
     }
 
     public Mono<String> convertToJson(MailboxMessage message) {
diff --git a/src/site/xdoc/server/config-opensearch.xml 
b/src/site/xdoc/server/config-opensearch.xml
index 6dda770d3c..e6c5f95f3c 100644
--- a/src/site/xdoc/server/config-opensearch.xml
+++ b/src/site/xdoc/server/config-opensearch.xml
@@ -124,6 +124,8 @@
               Default to false.</dd>
           <dt><strong>opensearch.indexBody</strong></dt>
           <dd>Indicates if you wish to index body or not (default: true). This 
can be used to decrease the performance cost associated with indexing.</dd>
+          <dt><strong>opensearch.indexUser</strong></dt>
+          <dd>Indicates if you wish to index user or not (default: false). 
This can be used to have per user reports in OpenSearch Dashboards.</dd>
           <dt><strong>opensearch.index.quota.ratio.name</strong></dt>
           <dd>Specify the OpenSearch alias name used for quotas</dd>
           <dt><strong>opensearch.alias.read.quota.ratio.name</strong></dt>
diff --git a/upgrade-instructions.md b/upgrade-instructions.md
index d1a308f9a2..2d9bfe8b52 100644
--- a/upgrade-instructions.md
+++ b/upgrade-instructions.md
@@ -32,8 +32,9 @@ Change list:
  - [Make all queues on RabbitMQ quorum queue when 
`quorum.queues.enable=true`](#make-all-queues-on-rabbitmq-quorum-queue-when-quorumqueuesenabletrue)
  - [Migrate RabbitMQ classic queues to version 
2](#migrate-rabbitmq-classic-queues-to-version-2)
  - [JAMES-3946 White list removals](#james-3946-white-list-removals)
+ - [JAMES-4052 Details in quota index](#james-4052-details-in-quota-index)
 
-### JAMES-4052 Details in quota index
+### JAMES-4052 Details in quota index and mailbox user
 
 Date: 23/07/2024
 
@@ -80,6 +81,29 @@ 
opensearch.alias.read.quota.ratio.name=james-quota-ratio-read-v2
 opensearch.alias.write.quota.ratio.name=james-quota-ratio-write-v2
 ```
 
+We also added an optional field to the mailbox mapping for `user`. It allows 
doing per user analysis in OpenSearch dashboards.
+
+In order to activate that field, include in `opensearch.properties`: 
+
+```
+opensearch.indexUser=true
+```
+
+And create the field:
+
+```
+curl -X PUT \
+  http://ip:port/mailbox_v2/_mapping \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "properties": {
+        "user": {
+            "type": "keyword"
+        }
+    }
+}'
+```
+
 ### JAMES-3946 White list removals
 
 Date: 14/06/2024


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

Reply via email to