Skip to content

Commit

Permalink
Move event attendance mail sending logic to StandaloneEventAttendance…
Browse files Browse the repository at this point in the history
…Repository
  • Loading branch information
HoussemNasri committed Dec 19, 2024
1 parent 73ffe99 commit 5a58fc5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 18 deletions.
5 changes: 5 additions & 0 deletions tmail-backend/jmap/extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@
<artifactId>uuid-creator</artifactId>
<version>${uuid-creator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>james-server-queue-memory</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package com.linagora.tmail.james.jmap;

import java.util.Optional;

import org.apache.james.core.Username;
import org.apache.james.jmap.mail.BlobIds;
import org.apache.james.mailbox.model.MessageId;
import org.reactivestreams.Publisher;

interface EventAttendanceRepository {
import com.linagora.tmail.james.jmap.model.CalendarEventReplyResults;
import com.linagora.tmail.james.jmap.model.LanguageLocation;

public interface EventAttendanceRepository {
Publisher<AttendanceStatus> getAttendanceStatus(Username username, MessageId messageId);

Publisher<Void> setAttendanceStatus(Username username, MessageId messageId, AttendanceStatus attendanceStatus);
Publisher<CalendarEventReplyResults> setAttendanceStatus(Username username, AttendanceStatus attendanceStatus,
BlobIds eventBlobIds,
Optional<LanguageLocation> maybePreferredLanguage);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.linagora.tmail.james.jmap;

import java.util.List;
import java.util.Optional;

import jakarta.inject.Inject;
import jakarta.mail.Flags;

import org.apache.james.core.Username;
import org.apache.james.jmap.core.AccountId;
import org.apache.james.jmap.mail.BlobIds;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageIdManager;
import org.apache.james.mailbox.MessageManager;
Expand All @@ -18,19 +21,32 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.linagora.tmail.james.jmap.method.CalendarEventReplyPerformer;
import com.linagora.tmail.james.jmap.model.CalendarEventReplyRequest;
import com.linagora.tmail.james.jmap.model.CalendarEventReplyResults;
import com.linagora.tmail.james.jmap.model.LanguageLocation;

import net.fortuna.ical4j.model.parameter.PartStat;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import scala.collection.JavaConverters;
import scala.compat.java8.OptionConverters;

public class StandaloneEventAttendanceRepository implements EventAttendanceRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(StandaloneEventAttendanceRepository.class);

private final MessageIdManager messageIdManager;
private final SessionProvider sessionProvider;
private final CalendarEventReplyPerformer calendarEventReplyPerformer;
private final MessageId.Factory messageIdFactory;

@Inject
public StandaloneEventAttendanceRepository(MessageIdManager messageIdManager, SessionProvider sessionProvider) {
public StandaloneEventAttendanceRepository(MessageIdManager messageIdManager, SessionProvider sessionProvider,
CalendarEventReplyPerformer calendarEventReplyPerformer, MessageId.Factory messageIdFactory) {
this.messageIdManager = messageIdManager;
this.sessionProvider = sessionProvider;
this.calendarEventReplyPerformer = calendarEventReplyPerformer;
this.messageIdFactory = messageIdFactory;
}

@Override
Expand All @@ -52,15 +68,66 @@ private Mono<AttendanceStatus> handleMissingEventAttendanceFlag(MessageId messag
}

@Override
public Publisher<Void> setAttendanceStatus(Username username, MessageId messageId,
AttendanceStatus attendanceStatus) {
public Publisher<CalendarEventReplyResults> setAttendanceStatus(Username username, AttendanceStatus attendanceStatus,
BlobIds eventBlobIds,
Optional<LanguageLocation> maybePreferredLanguage) {
MailboxSession systemMailboxSession = sessionProvider.createSystemSession(username);

return Flux.from(messageIdManager.getMessagesReactive(List.of(messageId), FetchGroup.MINIMAL, systemMailboxSession))
.map(MessageResult::getMailboxId)
return getEnclosingMessageId(eventBlobIds).flatMapMany(messageId ->
Flux.from(messageIdManager.getMessagesReactive(List.of(messageId), FetchGroup.MINIMAL, systemMailboxSession))
.map(MessageResult::getMailboxId)
.collectList()
.flatMap(mailboxIds ->
updateEventAttendanceFlagsInMailboxes(
messageId,
attendanceStatus,
systemMailboxSession,
mailboxIds)))
.flatMap(ignored -> tryToSendReplyEmail(username, eventBlobIds, maybePreferredLanguage, systemMailboxSession));
}

private Mono<CalendarEventReplyResults> tryToSendReplyEmail(Username username, BlobIds eventBlobIds, Optional<LanguageLocation> maybePreferredLanguage, MailboxSession systemMailboxSession) {
return Mono.just(AccountId.from(username))
.flatMap(accountIdEither ->
accountIdEither.fold(
exception -> Mono.error(new IllegalArgumentException(
"Failed to get account id from username: " + username, exception)),
accountId -> doSendReplyEmail(accountId, systemMailboxSession, eventBlobIds,
maybePreferredLanguage)));
}

private Mono<MessageId> getEnclosingMessageId(BlobIds blobIds) {
return Flux.fromIterable(JavaConverters.seqAsJavaList(blobIds.value()))
.flatMap(blobId -> extractMessageId(blobId.value()))
.distinct()
.log()
.collectList()
.flatMap(mailboxIds ->
updateEventAttendanceFlagsInMailboxes(messageId, attendanceStatus, systemMailboxSession, mailboxIds));
.handle((enclosingMessageIds, sink) -> {
if (enclosingMessageIds.size() != 1) {
sink.error(new IllegalStateException("Expected a single enclosing message for all calendar event blobIds, got: " + enclosingMessageIds));
} else {
sink.next(enclosingMessageIds.getFirst());
}
});
}

private Mono<MessageId> extractMessageId(String blobId) {
return Mono.just(blobId)
.map(blobIdParam -> {
int underscoreIndex = blobId.indexOf('_');
String messageId = blobId.substring(0, underscoreIndex);
return messageIdFactory.fromString(messageId);
});
}

private Mono<CalendarEventReplyResults> doSendReplyEmail(AccountId accountId, MailboxSession session, BlobIds eventBlobIds, Optional<LanguageLocation> maybePreferredLanguage) {
return Mono.from(calendarEventReplyPerformer.process(
new CalendarEventReplyRequest(
accountId,
eventBlobIds,
OptionConverters.toScala(maybePreferredLanguage)),
session,
PartStat.ACCEPTED));
}

private Mono<Void> updateEventAttendanceFlagsInMailboxes(MessageId messageId, AttendanceStatus attendanceStatus,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.linagora.tmail.james.jmap

import java.io.FileNotFoundException

import com.google.inject.name.Named
import com.google.inject.{AbstractModule, Provides, Singleton}
import com.linagora.tmail.james.jmap.method.CalendarEventReplyPerformer
import org.apache.commons.configuration2.{Configuration, PropertiesConfiguration}
import org.apache.james.mailbox.model.MessageId
import org.apache.james.mailbox.{MessageIdManager, SessionProvider}
import org.apache.james.utils.PropertiesProvider

import scala.util.Try
Expand All @@ -27,4 +29,8 @@ class TMailJMAPModule extends AbstractModule {

@Provides
def providePublicAssetTotalSizeLimit(jmapExtensionConfiguration: JMAPExtensionConfiguration): PublicAssetTotalSizeLimit = jmapExtensionConfiguration.publicAssetTotalSizeLimit

@Provides
def provideEventAttendanceRepository(messageIdManager: MessageIdManager, sessionProvider: SessionProvider, calendarEventReplyPerformer: CalendarEventReplyPerformer, messageIdFactory: MessageId.Factory): EventAttendanceRepository =
new StandaloneEventAttendanceRepository(messageIdManager, sessionProvider, calendarEventReplyPerformer, messageIdFactory)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package com.linagora.tmail.james.jmap.method
import com.linagora.tmail.james.jmap.json.CalendarEventReplySerializer
import com.linagora.tmail.james.jmap.method.CapabilityIdentifier.LINAGORA_CALENDAR
import com.linagora.tmail.james.jmap.model.{CalendarEventReplyAcceptedResponse, CalendarEventReplyRequest}
import com.linagora.tmail.james.jmap.{AttendanceStatus, EventAttendanceRepository}
import eu.timepit.refined.auto._
import jakarta.inject.Inject
import net.fortuna.ical4j.model.parameter.PartStat
import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_CORE}
import org.apache.james.jmap.core.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.core.{Invocation, SessionTranslator}
Expand All @@ -16,8 +16,11 @@ import org.apache.james.mailbox.MailboxSession
import org.apache.james.metrics.api.MetricFactory
import org.reactivestreams.Publisher
import play.api.libs.json.JsObject
import reactor.core.publisher.Mono

class CalendarEventAcceptMethod @Inject()(val calendarEventReplyPerformer: CalendarEventReplyPerformer,
import scala.compat.java8.OptionConverters

class CalendarEventAcceptMethod @Inject()(val eventAttendanceRepository: EventAttendanceRepository,
val metricFactory: MetricFactory,
val sessionTranslator: SessionTranslator,
val sessionSupplier: SessionSupplier,
Expand All @@ -37,12 +40,12 @@ class CalendarEventAcceptMethod @Inject()(val calendarEventReplyPerformer: Calen
invocation: InvocationWithContext,
mailboxSession: MailboxSession,
request: CalendarEventReplyRequest): Publisher[InvocationWithContext] = {
calendarEventReplyPerformer.process(request, mailboxSession, PartStat.ACCEPTED)
return Mono.from(eventAttendanceRepository.setAttendanceStatus(mailboxSession.getUser, AttendanceStatus.Accepted, request.blobIds, OptionConverters.toJava(request.language)))
.map(result => CalendarEventReplyAcceptedResponse.from(request.accountId, result))
.map(response => Invocation(
methodName,
Arguments(CalendarEventReplySerializer.serialize(response).as[JsObject]),
invocation.invocation.methodCallId))
.map(InvocationWithContext(_, invocation.processingContext))
.map(response => Invocation(
methodName,
Arguments(CalendarEventReplySerializer.serialize(response).as[JsObject]),
invocation.invocation.methodCallId))
.map(InvocationWithContext(_, invocation.processingContext))
}
}

0 comments on commit 5a58fc5

Please sign in to comment.