You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/11/22 11:47:05 UTC

(james-project) branch postgresql updated (666c7e1b22 -> b32d220f37)

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

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


    from 666c7e1b22 JAMES-2586 Implement PostgresExecutor Factory and Mailbox Aggregate Module
     new 69ebb847cb JAMES-2586 Implement MailboxACL support for PostgresMailboxMapper
     new b32d220f37 JAMES-2586 Create hstore extension if needed upon James startup

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 backends-common/postgres/pom.xml                   |  5 ++
 .../backends/postgres/PostgresTableManager.java    |  8 +++
 .../james/backends/postgres/PostgresExtension.java | 46 ++++++++++++----
 .../postgres/mail/PostgresMailboxMapper.java       | 23 +++++---
 .../postgres/mail/PostgresMailboxModule.java       |  4 ++
 .../postgres/mail/dao/PostgresMailboxDAO.java      | 64 +++++++++++++++++++++-
 ...Test.java => PostgresMailboxMapperACLTest.java} | 11 +---
 .../james/modules/data/PostgresCommonModule.java   |  3 +-
 8 files changed, 135 insertions(+), 29 deletions(-)
 copy mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/{PostgresMailboxMapperTest.java => PostgresMailboxMapperACLTest.java} (83%)


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


(james-project) 02/02: JAMES-2586 Create hstore extension if needed upon James startup

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b32d220f372e9abce53fd540e5cc61648a7fb8b2
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Tue Nov 21 16:35:57 2023 +0700

    JAMES-2586 Create hstore extension if needed upon James startup
---
 .../org/apache/james/backends/postgres/PostgresTableManager.java  | 8 ++++++++
 .../java/org/apache/james/modules/data/PostgresCommonModule.java  | 3 ++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTableManager.java b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTableManager.java
index c7b2ff1bf7..a46e6b36a2 100644
--- a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTableManager.java
+++ b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTableManager.java
@@ -58,6 +58,14 @@ public class PostgresTableManager implements Startable {
         this.rowLevelSecurityEnabled = rowLevelSecurityEnabled;
     }
 
