You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2022/12/05 02:54:13 UTC
[james-project] branch master updated: JAMES-3461 - Fix Mailbox/changes do not take isSubscribe changes into account (#1320)
This is an automated email from the ASF dual-hosted git repository.
rcordier 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 0a7c50830f JAMES-3461 - Fix Mailbox/changes do not take isSubscribe changes into account (#1320)
0a7c50830f is described below
commit 0a7c50830fa98ee32b8822816349cc8e655824c5
Author: vttran <vt...@linagora.com>
AuthorDate: Mon Dec 5 09:54:08 2022 +0700
JAMES-3461 - Fix Mailbox/changes do not take isSubscribe changes into account (#1320)
---
.../apache/james/mailbox/events/MailboxEvents.java | 62 ++++++++
.../cassandra/CassandraMailboxManagerTest.java | 4 +-
.../CassandraSubscriptionManagerTest.java | 23 ++-
.../james/event/json/MailboxEventSerializer.scala | 26 ++-
.../main/resources/META-INF/spring/mailbox-jpa.xml | 2 +
.../james/mailbox/jpa/JPAMailboxManagerTest.java | 2 +-
.../mailbox/jpa/JPASubscriptionManagerTest.java | 9 +-
.../resources/META-INF/spring/mailbox-memory.xml | 2 +
.../mailbox/inmemory/MemoryMailboxManagerTest.java | 2 +-
.../mailbox/store/StoreSubscriptionManager.java | 41 ++++-
.../james/mailbox/store/event/EventFactory.java | 61 ++++++-
.../cassandra/host/CassandraHostSystem.java | 2 +-
.../org/apache/james/imap/scripts/Subscribe.test | 16 ++
.../inmemory/host/InMemoryHostSystem.java | 4 +-
.../mpt/imapmailbox/jpa/host/JPAHostSystem.java | 2 +-
.../lucenesearch/host/LuceneSearchHostSystem.java | 2 +-
.../elasticsearch/host/OpenSearchHostSystem.java | 2 +-
.../rabbitmq/host/RabbitMQEventBusHostSystem.java | 2 +-
.../james/jmap/api/change/MailboxChange.java | 49 ++++++
.../jmap/draft/methods/GetMailboxesMethodTest.java | 2 +-
.../jmap/http/DefaultMailboxesProvisionerTest.java | 2 +-
.../james/jmap/rfc8621/contract/JmapRequests.scala | 58 +++++++
.../contract/MailboxChangesMethodContract.scala | 176 +++++++++++++++++++++
.../contract/MailboxSetMethodContract.scala | 128 ++++++++++++++-
.../james/jmap/change/MailboxChangeListener.scala | 8 +-
.../jmap/change/MailboxChangeListenerTest.scala | 45 +++++-
.../james/jmap/http/MailboxesProvisionerTest.scala | 2 +-
.../james/imapserver/netty/IMAPServerTest.java | 4 +-
.../service/SubscribeAllRequestToTaskTest.java | 4 +-
29 files changed, 704 insertions(+), 38 deletions(-)
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
index 3a45e0eff6..f56c8518d3 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
@@ -587,4 +587,66 @@ public interface MailboxEvents {
}
}
+ class MailboxSubscribedEvent extends MailboxEvent {
+
+ public MailboxSubscribedEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
+ super(sessionId, username, path, mailboxId, eventId);
+ }
+
+ @Override
+ public boolean isNoop() {
+ return false;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof MailboxACLUpdated) {
+ MailboxACLUpdated that = (MailboxACLUpdated) o;
+
+ return Objects.equals(this.eventId, that.eventId)
+ && Objects.equals(this.sessionId, that.sessionId)
+ && Objects.equals(this.username, that.username)
+ && Objects.equals(this.path, that.path)
+ && Objects.equals(this.mailboxId, that.mailboxId);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(eventId, sessionId, username, path, mailboxId);
+ }
+ }
+
+ class MailboxUnsubscribedEvent extends MailboxEvent {
+
+ public MailboxUnsubscribedEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
+ super(sessionId, username, path, mailboxId, eventId);
+ }
+
+ @Override
+ public boolean isNoop() {
+ return false;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof MailboxACLUpdated) {
+ MailboxACLUpdated that = (MailboxACLUpdated) o;
+
+ return Objects.equals(this.eventId, that.eventId)
+ && Objects.equals(this.sessionId, that.sessionId)
+ && Objects.equals(this.username, that.username)
+ && Objects.equals(this.path, that.path)
+ && Objects.equals(this.mailboxId, that.mailboxId);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(eventId, sessionId, username, path, mailboxId);
+ }
+ }
+
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
index 97aa4363df..7fff10ce0b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
@@ -120,7 +120,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
@Override
protected SubscriptionManager provideSubscriptionManager() {
- return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+ return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory(), provideMailboxManager().getMapperFactory(), provideMailboxManager().getEventBus());
}
@Override
@@ -904,7 +904,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
@Override
protected SubscriptionManager provideSubscriptionManager() {
- return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+ return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory(), provideMailboxManager().getMapperFactory(), provideMailboxManager().getEventBus());
}
@Override
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
index 37d980a9e2..2c6a90d691 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
@@ -24,8 +24,13 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
import org.apache.james.blob.api.BlobStore;
import org.apache.james.core.Username;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.SubscriptionManager;
import org.apache.james.mailbox.SubscriptionManagerContract;
import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
@@ -49,11 +54,13 @@ import org.apache.james.mailbox.cassandra.mail.CassandraUidProvider;
import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService;
import org.apache.james.mailbox.cassandra.modules.CassandraAnnotationModule;
+import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
import org.apache.james.mailbox.cassandra.modules.CassandraSubscriptionModule;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.BatchSizes;
import org.apache.james.mailbox.store.StoreSubscriptionManager;
import org.apache.james.mailbox.store.user.model.Subscription;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -69,7 +76,9 @@ class CassandraSubscriptionManagerTest implements SubscriptionManagerContract {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraModule.aggregateModules(
CassandraSubscriptionModule.MODULE,
- CassandraAnnotationModule.MODULE));
+ CassandraAnnotationModule.MODULE,
+ CassandraSchemaVersionModule.MODULE,
+ CassandraMailboxModule.MODULE));
private SubscriptionManager subscriptionManager;
private CassandraMailboxSessionMapperFactory mailboxSessionMapperFactory;
@@ -90,7 +99,7 @@ class CassandraSubscriptionManagerTest implements SubscriptionManagerContract {
CassandraMailboxCounterDAO mailboxCounterDAO = null;
CassandraMailboxRecentsDAO mailboxRecentsDAO = null;
CassandraMailboxDAO mailboxDAO = null;
- CassandraMailboxPathV3DAO mailboxPathV3DAO = null;
+ CassandraMailboxPathV3DAO mailboxPathV3DAO = new CassandraMailboxPathV3DAO(cassandraCluster.getCassandraCluster().getConf());
CassandraFirstUnseenDAO firstUnseenDAO = null;
CassandraApplicableFlagDAO applicableFlagDAO = null;
CassandraDeletedMessageDAO deletedMessageDAO = null;
@@ -103,7 +112,7 @@ class CassandraSubscriptionManagerTest implements SubscriptionManagerContract {
CassandraModSeqProvider modSeqProvider = null;
RecomputeMailboxCountersService recomputeMailboxCountersService = null;
- mailboxSessionMapperFactory = new CassandraMailboxSessionMapperFactory(
+ mailboxSessionMapperFactory = new CassandraMailboxSessionMapperFactory(
uidProvider,
modSeqProvider,
cassandraCluster.getCassandraCluster().getConf(),
@@ -128,7 +137,13 @@ class CassandraSubscriptionManagerTest implements SubscriptionManagerContract {
recomputeMailboxCountersService,
CassandraConfiguration.DEFAULT_CONFIGURATION,
BatchSizes.defaultValues());
- subscriptionManager = new StoreSubscriptionManager(mailboxSessionMapperFactory);
+
+ InVMEventBus eventBus = new InVMEventBus(new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, new MemoryEventDeadLetters());
+
+ subscriptionManager = new StoreSubscriptionManager(
+ mailboxSessionMapperFactory,
+ mailboxSessionMapperFactory,
+ eventBus);
}
@Test
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
index 23cf3d8298..1e31a140db 100644
--- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
+++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
@@ -31,7 +31,7 @@ import org.apache.james.event.json.DTOs._
import org.apache.james.events.Event.EventId
import org.apache.james.events.{EventSerializer, Event => JavaEvent}
import org.apache.james.mailbox.MailboxSession.SessionId
-import org.apache.james.mailbox.events.MailboxEvents.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
+import org.apache.james.mailbox.events.MailboxEvents.{MailboxSubscribedEvent => JavaMailboxSubscribedEvent, MailboxUnsubscribedEvent => JavaMailboxUnsubscribedEvent, Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
import org.apache.james.mailbox.events.{MessageMoveEvent => JavaMessageMoveEvent}
import org.apache.james.mailbox.model.{MailboxId, MessageId, MessageMoves, QuotaRoot, ThreadId, MailboxACL => JavaMailboxACL, MessageMetaData => JavaMessageMetaData, Quota => JavaQuota}
import org.apache.james.mailbox.quota.QuotaRootDeserializer
@@ -116,6 +116,14 @@ private object DTO {
updatedFlags.map(_.toJava).asJava,
eventId)
}
+
+ case class MailboxSubscribedEvent(eventId: EventId, mailboxPath: MailboxPath, mailboxId: MailboxId, user: Username, sessionId: SessionId) extends Event {
+ override def toJava: JavaEvent = new JavaMailboxSubscribedEvent(sessionId, user, mailboxPath.toJava, mailboxId, eventId)
+ }
+
+ case class MailboxUnSubscribedEvent(eventId: EventId, mailboxPath: MailboxPath, mailboxId: MailboxId, user: Username, sessionId: SessionId) extends Event {
+ override def toJava: JavaEvent = new JavaMailboxUnsubscribedEvent(sessionId, user, mailboxPath.toJava, mailboxId, eventId)
+ }
}
private object ScalaConverter {
@@ -193,6 +201,20 @@ private object ScalaConverter {
mailboxId = event.getMailboxId,
updatedFlags = event.getUpdatedFlags.asScala.toList.map(DTOs.UpdatedFlags.toUpdatedFlags))
+ private def toScala(event: JavaMailboxSubscribedEvent): DTO.MailboxSubscribedEvent = DTO.MailboxSubscribedEvent(
+ eventId = event.getEventId,
+ mailboxPath = MailboxPath.fromJava(event.getMailboxPath),
+ mailboxId = event.getMailboxId,
+ user = event.getUsername,
+ sessionId = event.getSessionId)
+
+ private def toScala(event: JavaMailboxUnsubscribedEvent): DTO.MailboxUnSubscribedEvent = DTO.MailboxUnSubscribedEvent(
+ eventId = event.getEventId,
+ mailboxPath = MailboxPath.fromJava(event.getMailboxPath),
+ mailboxId = event.getMailboxId,
+ user = event.getUsername,
+ sessionId = event.getSessionId)
+
def toScala(javaEvent: JavaEvent): Event = javaEvent match {
case e: JavaAdded => toScala(e)
case e: JavaExpunged => toScala(e)
@@ -203,6 +225,8 @@ private object ScalaConverter {
case e: JavaMailboxRenamed => toScala(e)
case e: JavaMessageMoveEvent => toScala(e)
case e: JavaQuotaUsageUpdatedEvent => toScala(e)
+ case e: JavaMailboxSubscribedEvent => toScala(e)
+ case e: JavaMailboxUnsubscribedEvent => toScala(e)
case _ => throw new RuntimeException("no Scala conversion known")
}
}
diff --git a/mailbox/jpa/src/main/resources/META-INF/spring/mailbox-jpa.xml b/mailbox/jpa/src/main/resources/META-INF/spring/mailbox-jpa.xml
index 6d717dc1d2..044f1d3a98 100644
--- a/mailbox/jpa/src/main/resources/META-INF/spring/mailbox-jpa.xml
+++ b/mailbox/jpa/src/main/resources/META-INF/spring/mailbox-jpa.xml
@@ -48,6 +48,8 @@
<bean id ="jpa-subscriptionManager" class="org.apache.james.mailbox.store.StoreSubscriptionManager">
<constructor-arg index="0" ref="jpa-sessionMapperFactory"/>
+ <constructor-arg index="1" ref="jpa-sessionMapperFactory"/>
+ <constructor-arg index="2" ref="event-bus"/>
</bean>
<bean id="jpa-sessionMapperFactory" class="org.apache.james.mailbox.jpa.JPAMailboxSessionMapperFactory">
<constructor-arg index="0" ref="entityManagerFactory"/>
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
index bd632cca13..bab657d713 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
@@ -52,7 +52,7 @@ class JPAMailboxManagerTest extends MailboxManagerTest<OpenJPAMailboxManager> {
@Override
protected SubscriptionManager provideSubscriptionManager() {
- return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+ return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory(), provideMailboxManager().getMapperFactory(), provideMailboxManager().getEventBus());
}
@AfterEach
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPASubscriptionManagerTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPASubscriptionManagerTest.java
index 41bfd71b79..de8112a3e4 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPASubscriptionManagerTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPASubscriptionManagerTest.java
@@ -21,11 +21,16 @@ package org.apache.james.mailbox.jpa;
import javax.persistence.EntityManagerFactory;
import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.SubscriptionManager;
import org.apache.james.mailbox.SubscriptionManagerContract;
import org.apache.james.mailbox.jpa.mail.JPAModSeqProvider;
import org.apache.james.mailbox.jpa.mail.JPAUidProvider;
import org.apache.james.mailbox.store.StoreSubscriptionManager;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -47,8 +52,8 @@ class JPASubscriptionManagerTest implements SubscriptionManagerContract {
JPAMailboxSessionMapperFactory mapperFactory = new JPAMailboxSessionMapperFactory(entityManagerFactory,
new JPAUidProvider(entityManagerFactory),
new JPAModSeqProvider(entityManagerFactory));
-
- subscriptionManager = new StoreSubscriptionManager(mapperFactory);
+ InVMEventBus eventBus = new InVMEventBus(new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, new MemoryEventDeadLetters());
+ subscriptionManager = new StoreSubscriptionManager(mapperFactory, mapperFactory, eventBus);
}
@AfterEach
diff --git a/mailbox/memory/src/main/resources/META-INF/spring/mailbox-memory.xml b/mailbox/memory/src/main/resources/META-INF/spring/mailbox-memory.xml
index 6f5ba0cf2a..a4cf3f9053 100644
--- a/mailbox/memory/src/main/resources/META-INF/spring/mailbox-memory.xml
+++ b/mailbox/memory/src/main/resources/META-INF/spring/mailbox-memory.xml
@@ -48,6 +48,8 @@
<bean id ="memory-subscriptionManager" class="org.apache.james.mailbox.store.StoreSubscriptionManager">
<constructor-arg index="0" ref="memory-sessionMapperFactory"/>
+ <constructor-arg index="1" ref="memory-sessionMapperFactory"/>
+ <constructor-arg index="2" ref="event-bus"/>
</bean>
<bean id="memory-sessionMapperFactory" class="org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory" />
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
index 4bde607d21..2c107a5af4 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
@@ -33,7 +33,7 @@ class MemoryMailboxManagerTest extends MailboxManagerTest<InMemoryMailboxManager
@Override
protected SubscriptionManager provideSubscriptionManager() {
- return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+ return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory(), provideMailboxManager().getMapperFactory(), provideMailboxManager().getEventBus());
}
@Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreSubscriptionManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreSubscriptionManager.java
index 8e0f9f1df0..090e01f0a9 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreSubscriptionManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreSubscriptionManager.java
@@ -25,12 +25,15 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
+import org.apache.james.events.EventBus;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.RequestAware;
import org.apache.james.mailbox.SubscriptionManager;
+import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.SubscriptionException;
import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.store.event.EventFactory;
import org.apache.james.mailbox.store.transaction.Mapper;
import org.apache.james.mailbox.store.user.SubscriptionMapper;
import org.apache.james.mailbox.store.user.SubscriptionMapperFactory;
@@ -46,10 +49,16 @@ public class StoreSubscriptionManager implements SubscriptionManager {
private static final int INITIAL_SIZE = 32;
protected SubscriptionMapperFactory mapperFactory;
+ private final MailboxSessionMapperFactory mailboxSessionMapperFactory;
+ private final EventBus eventBus;
@Inject
- public StoreSubscriptionManager(SubscriptionMapperFactory mapperFactory) {
+ public StoreSubscriptionManager(SubscriptionMapperFactory mapperFactory,
+ MailboxSessionMapperFactory mailboxSessionMapperFactory,
+ EventBus eventBus) {
this.mapperFactory = mapperFactory;
+ this.mailboxSessionMapperFactory = mailboxSessionMapperFactory;
+ this.eventBus = eventBus;
}
@Override
@@ -63,6 +72,7 @@ public class StoreSubscriptionManager implements SubscriptionManager {
} catch (MailboxException e) {
throw new SubscriptionException(e);
}
+ dispatchSubscribedEvent(session, mailbox).block();
}
@Override
@@ -70,12 +80,24 @@ public class StoreSubscriptionManager implements SubscriptionManager {
try {
SubscriptionMapper mapper = mapperFactory.getSubscriptionMapper(session);
Subscription newSubscription = new Subscription(session.getUser(), mailbox.asEscapedString());
- return mapper.executeReactive(mapper.saveReactive(newSubscription));
+ return mapper.executeReactive(mapper.saveReactive(newSubscription))
+ .then(dispatchSubscribedEvent(session, mailbox));
} catch (SubscriptionException e) {
return Mono.error(e);
}
}
+ private Mono<Void> dispatchSubscribedEvent(MailboxSession session, MailboxPath mailboxPath) {
+ return mailboxSessionMapperFactory.getMailboxMapper(session)
+ .findMailboxByPath(mailboxPath)
+ .flatMap(mailbox -> eventBus.dispatch(EventFactory.mailboxSubscribed()
+ .randomEventId()
+ .mailboxSession(session)
+ .mailbox(mailbox)
+ .build(),
+ new MailboxIdRegistrationKey(mailbox.getMailboxId())));
+ }
+
@Override
public Publisher<Void> unsubscribeReactive(MailboxPath mailbox, MailboxSession session) {
try {
@@ -86,7 +108,8 @@ public class StoreSubscriptionManager implements SubscriptionManager {
return mapper.executeReactive(mapper.deleteReactive(oldSubscription))
.then(legacyOldSubscription
.map(subscription -> mapper.executeReactive(mapper.deleteReactive(subscription)))
- .orElse(Mono.empty()));
+ .orElse(Mono.empty()))
+ .then(dispatchUnSubscribedEvent(session, mailbox));
} catch (SubscriptionException e) {
return Mono.error(e);
}
@@ -122,6 +145,18 @@ public class StoreSubscriptionManager implements SubscriptionManager {
} catch (MailboxException e) {
throw new SubscriptionException(e);
}
+ dispatchUnSubscribedEvent(session, mailbox).block();
+ }
+
+ private Mono<Void> dispatchUnSubscribedEvent(MailboxSession session, MailboxPath mailboxPath) {
+ return mailboxSessionMapperFactory.getMailboxMapper(session)
+ .findMailboxByPath(mailboxPath)
+ .flatMap(mailbox -> eventBus.dispatch(EventFactory.mailboxUnSubscribed()
+ .randomEventId()
+ .mailboxSession(session)
+ .mailbox(mailbox)
+ .build(),
+ new MailboxIdRegistrationKey(mailbox.getMailboxId())));
}
@Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
index a725f0ff0c..f2a7052e54 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
@@ -34,6 +34,7 @@ import org.apache.james.events.Event;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.events.MailboxEvents;
import org.apache.james.mailbox.events.MailboxEvents.Added;
import org.apache.james.mailbox.events.MailboxEvents.Expunged;
import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
@@ -427,6 +428,56 @@ public class EventFactory {
}
}
+ public static class MailboxSubscribedFinalStage {
+ private final Event.EventId eventId;
+ private final MailboxPath path;
+ private final MailboxId mailboxId;
+ private final Username username;
+ private final MailboxSession.SessionId sessionId;
+
+ MailboxSubscribedFinalStage(Event.EventId eventId, MailboxPath path, MailboxId mailboxId, Username username, MailboxSession.SessionId sessionId) {
+ this.eventId = eventId;
+ this.path = path;
+ this.mailboxId = mailboxId;
+ this.username = username;
+ this.sessionId = sessionId;
+ }
+
+ public MailboxEvents.MailboxSubscribedEvent build() {
+ Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mailboxId);
+ Preconditions.checkNotNull(username);
+ Preconditions.checkNotNull(sessionId);
+
+ return new MailboxEvents.MailboxSubscribedEvent(sessionId, username, path, mailboxId, eventId);
+ }
+ }
+
+ public static class MailboxUnSubscribedFinalStage {
+ private final Event.EventId eventId;
+ private final MailboxPath path;
+ private final MailboxId mailboxId;
+ private final Username username;
+ private final MailboxSession.SessionId sessionId;
+
+ MailboxUnSubscribedFinalStage(Event.EventId eventId, MailboxPath path, MailboxId mailboxId, Username username, MailboxSession.SessionId sessionId) {
+ this.eventId = eventId;
+ this.path = path;
+ this.mailboxId = mailboxId;
+ this.username = username;
+ this.sessionId = sessionId;
+ }
+
+ public MailboxEvents.MailboxUnsubscribedEvent build() {
+ Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mailboxId);
+ Preconditions.checkNotNull(username);
+ Preconditions.checkNotNull(sessionId);
+
+ return new MailboxEvents.MailboxUnsubscribedEvent(sessionId, username, path, mailboxId, eventId);
+ }
+ }
+
public static RequireMailboxEvent<RequireMetadata<RequireIsDelivery<AddedFinalStage>>> added() {
return eventId -> user -> sessionId -> mailboxId -> path -> metaData -> isDelivery -> new AddedFinalStage(eventId, path, mailboxId, user, sessionId, metaData, isDelivery);
}
@@ -443,7 +494,7 @@ public class EventFactory {
return eventId -> user -> sessionId -> mailboxId -> oldPath -> newPath -> new MailboxRenamedFinalStage(eventId, oldPath, mailboxId, user, sessionId, newPath);
}
- public static RequireMailboxEvent<RequireQuotaRoot<RequireMailboxACL<RequireQuotaCountValue<RequireQuotaSizeValue<MailboxDeletionFinalStage>>>>> mailboxDeleted() {
+ public static RequireMailboxEvent<RequireQuotaRoot<RequireMailboxACL<RequireQuotaCountValue<RequireQuotaSizeValue<MailboxDeletionFinalStage>>>>> mailboxDeleted() {
return eventId -> user -> sessionId -> mailboxId -> path -> quotaRoot -> mailboxACL -> quotaCount -> quotaSize -> new MailboxDeletionFinalStage(
eventId, path, mailboxACL, mailboxId, user, sessionId, quotaRoot, quotaCount, quotaSize);
}
@@ -460,6 +511,14 @@ public class EventFactory {
return eventId -> user -> quotaRoot -> quotaCount -> quotaSize -> instant -> new QuotaUsageUpdatedFinalStage(eventId, user, quotaRoot, quotaCount, quotaSize, instant);
}
+ public static RequireMailboxEvent<MailboxSubscribedFinalStage> mailboxSubscribed() {
+ return eventId -> user -> sessionId -> mailboxId -> path -> new MailboxSubscribedFinalStage(eventId, path, mailboxId, user, sessionId);
+ }
+
+ public static RequireMailboxEvent<MailboxUnSubscribedFinalStage> mailboxUnSubscribed() {
+ return eventId -> user -> sessionId -> mailboxId -> path -> new MailboxUnSubscribedFinalStage(eventId, path, mailboxId, user, sessionId);
+ }
+
public static MessageMoveEvent.Builder moved() {
return MessageMoveEvent.builder();
}
diff --git a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
index aec693c450..e9b7b3c789 100644
--- a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
+++ b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
@@ -127,7 +127,7 @@ public class CassandraHostSystem extends JamesImapHostSystem {
eventBus.register(quotaUpdater);
- SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mapperFactory);
+ SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mapperFactory, mapperFactory, eventBus);
configure(new DefaultImapDecoderFactory().buildImapDecoder(),
new DefaultImapEncoderFactory().buildImapEncoder(),
diff --git a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Subscribe.test b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Subscribe.test
index 461d067b8b..1621e72a2e 100644
--- a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Subscribe.test
+++ b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Subscribe.test
@@ -51,6 +51,22 @@ S: \* LSUB \(\) \"\.\" \"subscribetest1\.subfolder1\"
}
S: a06 OK LSUB completed.
+C: b05 SUBSCRIBE whatever
+S: b05 OK SUBSCRIBE completed.
+
+# LIST All subscribed
+C: b06 LSUB "" "*"
+SUB {
+S: \* LSUB \(\) \"\.\" \"whatever\"
+S: \* LSUB \(\) \"\.\" \"subscribetest\"
+S: \* LSUB \(\) \"\.\" \"subscribetest\.subfolder\"
+S: \* LSUB \(\) \"\.\" \"subscribetest1\.subfolder1\"
+}
+S: b06 OK LSUB completed.
+
+C: b08 UNSUBSCRIBE whatever
+S: b08 OK UNSUBSCRIBE completed.
+
# LIST A subset of subscribed
C: a07 LSUB "" "subscribetest.sub*"
S: \* LSUB \(\) \"\.\" \"subscribetest\.subfolder\"
diff --git a/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/host/InMemoryHostSystem.java b/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/host/InMemoryHostSystem.java
index d327eaeb4e..a354f8e09d 100644
--- a/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/host/InMemoryHostSystem.java
+++ b/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/host/InMemoryHostSystem.java
@@ -64,7 +64,9 @@ public class InMemoryHostSystem extends JamesImapHostSystem {
this.mailboxManager = resources.getMailboxManager();
this.perUserMaxQuotaManager = resources.getMaxQuotaManager();
- ImapProcessor defaultImapProcessorFactory = DefaultImapProcessorFactory.createDefaultProcessor(mailboxManager, mailboxManager.getEventBus(), new StoreSubscriptionManager(mailboxManager.getMapperFactory()),
+ ImapProcessor defaultImapProcessorFactory = DefaultImapProcessorFactory.createDefaultProcessor(mailboxManager, mailboxManager.getEventBus(), new StoreSubscriptionManager(mailboxManager.getMapperFactory(),
+ mailboxManager.getMapperFactory(),
+ mailboxManager.getEventBus()),
mailboxManager.getQuotaComponents().getQuotaManager(), mailboxManager.getQuotaComponents().getQuotaRootResolver(), new DefaultMetricFactory());
configure(new DefaultImapDecoderFactory().buildImapDecoder(),
diff --git a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
index 7e6095f072..4ef7a4fa78 100644
--- a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
+++ b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
@@ -121,7 +121,7 @@ public class JPAHostSystem extends JamesImapHostSystem {
eventBus.register(quotaUpdater);
eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
- SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mapperFactory);
+ SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mapperFactory, mapperFactory, eventBus);
ImapProcessor defaultImapProcessorFactory =
DefaultImapProcessorFactory.createDefaultProcessor(
diff --git a/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java b/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
index a19759930f..84cbb60c2e 100644
--- a/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
+++ b/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
@@ -75,7 +75,7 @@ public class LuceneSearchHostSystem extends JamesImapHostSystem {
searchIndex = (LuceneMessageSearchIndex) resources.getSearchIndex();
searchIndex.setEnableSuffixMatch(true);
- SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory());
+ SubscriptionManager subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory(), mailboxManager.getMapperFactory(), mailboxManager.getEventBus());
ImapProcessor defaultImapProcessorFactory =
DefaultImapProcessorFactory.createDefaultProcessor(
diff --git a/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java b/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java
index ed602b4876..a8dcfcf86b 100644
--- a/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java
+++ b/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java
@@ -114,7 +114,7 @@ public class OpenSearchHostSystem extends JamesImapHostSystem {
ImapProcessor defaultImapProcessorFactory =
DefaultImapProcessorFactory.createDefaultProcessor(mailboxManager,
resources.getMailboxManager().getEventBus(),
- new StoreSubscriptionManager(mailboxManager.getMapperFactory()),
+ new StoreSubscriptionManager(mailboxManager.getMapperFactory(), mailboxManager.getMapperFactory(), mailboxManager.getEventBus()),
new NoQuotaManager(),
resources.getDefaultUserQuotaRootResolver(),
new DefaultMetricFactory());
diff --git a/mpt/impl/imap-mailbox/rabbitmq/src/test/java/org/apache/james/mpt/imapmailbox/rabbitmq/host/RabbitMQEventBusHostSystem.java b/mpt/impl/imap-mailbox/rabbitmq/src/test/java/org/apache/james/mpt/imapmailbox/rabbitmq/host/RabbitMQEventBusHostSystem.java
index 057cc3a96b..a2e1cc5c18 100644
--- a/mpt/impl/imap-mailbox/rabbitmq/src/test/java/org/apache/james/mpt/imapmailbox/rabbitmq/host/RabbitMQEventBusHostSystem.java
+++ b/mpt/impl/imap-mailbox/rabbitmq/src/test/java/org/apache/james/mpt/imapmailbox/rabbitmq/host/RabbitMQEventBusHostSystem.java
@@ -101,7 +101,7 @@ public class RabbitMQEventBusHostSystem extends JamesImapHostSystem {
DefaultImapProcessorFactory.createDefaultProcessor(
resources.getMailboxManager(),
eventBus,
- new StoreSubscriptionManager(resources.getMailboxManager().getMapperFactory()),
+ new StoreSubscriptionManager(resources.getMailboxManager().getMapperFactory(), resources.getMailboxManager().getMapperFactory(), resources.getMailboxManager().getEventBus()),
resources.getQuotaManager(),
resources.getDefaultUserQuotaRootResolver(),
new DefaultMetricFactory());
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
index fc029c2397..f8cc6b02c3 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
@@ -28,6 +28,7 @@ import java.util.stream.Stream;
import javax.inject.Inject;
import org.apache.james.jmap.api.model.AccountId;
+import org.apache.james.mailbox.events.MailboxEvents;
import org.apache.james.mailbox.events.MailboxEvents.MailboxACLUpdated;
import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
@@ -158,6 +159,54 @@ public class MailboxChange implements JmapChange {
.collect(ImmutableList.toImmutableList());
}
+ public List<JmapChange> fromMailboxSubscribed(List<AccountId> sharees, MailboxEvents.MailboxSubscribedEvent mailboxSubscribedEvent,
+ ZonedDateTime now) {
+ MailboxChange ownerChange = MailboxChange.builder()
+ .accountId(AccountId.fromUsername(mailboxSubscribedEvent.getUsername()))
+ .state(stateFactory.generate())
+ .date(now)
+ .isCountChange(false)
+ .updated(ImmutableList.of(mailboxSubscribedEvent.getMailboxId()))
+ .build();
+
+ Stream<MailboxChange> shareeChanges = sharees.stream()
+ .map(shareeId -> MailboxChange.builder()
+ .accountId(shareeId)
+ .state(stateFactory.generate())
+ .date(now)
+ .isCountChange(false)
+ .updated(ImmutableList.of(mailboxSubscribedEvent.getMailboxId()))
+ .delegated()
+ .build());
+
+ return Stream.concat(Stream.of(ownerChange), shareeChanges)
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ public List<JmapChange> fromMailboxUnSubscribed(List<AccountId> sharees, MailboxEvents.MailboxUnsubscribedEvent mailboxUnsubscribedEvent,
+ ZonedDateTime now) {
+ MailboxChange ownerChange = MailboxChange.builder()
+ .accountId(AccountId.fromUsername(mailboxUnsubscribedEvent.getUsername()))
+ .state(stateFactory.generate())
+ .date(now)
+ .isCountChange(false)
+ .updated(ImmutableList.of(mailboxUnsubscribedEvent.getMailboxId()))
+ .build();
+
+ Stream<MailboxChange> shareeChanges = sharees.stream()
+ .map(shareeId -> MailboxChange.builder()
+ .accountId(shareeId)
+ .state(stateFactory.generate())
+ .date(now)
+ .isCountChange(false)
+ .updated(ImmutableList.of(mailboxUnsubscribedEvent.getMailboxId()))
+ .delegated()
+ .build());
+
+ return Stream.concat(Stream.of(ownerChange), shareeChanges)
+ .collect(ImmutableList.toImmutableList());
+ }
+
public List<JmapChange> fromMailboxACLUpdated(MailboxACLUpdated mailboxACLUpdated, ZonedDateTime now, List<AccountId> sharees) {
MailboxChange ownerChange = MailboxChange.builder()
.accountId(AccountId.fromUsername(mailboxACLUpdated.getUsername()))
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/GetMailboxesMethodTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/GetMailboxesMethodTest.java
index c17fbf61f0..dbbeb02c3d 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/GetMailboxesMethodTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/GetMailboxesMethodTest.java
@@ -86,7 +86,7 @@ public class GetMailboxesMethodTest {
quotaRootResolver = mailboxManager.getQuotaComponents().getQuotaRootResolver();
quotaManager = mailboxManager.getQuotaComponents().getQuotaManager();
mailboxFactory = new MailboxFactory(mailboxManager, quotaManager, quotaRootResolver);
- provisioner = new DefaultMailboxesProvisioner(mailboxManager, new StoreSubscriptionManager(mailboxManager.getMapperFactory()), new DefaultMetricFactory());
+ provisioner = new DefaultMailboxesProvisioner(mailboxManager, new StoreSubscriptionManager(mailboxManager.getMapperFactory(), mailboxManager.getMapperFactory(), mailboxManager.getEventBus()), new DefaultMetricFactory());
getMailboxesMethod = new GetMailboxesMethod(mailboxManager, quotaRootResolver, quotaManager, mailboxFactory, new DefaultMetricFactory(), provisioner);
}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesProvisionerTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesProvisionerTest.java
index 03810bdd09..fdb8c49ebe 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesProvisionerTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesProvisionerTest.java
@@ -52,7 +52,7 @@ public class DefaultMailboxesProvisionerTest {
session = MailboxSessionUtil.create(USERNAME);
mailboxManager = InMemoryIntegrationResources.defaultResources().getMailboxManager();
- subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory());
+ subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory(), mailboxManager.getMapperFactory(), mailboxManager.getEventBus());
testee = new DefaultMailboxesProvisioner(mailboxManager, subscriptionManager, new RecordingMetricFactory());
}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JmapRequests.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JmapRequests.scala
index dd9cd534c2..4610f4a94f 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JmapRequests.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JmapRequests.scala
@@ -156,4 +156,62 @@ object JmapRequests {
.statusCode(SC_OK)
.contentType(JSON)
}
+
+ def subscribe( mailboxId: String) : Unit = {
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [[
+ | "Mailbox/set", {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "$mailboxId": {
+ | "isSubscribed": true
+ | }
+ | }
+ | }, "c1"]
+ | ]
+ |}
+ |""".stripMargin
+
+ `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ }
+
+ def unSubscribe(mailboxId: String): Unit = {
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [[
+ | "Mailbox/set", {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "$mailboxId": {
+ | "isSubscribed": false
+ | }
+ | }
+ | }, "c1"]
+ | ]
+ |}
+ |""".stripMargin
+
+ `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ }
}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
index dad2ea17ac..24442ab51c 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
@@ -201,6 +201,182 @@ trait MailboxChangesMethodContract {
}
}
+ @Test
+ def mailboxChangesShouldReturnUpdatedChangesWhenSubscribed(server: GuiceJamesServer): Unit = {
+ val accountId: AccountId = AccountId.fromUsername(BOB)
+ val provisioningState: State = provisionSystemMailboxes(server)
+
+ // create mailbox with isSubscribed = false
+ val mailboxId: String = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(
+ """
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "create": {
+ | "C42": {
+ | "name": "myMailbox",
+ | "isSubscribed": false
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .jsonPath()
+ .get("methodResponses[0][1].created.C42.id");
+
+ val oldState: State = waitForNextState(server, accountId, provisioningState)
+
+ // change subscription
+ JmapRequests.subscribe(mailboxId)
+
+ awaitAtMostTenSeconds.untilAsserted { () =>
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Mailbox/changes",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "sinceState": "${oldState.getValue}"
+ | },
+ | "c1"]]
+ |}""".stripMargin)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .whenIgnoringPaths("methodResponses[0][1].newState")
+ .withOptions(new Options(IGNORING_ARRAY_ORDER))
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [ "Mailbox/changes", {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "oldState": "${oldState.getValue}",
+ | "hasMoreChanges": false,
+ | "updatedProperties": null,
+ | "created": [],
+ | "updated": ["$mailboxId"],
+ | "destroyed": []
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+ }
+
+ @Test
+ def mailboxChangesShouldReturnUpdatedChangesWhenUnSubscribed(server: GuiceJamesServer): Unit = {
+ val accountId: AccountId = AccountId.fromUsername(BOB)
+ val provisioningState: State = provisionSystemMailboxes(server)
+
+ // create mailbox with isSubscribed = true
+ val mailboxId: String = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(
+ """
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "create": {
+ | "C42": {
+ | "name": "myMailbox",
+ | "isSubscribed": true
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .jsonPath()
+ .get("methodResponses[0][1].created.C42.id");
+
+ val oldState: State = waitForNextState(server, accountId, provisioningState)
+
+ // change subscription
+ JmapRequests.unSubscribe(mailboxId)
+
+ awaitAtMostTenSeconds.untilAsserted { () =>
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Mailbox/changes",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "sinceState": "${oldState.getValue}"
+ | },
+ | "c1"]]
+ |}""".stripMargin)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .whenIgnoringPaths("methodResponses[0][1].newState")
+ .withOptions(new Options(IGNORING_ARRAY_ORDER))
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [ "Mailbox/changes", {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "oldState": "${oldState.getValue}",
+ | "hasMoreChanges": false,
+ | "updatedProperties": null,
+ | "created": [],
+ | "updated": ["$mailboxId"],
+ | "destroyed": []
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+ }
+
@Test
def mailboxChangesShouldReturnUpdatedChangesWhenAppendMessageToMailbox(server: GuiceJamesServer): Unit = {
val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
index bed70285a0..ba755bedfc 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
@@ -19,9 +19,6 @@
package org.apache.james.jmap.rfc8621.contract
-import java.nio.charset.StandardCharsets
-import java.time.Duration
-
import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
import io.restassured.RestAssured._
import io.restassured.http.ContentType.JSON
@@ -32,9 +29,9 @@ import org.apache.http.HttpStatus.SC_OK
import org.apache.james.GuiceJamesServer
import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
import org.apache.james.jmap.core.UuidState.INSTANCE
-import org.apache.james.jmap.draft.MessageIdProbe
+import org.apache.james.jmap.draft.{JmapGuiceProbe, MessageIdProbe}
import org.apache.james.jmap.http.UserCredential
-import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ANDRE, BOB, BOB_PASSWORD, CEDRIC, DAVID, DOMAIN, authScheme, baseRequestSpecBuilder}
+import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ACCOUNT_ID, ANDRE, BOB, BOB_PASSWORD, CEDRIC, DAVID, DOMAIN, authScheme, baseRequestSpecBuilder}
import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
import org.apache.james.mailbox.MessageManager.AppendCommand
import org.apache.james.mailbox.model.MailboxACL.{EntryKey, Right}
@@ -45,12 +42,34 @@ import org.apache.james.util.concurrency.ConcurrentTestRunner
import org.apache.james.utils.DataProbeImpl
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.{Assertions, SoftAssertions}
+import org.awaitility.Awaitility
import org.hamcrest.Matchers.{equalTo, hasSize, not}
-import org.junit.jupiter.api.{BeforeEach, Disabled, RepeatedTest, Tag, Test}
+import org.junit.jupiter.api.{BeforeEach, RepeatedTest, Tag, Test}
import reactor.core.scala.publisher.{SFlux, SMono}
+import reactor.core.scheduler.Schedulers
+import reactor.netty.http.client.HttpClient
+import sttp.capabilities.WebSockets
+import sttp.client3.monad.IdMonad
+import sttp.client3.okhttp.OkHttpSyncBackend
+import sttp.client3.{Identity, SttpBackend, asWebSocket, basicRequest}
+import sttp.model.Uri
+import sttp.monad.MonadError
+import sttp.monad.syntax.MonadErrorOps
+import sttp.ws.WebSocketFrame
+import sttp.ws.WebSocketFrame.Text
+
+import java.net.URI
+import java.nio.charset.StandardCharsets
+import java.time.Duration
+import scala.collection.mutable.ListBuffer
+import scala.jdk.CollectionConverters._
+
trait MailboxSetMethodContract {
+ private lazy val backend: SttpBackend[Identity, WebSockets] = OkHttpSyncBackend()
+ private lazy implicit val monadError: MonadError[Identity] = IdMonad
+
@BeforeEach
def setUp(server: GuiceJamesServer): Unit = {
server.getProbe(classOf[DataProbeImpl])
@@ -7981,4 +8000,101 @@ trait MailboxSetMethodContract {
.statusCode(SC_OK)
.body("methodResponses[0][1].oldState", not(equalTo(state)))
}
+
+ @Test
+ def webSocketShouldPushNewMessageWhenChangeSubscriptionOfMailbox(server: GuiceJamesServer): Unit = {
+ val bobPath = MailboxPath.inbox(BOB)
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+ Thread.sleep(100)
+
+ val socketPort = server.getProbe(classOf[JmapGuiceProbe])
+ .getJmapPort
+ .getValue
+
+ val response: Either[String, List[String]] =
+ basicRequest.get(Uri.apply(new URI(s"ws://127.0.0.1:$socketPort/jmap/ws")))
+ .header("Authorization", "Basic Ym9iQGRvbWFpbi50bGQ6Ym9icGFzc3dvcmQ=")
+ .header("Accept", ACCEPT_RFC8621_VERSION_HEADER)
+ .response(asWebSocket[Identity, List[String]] {
+ ws =>
+ ws.send(WebSocketFrame.text(
+ """{
+ | "@type": "WebSocketPushEnable",
+ | "dataTypes": ["Mailbox"]
+ |}""".stripMargin))
+
+ Thread.sleep(100)
+
+ ws.send(WebSocketFrame.text(
+ s"""{
+ | "@type": "Request",
+ | "id": "req-36",
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | ["Mailbox/set", {
+ | "accountId": "$ACCOUNT_ID",
+ | "update": {
+ | "${mailboxId.serialize}" : {
+ | "isSubscribed": true
+ | }
+ | }
+ | }, "c1"]]
+ |}""".stripMargin))
+
+ List(ws.receive()
+ .map { case t: Text =>
+ t.payload
+ })
+ })
+ .send(backend)
+ .body
+
+ Thread.sleep(200)
+ assertThat(response.toOption.get.asJava)
+ .hasSize(1)
+ assertThat(response.toOption.get.head)
+ .startsWith("{\"@type\":\"StateChange\",\"changed\":{\"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6\":{\"Mailbox\":")
+ }
+
+ @Test
+ def sseShouldHasNewEventWhenChangeSubscribeOfMailbox(server: GuiceJamesServer): Unit = {
+ val port = server.getProbe(classOf[JmapGuiceProbe]).getJmapPort.getValue
+ val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "mailbox12"))
+ Thread.sleep(500)
+
+ val seq = new ListBuffer[String]()
+ HttpClient.create
+ .baseUrl(s"http://127.0.0.1:$port/eventSource?types=*&ping=0&closeAfter=no")
+ .headers(builder => {
+ builder.add("Authorization", "Basic Ym9iQGRvbWFpbi50bGQ6Ym9icGFzc3dvcmQ=")
+ builder.add("Accept", ACCEPT_RFC8621_VERSION_HEADER)
+ })
+ .get()
+ .responseContent()
+ .map(buffer => {
+ val bytes = new Array[Byte](buffer.readableBytes)
+ buffer.readBytes(bytes)
+ new String(bytes, StandardCharsets.UTF_8)
+ })
+ .doOnNext(seq.addOne)
+ .subscribeOn(Schedulers.boundedElastic())
+ .subscribe()
+
+ Awaitility.`with`
+ .pollInterval(Duration.ofMillis(100))
+ .atMost(Duration.ofSeconds(100))
+ .await
+ .untilAsserted { () =>
+ // change subscription
+ JmapRequests.subscribe(mailboxId.serialize())
+ Thread.sleep(200)
+
+ assertThat(seq.asJava)
+ .hasSize(1)
+ assertThat(seq.head)
+ .startsWith("event: state\ndata: {\"@type\":\"StateChange\",\"changed\":{\"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6\":{\"Mailbox\":")
+ assertThat(seq.head).endsWith("\n\n")
+ }
+ }
+
}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
index 7d3b1bb020..9165342cf7 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
@@ -20,7 +20,6 @@
package org.apache.james.jmap.change
import java.time.{Clock, ZonedDateTime}
-
import javax.inject.{Inject, Named}
import org.apache.james.core.Username
import org.apache.james.events.Event.EventId
@@ -32,6 +31,7 @@ import org.apache.james.jmap.api.model.{AccountId, State, TypeName}
import org.apache.james.jmap.change.MailboxChangeListener.LOGGER
import org.apache.james.jmap.core.UuidState
import org.apache.james.mailbox.MailboxManager
+import org.apache.james.mailbox.events.MailboxEvents
import org.apache.james.mailbox.events.MailboxEvents.{Added, Expunged, FlagsUpdated, MailboxACLUpdated, MailboxAdded, MailboxDeletion, MailboxEvent, MailboxRenamed}
import org.apache.james.mailbox.model.{MailboxACL, MailboxId}
import org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY
@@ -90,6 +90,12 @@ case class MailboxChangeListener @Inject() (@Named(InjectionKeys.JMAP) eventBus:
getSharees(mailboxId, username)
.flatMapMany(sharees =>
SFlux(emailChangeFactory.fromExpunged(expunged, now, sharees.map(_.getIdentifier).map(Username.of).asJava)))
+ case subscribed: MailboxEvents.MailboxSubscribedEvent =>
+ getSharees(mailboxId, username)
+ .flatMapIterable(sharees => mailboxChangeFactory.fromMailboxSubscribed(sharees.asJava, subscribed, now).asScala)
+ case unSubscribed: MailboxEvents.MailboxUnsubscribedEvent =>
+ getSharees(mailboxId, username)
+ .flatMapIterable(sharees => mailboxChangeFactory.fromMailboxUnSubscribed(sharees.asJava, unSubscribed, now).asScala)
}
}
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
index 26f9309d3e..6c02539e90 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
@@ -19,10 +19,6 @@
package org.apache.james.jmap.change
-import java.time.{Clock, ZonedDateTime}
-import java.util
-
-import javax.mail.Flags
import org.apache.james.events.delivery.InVmEventDelivery
import org.apache.james.events.{Event, EventBus, EventListener, Group, InVMEventBus, MemoryEventDeadLetters, Registration, RegistrationKey, RetryBackoffConfiguration}
import org.apache.james.jmap.api.change.{EmailChange, EmailChangeRepository, Limit, MailboxAndEmailChange, MailboxChange, MailboxChangeRepository, State}
@@ -33,13 +29,17 @@ import org.apache.james.mailbox.MessageManager.{AppendCommand, AppendResult, Fla
import org.apache.james.mailbox.fixture.MailboxFixture.{ALICE, BOB}
import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources
import org.apache.james.mailbox.model.{MailboxACL, MailboxId, MailboxPath, MessageRange, TestId, TestMessageId}
-import org.apache.james.mailbox.{MailboxManager, MailboxSessionUtil, MessageManager}
+import org.apache.james.mailbox.store.StoreSubscriptionManager
+import org.apache.james.mailbox.{MailboxManager, MailboxSessionUtil, MessageManager, SubscriptionManager}
import org.apache.james.metrics.tests.RecordingMetricFactory
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.{BeforeEach, Nested, Test}
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono
+import java.time.{Clock, ZonedDateTime}
+import java.util
+import javax.mail.Flags
import scala.jdk.CollectionConverters._
import scala.jdk.OptionConverters._
@@ -58,6 +58,7 @@ class MailboxChangeListenerTest {
var stateFactory: State.Factory = _
var listener: MailboxChangeListener = _
var clock: Clock = _
+ var subscriptionManager: SubscriptionManager = _
@BeforeEach
def setUp: Unit = {
@@ -84,6 +85,10 @@ class MailboxChangeListenerTest {
override def reDeliver(group: Group, event: Event): Mono[Void] = Mono.empty()
}
+
+ subscriptionManager = new StoreSubscriptionManager(resources.getMailboxManager.getMapperFactory,
+ resources.getMailboxManager.getMapperFactory,
+ resources.getEventBus)
listener = MailboxChangeListener(eventBus, mailboxChangeRepository, mailboxChangeFactory, emailChangeRepository, emailChangeFactory, mailboxManager, clock)
resources.getEventBus.register(listener)
}
@@ -252,6 +257,36 @@ class MailboxChangeListenerTest {
assertThat(mailboxChangeRepository.getSinceState(ACCOUNT_ID, state, None.toJava).block().getDestroyed)
.containsExactly(inboxId)
}
+
+ @Test
+ def subscribeMailboxShouldStoreMailboxSubscribedEvent(): Unit = {
+ val mailboxSession = MailboxSessionUtil.create(BOB)
+ val path = MailboxPath.forUser(BOB, "test")
+ val inboxId: MailboxId = mailboxManager.createMailbox(path, mailboxSession).get
+
+ val state = stateFactory.generate()
+ mailboxChangeRepository.save(MailboxChange.builder().accountId(ACCOUNT_ID).state(state).date(ZonedDateTime.now).isCountChange(false).created(List[MailboxId](TestId.of(0)).asJava).build).block()
+
+ subscriptionManager.subscribe(mailboxSession, path)
+ Thread.sleep(200)
+ assertThat(mailboxChangeRepository.getSinceState(ACCOUNT_ID, state, None.toJava).block().getUpdated)
+ .containsExactly(inboxId)
+ }
+
+ @Test
+ def unSubscribeMailboxShouldStoreMailboxUnSubscribedEvent(): Unit = {
+ val mailboxSession = MailboxSessionUtil.create(BOB)
+ val path = MailboxPath.forUser(BOB, "test")
+ val inboxId: MailboxId = mailboxManager.createMailbox(path, mailboxSession).get
+
+ val state = stateFactory.generate()
+ mailboxChangeRepository.save(MailboxChange.builder().accountId(ACCOUNT_ID).state(state).date(ZonedDateTime.now).isCountChange(false).created(List[MailboxId](TestId.of(0)).asJava).build).block()
+
+ subscriptionManager.unsubscribe(mailboxSession, path)
+ Thread.sleep(200)
+ assertThat(mailboxChangeRepository.getSinceState(ACCOUNT_ID, state, None.toJava).block().getUpdated)
+ .containsExactly(inboxId)
+ }
}
@Nested
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/MailboxesProvisionerTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/MailboxesProvisionerTest.scala
index c9d8400043..688cbce007 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/MailboxesProvisionerTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/MailboxesProvisionerTest.scala
@@ -51,7 +51,7 @@ class MailboxesProvisionerTest {
def setup(): Unit = {
session = MailboxSessionUtil.create(USERNAME)
mailboxManager = InMemoryIntegrationResources.defaultResources.getMailboxManager
- subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory)
+ subscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory, mailboxManager.getMapperFactory, mailboxManager.getEventBus)
testee = new MailboxesProvisioner(mailboxManager, subscriptionManager, new RecordingMetricFactory)
}
diff --git a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
index 5973e676a9..0bdb91e8a0 100644
--- a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
+++ b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
@@ -154,7 +154,9 @@ class IMAPServerTest {
DefaultImapProcessorFactory.createXListSupportingProcessor(
memoryIntegrationResources.getMailboxManager(),
memoryIntegrationResources.getEventBus(),
- new StoreSubscriptionManager(memoryIntegrationResources.getMailboxManager().getMapperFactory()),
+ new StoreSubscriptionManager(memoryIntegrationResources.getMailboxManager().getMapperFactory(),
+ memoryIntegrationResources.getMailboxManager().getMapperFactory(),
+ memoryIntegrationResources.getMailboxManager().getEventBus()),
null,
memoryIntegrationResources.getQuotaManager(),
memoryIntegrationResources.getQuotaRootResolver(),
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/SubscribeAllRequestToTaskTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/SubscribeAllRequestToTaskTest.java
index 09bee339bb..414f7bdbb0 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/SubscribeAllRequestToTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/SubscribeAllRequestToTaskTest.java
@@ -99,7 +99,9 @@ class SubscribeAllRequestToTaskTest {
void setUp() throws Exception {
InMemoryIntegrationResources inMemoryIntegrationResources = InMemoryIntegrationResources.defaultResources();
mailboxManager = inMemoryIntegrationResources.getMailboxManager();
- subscriptionManager = new StoreSubscriptionManager(inMemoryIntegrationResources.getMailboxManager().getMapperFactory());
+ subscriptionManager = new StoreSubscriptionManager(inMemoryIntegrationResources.getMailboxManager().getMapperFactory(),
+ inMemoryIntegrationResources.getMailboxManager().getMapperFactory(),
+ inMemoryIntegrationResources.getMailboxManager().getEventBus());
DomainList domainList = mock(DomainList.class);
Mockito.when(domainList.containsDomain(any())).thenReturn(true);
MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org