+    public Mono<Void> initializePostgresExtension() {
+        return postgresExecutor.connection()
+            .flatMapMany(connection -> connection.createStatement("CREATE EXTENSION IF NOT EXISTS hstore")
+                .execute())
+            .flatMap(Result::getRowsUpdated)
+            .then();
+    }
+
     public Mono<Void> initializeTables() {
         return postgresExecutor.dslContext()
             .flatMap(dsl -> Flux.fromIterable(module.tables())
diff --git a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresCommonModule.java b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresCommonModule.java
index 5492c65893..d33097bc4f 100644
--- a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresCommonModule.java
+++ b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresCommonModule.java
@@ -105,7 +105,8 @@ public class PostgresCommonModule extends AbstractModule {
     InitializationOperation provisionPostgresTablesAndIndexes(PostgresTableManager postgresTableManager) {
         return InitilizationOperationBuilder
             .forClass(PostgresTableManager.class)
-            .init(() -> postgresTableManager.initializeTables()
+            .init(() -> postgresTableManager.initializePostgresExtension()
+                .then(postgresTableManager.initializeTables())
                 .then(postgresTableManager.initializeTableIndexes())
                 .block());
     }


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


(james-project) 01/02: JAMES-2586 Implement MailboxACL support for PostgresMailboxMapper

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 69ebb847cbfe0e556e0023f3bddba36cc392f996
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Tue Nov 21 15:28:02 2023 +0700

    JAMES-2586 Implement MailboxACL support for PostgresMailboxMapper
    
    Co-authored-by: Tung TRAN <vt...@linagora.com>
---
 backends-common/postgres/pom.xml                   |  5 ++
 .../james/backends/postgres/PostgresExtension.java | 46 ++++++++++++----
 .../postgres/mail/PostgresMailboxMapper.java       | 23 +++++---
 .../postgres/mail/PostgresMailboxModule.java       |  4 ++
 .../postgres/mail/dao/PostgresMailboxDAO.java      | 64 +++++++++++++++++++++-
 .../mail/PostgresMailboxMapperACLTest.java         | 36 ++++++++++++
 6 files changed, 159 insertions(+), 19 deletions(-)

diff --git a/backends-common/postgres/pom.xml b/backends-common/postgres/pom.xml
index 2e87eb59ea..e204034ecc 100644
--- a/backends-common/postgres/pom.xml
+++ b/backends-common/postgres/pom.xml
@@ -70,6 +70,11 @@
             <artifactId>jooq</artifactId>
             <version>${jooq.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.jooq</groupId>
+            <artifactId>jooq-postgres-extensions</artifactId>
+            <version>${jooq.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.postgresql</groupId>
             <artifactId>r2dbc-postgresql</artifactId>
diff --git a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
index d6f65b6f7a..4f9ba51094 100644
--- a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
+++ b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
@@ -22,7 +22,10 @@ package org.apache.james.backends.postgres;
 import static org.apache.james.backends.postgres.PostgresFixture.Database.DEFAULT_DATABASE;
 import static org.apache.james.backends.postgres.PostgresFixture.Database.ROW_LEVEL_SECURITY_DATABASE;
 
+import java.io.IOException;
 import java.net.URISyntaxException;
+import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.http.client.utils.URIBuilder;
 import org.apache.james.GuiceModuleTestExtension;
@@ -79,16 +82,23 @@ public class PostgresExtension implements GuiceModuleTestExtension {
             PG_CONTAINER.start();
         }
         querySettingRowLevelSecurityIfNeed();
+        querySettingExtension();
         initPostgresSession();
     }
 
     private void querySettingRowLevelSecurityIfNeed() {
-        Throwing.runnable(() -> {
-            PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "create user " + ROW_LEVEL_SECURITY_DATABASE.dbUser() + " WITH PASSWORD '" + ROW_LEVEL_SECURITY_DATABASE.dbPassword() + "';");
-            PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "create database " + ROW_LEVEL_SECURITY_DATABASE.dbName() + ";");
-            PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "grant all privileges on database " + ROW_LEVEL_SECURITY_DATABASE.dbName() + " to " + ROW_LEVEL_SECURITY_DATABASE.dbUser() + ";");
-            PG_CONTAINER.execInContainer("psql", "-U", ROW_LEVEL_SECURITY_DATABASE.dbUser(), "-d", ROW_LEVEL_SECURITY_DATABASE.dbName(), "-c", "create schema if not exists " + ROW_LEVEL_SECURITY_DATABASE.schema() + ";");
-        }).sneakyThrow().run();
+        if (rlsEnabled) {
+            Throwing.runnable(() -> {
+                PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "create user " + ROW_LEVEL_SECURITY_DATABASE.dbUser() + " WITH PASSWORD '" + ROW_LEVEL_SECURITY_DATABASE.dbPassword() + "';");
+                PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "create database " + ROW_LEVEL_SECURITY_DATABASE.dbName() + ";");
+                PG_CONTAINER.execInContainer("psql", "-U", DEFAULT_DATABASE.dbUser(), "-c", "grant all privileges on database " + ROW_LEVEL_SECURITY_DATABASE.dbName() + " to " + ROW_LEVEL_SECURITY_DATABASE.dbUser() + ";");
+                PG_CONTAINER.execInContainer("psql", "-U", ROW_LEVEL_SECURITY_DATABASE.dbUser(), "-d", ROW_LEVEL_SECURITY_DATABASE.dbName(), "-c", "create schema if not exists " + ROW_LEVEL_SECURITY_DATABASE.schema() + ";");
+            }).sneakyThrow().run();
+        }
+    }
+
+    private void querySettingExtension() throws IOException, InterruptedException {
+        PG_CONTAINER.execInContainer("psql", "-U", selectedDatabase.dbUser(), selectedDatabase.dbName(), "-c", String.format("CREATE EXTENSION IF NOT EXISTS hstore SCHEMA %s;", selectedDatabase.schema()));
     }
 
     private void initPostgresSession() throws URISyntaxException {
@@ -177,10 +187,26 @@ public class PostgresExtension implements GuiceModuleTestExtension {
     }
 
     private void resetSchema() {
-        getConnection()
-            .flatMapMany(connection -> Mono.from(connection.createStatement("DROP SCHEMA " + selectedDatabase.schema() + " CASCADE").execute())
-                .then(Mono.from(connection.createStatement("CREATE SCHEMA " + selectedDatabase.schema() + " AUTHORIZATION " + selectedDatabase.dbUser()).execute()))
-                .flatMap(result -> Mono.from(result.getRowsUpdated())))
+        dropTables(listAllTables());
+    }
+
+    private void dropTables(List<String> tables) {
+        String tablesToDelete = tables.stream()
+            .map(tableName -> "\"" + tableName + "\"")
+            .collect(Collectors.joining(", "));
+
+        postgresExecutor.connection()
+            .flatMapMany(connection -> connection.createStatement(String.format("DROP table if exists %s cascade;", tablesToDelete))
+                .execute())
+            .then()
+            .block();
+    }
+
+    private List<String> listAllTables() {
+        return postgresExecutor.connection()
+            .flatMapMany(connection -> connection.createStatement(String.format("SELECT tablename FROM pg_tables WHERE schemaname = '%s'", selectedDatabase.schema()))
+                .execute())
+            .flatMap(result -> result.map((row, rowMetadata) -> row.get(0, String.class)))
             .collectList()
             .block();
     }
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapper.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapper.java
index 787ca65ced..f44a4fb0c5 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapper.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapper.java
@@ -20,7 +20,6 @@
 package org.apache.james.mailbox.postgres.mail;
 
 import javax.inject.Inject;
-import javax.naming.OperationNotSupportedException;
 
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.acl.ACLDiff;
@@ -33,6 +32,8 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxDAO;
 import org.apache.james.mailbox.store.mail.MailboxMapper;
 
+import com.github.fge.lambdas.Throwing;
+
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
@@ -86,19 +87,27 @@ public class PostgresMailboxMapper implements MailboxMapper {
 
     @Override
     public Flux<Mailbox> findNonPersonalMailboxes(Username userName, MailboxACL.Right right) {
-        // TODO
-        return Flux.error(new OperationNotSupportedException());
+        return postgresMailboxDAO.findNonPersonalMailboxes(userName, right);
     }
 
     @Override
     public Mono<ACLDiff> updateACL(Mailbox mailbox, MailboxACL.ACLCommand mailboxACLCommand) {
-        // TODO
-        return Mono.error(new OperationNotSupportedException());
+        MailboxACL oldACL = mailbox.getACL();
+        MailboxACL newACL = Throwing.supplier(() -> oldACL.apply(mailboxACLCommand)).get();
+        return postgresMailboxDAO.upsertACL(mailbox.getMailboxId(), newACL)
+            .map(updatedACL -> {
+                mailbox.setACL(updatedACL);
+                return ACLDiff.computeDiff(oldACL, updatedACL);
+            });
     }
 
     @Override
     public Mono<ACLDiff> setACL(Mailbox mailbox, MailboxACL mailboxACL) {
-        // TODO
-        return Mono.error(new OperationNotSupportedException());
+        MailboxACL oldACL = mailbox.getACL();
+        return postgresMailboxDAO.upsertACL(mailbox.getMailboxId(), mailboxACL)
+            .map(updatedACL -> {
+                mailbox.setACL(updatedACL);
+                return ACLDiff.computeDiff(oldACL, updatedACL);
+            });
     }
 }
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxModule.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxModule.java
index 9c9b424c48..af8b1dca04 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxModule.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxModule.java
@@ -30,6 +30,8 @@ import org.jooq.Record;
 import org.jooq.Table;
 import org.jooq.impl.DSL;
 import org.jooq.impl.SQLDataType;
+import org.jooq.postgres.extensions.bindings.HstoreBinding;
+import org.jooq.postgres.extensions.types.Hstore;
 
 public interface PostgresMailboxModule {
     interface PostgresMailboxTable {
@@ -42,6 +44,7 @@ public interface PostgresMailboxModule {
         Field<String> MAILBOX_NAMESPACE = DSL.field("mailbox_namespace", SQLDataType.VARCHAR(255).notNull());
         Field<Long> MAILBOX_LAST_UID = DSL.field("mailbox_last_uid", BIGINT);
         Field<Long> MAILBOX_HIGHEST_MODSEQ = DSL.field("mailbox_highest_modseq", BIGINT);
+        Field<Hstore> MAILBOX_ACL = DSL.field("mailbox_acl", org.jooq.impl.DefaultDataType.getDefaultDataType("hstore").asConvertedDataType(new HstoreBinding()));
 
         PostgresTable TABLE = PostgresTable.name(TABLE_NAME.getName())
             .createTableStep(((dsl, tableName) -> dsl.createTableIfNotExists(tableName)
@@ -52,6 +55,7 @@ public interface PostgresMailboxModule {
                 .column(MAILBOX_NAMESPACE)
                 .column(MAILBOX_LAST_UID)
                 .column(MAILBOX_HIGHEST_MODSEQ)
+                .column(MAILBOX_ACL)
                 .constraint(DSL.primaryKey(MAILBOX_ID))
                 .constraint(DSL.unique(MAILBOX_NAME, USER_NAME, MAILBOX_NAMESPACE))))
             .supportsRowLevelSecurity();
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
index c63909a43a..ab0aec9532 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.postgres.mail.dao;
 
 import static org.apache.james.mailbox.postgres.PostgresMailboxIdFaker.getMailboxId;
+import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_ACL;
 import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_HIGHEST_MODSEQ;
 import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_ID;
 import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_LAST_UID;
@@ -31,13 +32,21 @@ import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.Postg
 import static org.jooq.impl.DSL.coalesce;
 import static org.jooq.impl.DSL.count;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 import org.apache.james.backends.postgres.utils.PostgresExecutor;
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
 import org.apache.james.mailbox.exception.MailboxExistsException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.UidValidity;
@@ -46,15 +55,46 @@ import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.store.MailboxExpressionBackwardCompatibility;
 import org.jooq.Record;
 import org.jooq.exception.DataAccessException;
+import org.jooq.impl.DSL;
+import org.jooq.postgres.extensions.types.Hstore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class PostgresMailboxDAO {
+    private static final Logger LOGGER = LoggerFactory.getLogger(PostgresMailboxDAO.class);
     private static final char SQL_WILDCARD_CHAR = '%';
     private static final String DUPLICATE_VIOLATION_MESSAGE = "duplicate key value violates unique constraint";
+    private static final Function<MailboxACL, Hstore> MAILBOX_ACL_TO_HSTORE_FUNCTION = acl -> Hstore.hstore(acl.getEntries()
+        .entrySet()
+        .stream()
+        .collect(Collectors.toMap(
+            entry -> entry.getKey().serialize(),
+            entry -> entry.getValue().serialize())));
+
+    private static final Function<Hstore, MailboxACL> HSTORE_TO_MAILBOX_ACL_FUNCTION = hstore -> new MailboxACL(hstore.data()
+        .entrySet()
+        .stream()
+        .map(entry -> deserializeMailboxACLEntry(entry.getKey(), entry.getValue()))
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
+
+    private static Optional<Map.Entry<MailboxACL.EntryKey, MailboxACL.Rfc4314Rights>> deserializeMailboxACLEntry(String key, String value) {
+        try {
+            MailboxACL.EntryKey entryKey = MailboxACL.EntryKey.deserialize(key);
+            MailboxACL.Rfc4314Rights rfc4314Rights = MailboxACL.Rfc4314Rights.deserialize(value);
+            return Optional.of(Map.entry(entryKey, rfc4314Rights));
+        } catch (UnsupportedRightException e) {
+            LOGGER.error("Error while deserializing mailbox ACL", e);
+            return Optional.empty();
+        }
+    }
 
     private final PostgresExecutor postgresExecutor;
 
@@ -66,7 +106,7 @@ public class PostgresMailboxDAO {
         final PostgresMailboxId mailboxId = PostgresMailboxId.generate();
 
         return postgresExecutor.executeVoid(dslContext -> Mono.from(dslContext.insertInto(TABLE_NAME, MAILBOX_ID, MAILBOX_NAME, USER_NAME, MAILBOX_NAMESPACE, MAILBOX_UID_VALIDITY)
-            .values(mailboxId.asUuid(), mailboxPath.getName(), mailboxPath.getUser().asString(), mailboxPath.getNamespace(), uidValidity.asLong())))
+                .values(mailboxId.asUuid(), mailboxPath.getName(), mailboxPath.getUser().asString(), mailboxPath.getNamespace(), uidValidity.asLong())))
             .thenReturn(new Mailbox(mailboxPath, uidValidity, mailboxId))
             .onErrorMap(e -> e instanceof DataAccessException && e.getMessage().contains(DUPLICATE_VIOLATION_MESSAGE),
                 e -> new MailboxExistsException(mailboxPath.getName()));
@@ -91,6 +131,24 @@ public class PostgresMailboxDAO {
             .switchIfEmpty(Mono.error(new MailboxNotFoundException(mailbox.getMailboxId())));
     }
 
+    public Mono<MailboxACL> upsertACL(MailboxId mailboxId, MailboxACL acl) {
+        return postgresExecutor.executeRow(dslContext -> Mono.from(dslContext.update(TABLE_NAME)
+            .set(MAILBOX_ACL, MAILBOX_ACL_TO_HSTORE_FUNCTION.apply(acl))
+            .where(MAILBOX_ID.eq(((PostgresMailboxId) mailboxId).asUuid()))
+            .returning(MAILBOX_ACL)))
+            .map(record -> HSTORE_TO_MAILBOX_ACL_FUNCTION.apply(record.get(MAILBOX_ACL)));
+    }
+
+    public Flux<Mailbox> findNonPersonalMailboxes(Username userName, MailboxACL.Right right) {
+        String mailboxACLEntryByUser = String.format("mailbox_acl -> '%s'", userName.asString());
+
+        return postgresExecutor.executeRows(dslContext -> Flux.from(dslContext.selectFrom(TABLE_NAME)
+                .where(MAILBOX_ACL.isNotNull(),
+                    DSL.field(mailboxACLEntryByUser).isNotNull(),
+                    DSL.field(mailboxACLEntryByUser).contains(Character.toString(right.asCharacter())))))
+            .map(this::asMailbox);
+    }
+
     public Mono<Void> delete(MailboxId mailboxId) {
         return postgresExecutor.executeVoid(dslContext -> Mono.from(dslContext.deleteFrom(TABLE_NAME)
             .where(MAILBOX_ID.eq(((PostgresMailboxId) mailboxId).asUuid()))));
@@ -140,8 +198,10 @@ public class PostgresMailboxDAO {
     }
 
     private Mailbox asMailbox(Record record) {
-        return new Mailbox(new MailboxPath(record.get(MAILBOX_NAMESPACE), Username.of(record.get(USER_NAME)), record.get(MAILBOX_NAME)),
+        Mailbox mailbox = new Mailbox(new MailboxPath(record.get(MAILBOX_NAMESPACE), Username.of(record.get(USER_NAME)), record.get(MAILBOX_NAME)),
             UidValidity.of(record.get(MAILBOX_UID_VALIDITY)), PostgresMailboxId.of(record.get(MAILBOX_ID)));
+        mailbox.setACL(HSTORE_TO_MAILBOX_ACL_FUNCTION.apply(Hstore.hstore(record.get(MAILBOX_ACL, LinkedHashMap.class))));
+        return mailbox;
     }
 
     public Mono<MessageUid> findLastUidByMailboxId(MailboxId mailboxId) {
diff --git a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapperACLTest.java b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapperACLTest.java
new file mode 100644
index 0000000000..4b73a298ea
--- /dev/null
+++ b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresMailboxMapperACLTest.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * 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.postgres.mail;
+
+import org.apache.james.backends.postgres.PostgresExtension;
+import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxDAO;
+import org.apache.james.mailbox.store.mail.MailboxMapper;
+import org.apache.james.mailbox.store.mail.model.MailboxMapperACLTest;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class PostgresMailboxMapperACLTest extends MailboxMapperACLTest {
+    @RegisterExtension
+    static PostgresExtension postgresExtension = PostgresExtension.withoutRowLevelSecurity(PostgresMailboxModule.MODULE);
+
+    @Override
+    protected MailboxMapper createMailboxMapper() {
+        return new PostgresMailboxMapper(new PostgresMailboxDAO(postgresExtension.getPostgresExecutor()));
+    }
+}


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