From 0df173e10e87e566a8555cf58bafa39fdae02e60 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Wed, 15 Jan 2025 14:11:58 +0100 Subject: [PATCH] Implement getUserParticipationStatus --- .../tmail/james/app/DistributedServer.java | 2 +- .../tmail/james/app/MemoryServer.java | 2 +- .../james/jmap/model/CalendarEventParse.scala | 2 +- .../tmail-third-party/openpaas/pom.xml | 4 + .../com/linagora/tmail/OpenPaasModule.java | 10 +- .../OpenPaasModuleChooserConfiguration.java | 4 +- .../linagora/tmail/carddav/CardDavClient.java | 110 --------- ...nfiguration.java => DavConfiguration.java} | 14 +- .../configuration/OpenPaasConfiguration.java | 6 +- .../CardDavUtils.java} | 17 +- .../com/linagora/tmail/dav/DavClient.java | 232 ++++++++++++++++++ .../DavClientException.java} | 8 +- .../CardDavCreationObjectRequest.java | 2 +- .../GetCalendarByEventIdRequestBody.java | 43 ++++ .../linagora/tmail/dav/xml/CalendarData.java | 38 +++ .../com/linagora/tmail/dav/xml/DavHref.java | 39 +++ .../tmail/dav/xml/DavMultistatus.java | 46 ++++ .../com/linagora/tmail/dav/xml/DavProp.java | 39 +++ .../linagora/tmail/dav/xml/DavPropstat.java | 44 ++++ .../linagora/tmail/dav/xml/DavResponse.java | 44 ++++ .../com/linagora/tmail/dav/xml/DavStatus.java | 38 +++ .../com/linagora/tmail/dav/xml/XMLUtil.java | 49 ++++ .../tmail/mailet/CardDavCollectedContact.java | 18 +- ...ardDavCollectedContactIntegrationTest.java | 22 +- .../CardDavConfigurationTest.java | 10 +- .../CardDavCreationObjectRequestTest.java | 4 +- .../DavClientTest.java} | 18 +- .../DavServerExtension.java} | 10 +- 28 files changed, 693 insertions(+), 182 deletions(-) delete mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClient.java rename tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/{CardDavConfiguration.java => DavConfiguration.java} (87%) rename tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/{carddav/CardDavCreationFactory.java => dav/CardDavUtils.java} (74%) create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClient.java rename tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/{carddav/CardDavClientException.java => dav/DavClientException.java} (85%) rename tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/{carddav => dav/request}/CardDavCreationObjectRequest.java (98%) create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/GetCalendarByEventIdRequestBody.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/CalendarData.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavHref.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavMultistatus.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavProp.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavPropstat.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavResponse.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavStatus.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/XMLUtil.java rename tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/{carddav => dav}/CardDavCreationObjectRequestTest.java (96%) rename tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/{carddav/CardDavClientTest.java => dav/DavClientTest.java} (91%) rename tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/{carddav/CardDavServerExtension.java => dav/DavServerExtension.java} (95%) diff --git a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java index aa83c76f39..4741a9b025 100644 --- a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java +++ b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java @@ -493,7 +493,7 @@ private static List chooseOpenPaasModule(OpenPaasModuleChooserConfigurat if (openPaasModuleChooserConfiguration.enabled()) { ImmutableList.Builder moduleBuilder = ImmutableList.builder().add(new OpenPaasModule()); if (openPaasModuleChooserConfiguration.cardDavCollectedContactEnabled()) { - moduleBuilder.add(new OpenPaasModule.CardDavModule()); + moduleBuilder.add(new OpenPaasModule.DavModule()); } if (openPaasModuleChooserConfiguration.contactsConsumerEnabled()) { moduleBuilder.add(new OpenPaasContactsConsumerModule()); diff --git a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java index 127e83bc9f..4a3181813a 100644 --- a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java +++ b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java @@ -264,7 +264,7 @@ private static List chooseOpenPaas(OpenPaasModuleChooserConfiguration mo ImmutableList.Builder moduleBuilder = ImmutableList.builder().add(new OpenPaasModule()); if (moduleChooserConfiguration.cardDavCollectedContactEnabled()) { - moduleBuilder.add(new OpenPaasModule.CardDavModule()); + moduleBuilder.add(new OpenPaasModule.DavModule()); } if (moduleChooserConfiguration.contactsConsumerEnabled()) { moduleBuilder.add(Modules.override(new OpenPaasContactsConsumerModule()) diff --git a/tmail-backend/jmap/extensions/src/main/scala/com/linagora/tmail/james/jmap/model/CalendarEventParse.scala b/tmail-backend/jmap/extensions/src/main/scala/com/linagora/tmail/james/jmap/model/CalendarEventParse.scala index 112297e743..fc8bc00cc8 100644 --- a/tmail-backend/jmap/extensions/src/main/scala/com/linagora/tmail/james/jmap/model/CalendarEventParse.scala +++ b/tmail-backend/jmap/extensions/src/main/scala/com/linagora/tmail/james/jmap/model/CalendarEventParse.scala @@ -311,7 +311,7 @@ object CalendarAttendeeParticipationStatus { .map(_.getValue) .map(CalendarAttendeeParticipationStatus(_)) } -case class CalendarAttendeeParticipationStatus(value: String) extends AnyVal +case class CalendarAttendeeParticipationStatus(value: String) object CalendarAttendeeExpectReply { def from(attendee: Attendee): Option[CalendarAttendeeExpectReply] = Option(attendee.getParameter("RSVP").asInstanceOf[Parameter]) diff --git a/tmail-backend/tmail-third-party/openpaas/pom.xml b/tmail-backend/tmail-third-party/openpaas/pom.xml index 9b6584fce8..c145f5a4ab 100644 --- a/tmail-backend/tmail-third-party/openpaas/pom.xml +++ b/tmail-backend/tmail-third-party/openpaas/pom.xml @@ -37,6 +37,10 @@ ${james.groupId} apache-james-backends-rabbitmq + + ${project.groupId} + jmap-extensions + ${james.groupId} apache-james-backends-rabbitmq diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java index 347c6b522a..e7a7c7de1d 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java @@ -33,8 +33,8 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.linagora.tmail.api.OpenPaasRestClient; -import com.linagora.tmail.carddav.CardDavClient; import com.linagora.tmail.configuration.OpenPaasConfiguration; +import com.linagora.tmail.dav.DavClient; public class OpenPaasModule extends AbstractModule { private static final Logger LOGGER = LoggerFactory.getLogger(OpenPaasModule.class); @@ -65,14 +65,14 @@ public OpenPaasRestClient provideOpenPaasRestCLient(OpenPaasConfiguration openPa return new OpenPaasRestClient(openPaasConfiguration); } - public static class CardDavModule extends AbstractModule { + public static class DavModule extends AbstractModule { @Provides @Singleton - public CardDavClient provideCardDavClient(OpenPaasConfiguration openPaasConfiguration) { + public DavClient provideDavClient(OpenPaasConfiguration openPaasConfiguration) { Preconditions.checkArgument(openPaasConfiguration.cardDavConfiguration().isPresent(), - "OpenPaasConfiguration should have a carddav configuration"); - return new CardDavClient.OpenpaasCardDavClient(openPaasConfiguration.cardDavConfiguration().get()); + "OpenPaasConfiguration should have dav configuration"); + return new DavClient(openPaasConfiguration.cardDavConfiguration().get()); } } } diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java index 4d961aba1d..83746615e6 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java @@ -26,7 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.linagora.tmail.configuration.CardDavConfiguration; +import com.linagora.tmail.configuration.DavConfiguration; import com.linagora.tmail.configuration.OpenPaasConfiguration; public record OpenPaasModuleChooserConfiguration(boolean enabled, @@ -43,7 +43,7 @@ public static OpenPaasModuleChooserConfiguration parse(PropertiesProvider proper try { Configuration configuration = propertiesProvider.getConfiguration("openpaas"); boolean contactsConsumerEnabled = OpenPaasConfiguration.isConfiguredContactConsumer(configuration); - boolean cardDavCollectedContactEnabled = CardDavConfiguration.isConfigured(configuration); + boolean cardDavCollectedContactEnabled = DavConfiguration.isConfigured(configuration); LOGGER.info("OpenPaas module is turned on. Contacts consumer is enabled: {}, CardDav is enabled: {}", contactsConsumerEnabled, cardDavCollectedContactEnabled); return new OpenPaasModuleChooserConfiguration(ENABLED, cardDavCollectedContactEnabled, contactsConsumerEnabled); diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClient.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClient.java deleted file mode 100644 index afb5ddc9ff..0000000000 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClient.java +++ /dev/null @@ -1,110 +0,0 @@ -/******************************************************************** - * As a subpart of Twake Mail, this file is edited by Linagora. * - * * - * https://twake-mail.com/ * - * https://linagora.com * - * * - * This file is subject to The Affero Gnu Public License * - * version 3. * - * * - * https://www.gnu.org/licenses/agpl-3.0.en.html * - * * - * This program is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * - * PURPOSE. See the GNU Affero General Public License for * - * more details. * - ********************************************************************/ - -package com.linagora.tmail.carddav; - -import java.time.Duration; -import java.util.function.Function; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; -import com.linagora.tmail.HttpUtils; -import com.linagora.tmail.configuration.CardDavConfiguration; - -import io.netty.buffer.Unpooled; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import reactor.core.publisher.Mono; -import reactor.netty.http.client.HttpClient; - -public interface CardDavClient { - - Mono existsCollectedContact(String username, String userId, String collectedId); - - Mono createCollectedContact(String username, String userId, CardDavCreationObjectRequest creationObjectRequest); - - class OpenpaasCardDavClient implements CardDavClient { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenpaasCardDavClient.class); - private static final Duration RESPONSE_TIMEOUT_DEFAULT = Duration.ofSeconds(10); - private static final String COLLECTED_ADDRESS_BOOK_PATH = "/addressbooks/%s/collected/%s.vcf"; - - private final HttpClient client; - - private final Function adminCredentialWithDelegatedFunction; - - public OpenpaasCardDavClient(CardDavConfiguration cardDavConfiguration) { - this.client = HttpClient.create() - .baseUrl(cardDavConfiguration.baseUrl().toString()) - .headers(headers -> headers.add(HttpHeaderNames.ACCEPT, "application/vcard+json")) - .responseTimeout(cardDavConfiguration.responseTimeout().orElse(RESPONSE_TIMEOUT_DEFAULT)); - - cardDavConfiguration.trustAllSslCerts().ifPresent(trustAllSslCerts -> - client.secure(sslContextSpec -> sslContextSpec.sslContext( - SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)))); - - this.adminCredentialWithDelegatedFunction = openPaasUsername -> new UsernamePasswordCredentials(cardDavConfiguration.adminCredential().getUserName() + "&" + openPaasUsername, - cardDavConfiguration.adminCredential().getPassword()); - } - - @Override - public Mono existsCollectedContact(String username, String userId, String collectedId) { - Preconditions.checkArgument(StringUtils.isNotEmpty(userId), "OpenPaas user id should not be empty"); - Preconditions.checkArgument(StringUtils.isNotEmpty(collectedId), "Collected id should not be empty"); - - return client - .headers(headers -> headers.add(HttpHeaderNames.AUTHORIZATION, HttpUtils.createBasicAuthenticationToken(adminCredentialWithDelegatedFunction.apply(username)))) - .get() - .uri(String.format(COLLECTED_ADDRESS_BOOK_PATH, userId, collectedId)) - .responseSingle((response, byteBufMono) -> switch (response.status().code()) { - case 200 -> Mono.just(true); - case 404 -> Mono.just(false); - default -> - Mono.error(new CardDavClientException("Unexpected status code: " + response.status().code() - + " when checking contact exists for openPaasUserId: " + userId + " and collectedId: " + collectedId)); - }); - } - - @Override - public Mono createCollectedContact(String username, String userId, CardDavCreationObjectRequest creationObjectRequest) { - return client - .headers(headers -> { - headers.add(HttpHeaderNames.CONTENT_TYPE, "text/vcard"); - headers.add(HttpHeaderNames.AUTHORIZATION, HttpUtils.createBasicAuthenticationToken(adminCredentialWithDelegatedFunction.apply(username))); - }) - .put() - .uri(String.format(COLLECTED_ADDRESS_BOOK_PATH, userId, creationObjectRequest.uid())) - .send(Mono.just(Unpooled.wrappedBuffer(creationObjectRequest.toVCard().getBytes()))) - .responseSingle((response, byteBufMono) -> switch (response.status().code()) { - case 201 -> Mono.empty(); - case 204 -> { - LOGGER.info("Contact for user {} and collected id {} already exists", userId, creationObjectRequest.uid()); - yield Mono.empty(); - } - default -> - Mono.error(new CardDavClientException("Unexpected status code: " + response.status().code() - + " when creating contact for user: " + userId + " and collected id: " + creationObjectRequest.uid())); - }); - } - } -} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/CardDavConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/DavConfiguration.java similarity index 87% rename from tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/CardDavConfiguration.java rename to tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/DavConfiguration.java index ddb9226253..28ded12cc7 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/CardDavConfiguration.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/DavConfiguration.java @@ -28,10 +28,10 @@ import com.google.common.base.Preconditions; -public record CardDavConfiguration(UsernamePasswordCredentials adminCredential, - URI baseUrl, - Optional trustAllSslCerts, - Optional responseTimeout) { +public record DavConfiguration(UsernamePasswordCredentials adminCredential, + URI baseUrl, + Optional trustAllSslCerts, + Optional responseTimeout) { static final boolean CLIENT_TRUST_ALL_SSL_CERTS_DISABLED = false; static final String CARD_DAV_API_URI_PROPERTY = "carddav.api.uri"; static final String CARD_DAV_ADMIN_USER_PROPERTY = "carddav.admin.user"; @@ -39,14 +39,14 @@ public record CardDavConfiguration(UsernamePasswordCredentials adminCredential, static final String CARD_DAV_REST_CLIENT_TRUST_ALL_SSL_CERTS_PROPERTY = "carddav.rest.client.trust.all.ssl.certs"; static final String CARD_DAV_REST_CLIENT_RESPONSE_TIMEOUT_PROPERTY = "carddav.rest.client.response.timeout"; - public static Optional maybeFrom(Configuration configuration) { + public static Optional maybeFrom(Configuration configuration) { if (isConfigured(configuration)) { return Optional.of(from(configuration)); } return Optional.empty(); } - public static CardDavConfiguration from(Configuration configuration) { + public static DavConfiguration from(Configuration configuration) { String adminUser = configuration.getString(CARD_DAV_ADMIN_USER_PROPERTY, null); String adminPassword = configuration.getString(CARD_DAV_ADMIN_PASSWORD_PROPERTY, null); @@ -64,7 +64,7 @@ public static CardDavConfiguration from(Configuration configuration) { Preconditions.checkArgument(durationAsMilliseconds > 0, "Response timeout should not be negative"); return Duration.ofMillis(durationAsMilliseconds); }); - return new CardDavConfiguration(adminCredential, baseUrl, trustAllSslCerts, responseTimeout); + return new DavConfiguration(adminCredential, baseUrl, trustAllSslCerts, responseTimeout); } public static boolean isConfigured(Configuration configuration) { diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java index c7e7888717..f205370391 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java @@ -36,7 +36,7 @@ public record OpenPaasConfiguration(URI apirUri, String adminPassword, boolean trustAllSslCerts, Optional contactConsumerConfiguration, - Optional cardDavConfiguration) { + Optional cardDavConfiguration) { public record ContactConsumerConfiguration(List amqpUri, boolean quorumQueuesBypass) { @@ -46,7 +46,7 @@ public OpenPaasConfiguration(URI apirUri, String adminUsername, String adminPass this(apirUri, adminUsername, adminPassword, trustAllSslCerts, Optional.of(contactConsumerConfiguration), Optional.empty()); } - public OpenPaasConfiguration(URI apirUri, String adminUsername, String adminPassword, boolean trustAllSslCerts, CardDavConfiguration cardDavConfiguration) { + public OpenPaasConfiguration(URI apirUri, String adminUsername, String adminPassword, boolean trustAllSslCerts, DavConfiguration cardDavConfiguration) { this(apirUri, adminUsername, adminPassword, trustAllSslCerts, Optional.empty(), Optional.of(cardDavConfiguration)); } @@ -69,7 +69,7 @@ public static OpenPaasConfiguration from(Configuration configuration) { Optional contactConsumerConfiguration = readRabbitMqUri(configuration) .map(amqpUri -> new ContactConsumerConfiguration(amqpUri, readQuorumQueuesBypass(configuration))); - Optional cardDavConfiguration = CardDavConfiguration.maybeFrom(configuration); + Optional cardDavConfiguration = DavConfiguration.maybeFrom(configuration); return new OpenPaasConfiguration(openPaasApiUri, adminUser, adminPassword, trustAllSslCerts, contactConsumerConfiguration, cardDavConfiguration); } diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationFactory.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/CardDavUtils.java similarity index 74% rename from tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationFactory.java rename to tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/CardDavUtils.java index 8727208eee..bba0b0ccae 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationFactory.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/CardDavUtils.java @@ -16,7 +16,7 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav; import java.nio.charset.StandardCharsets; import java.util.List; @@ -25,20 +25,21 @@ import org.apache.james.core.MailAddress; import com.google.common.hash.Hashing; +import com.linagora.tmail.dav.request.CardDavCreationObjectRequest; import ezvcard.parameter.EmailType; -public class CardDavCreationFactory { +public class CardDavUtils { private static final String VERSION = "4.0"; - private static final EmailType EMAIL_TYPE_DEFAULT = EmailType.WORK; + private static final EmailType DEFAULT_EMAIL_TYPE = EmailType.WORK; - public static CardDavCreationObjectRequest create(Optional fullName, MailAddress email) { - CardDavCreationObjectRequest.Email emailObject = new CardDavCreationObjectRequest.Email(List.of(EMAIL_TYPE_DEFAULT), email); - return new CardDavCreationObjectRequest(VERSION, createContactUid(email), fullName, Optional.empty(), emailObject); + public static CardDavCreationObjectRequest createObjectCreationRequest(Optional maybeFullName, MailAddress email) { + CardDavCreationObjectRequest.Email emailObject = new CardDavCreationObjectRequest.Email(List.of(DEFAULT_EMAIL_TYPE), email); + return new CardDavCreationObjectRequest(VERSION, createContactUid(email), maybeFullName, Optional.empty(), emailObject); } - public static CardDavCreationObjectRequest create(MailAddress email) { - return create(Optional.empty(), email); + public static CardDavCreationObjectRequest createObjectCreationRequest(MailAddress email) { + return createObjectCreationRequest(Optional.empty(), email); } public static String createContactUid(MailAddress email) { diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClient.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClient.java new file mode 100644 index 0000000000..3ccfc171cc --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClient.java @@ -0,0 +1,232 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.regex.Pattern; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.linagora.tmail.HttpUtils; +import com.linagora.tmail.configuration.DavConfiguration; +import com.linagora.tmail.dav.request.CardDavCreationObjectRequest; +import com.linagora.tmail.dav.request.GetCalendarByEventIdRequestBody; +import com.linagora.tmail.dav.xml.DavMultistatus; +import com.linagora.tmail.dav.xml.DavResponse; +import com.linagora.tmail.dav.xml.XMLUtil; +import com.linagora.tmail.james.jmap.model.CalendarAttendeeField; +import com.linagora.tmail.james.jmap.model.CalendarAttendeeParticipationStatus; +import com.linagora.tmail.james.jmap.model.CalendarEventParsed; +import com.linagora.tmail.james.jmap.model.CalendarParticipantsField; + +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import net.fortuna.ical4j.model.Calendar; +import net.fortuna.ical4j.model.component.VEvent; +import net.fortuna.ical4j.model.parameter.PartStat; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.netty.http.client.HttpClient; +import scala.compat.java8.OptionConverters; + +public class DavClient { + private static final Logger LOGGER = LoggerFactory.getLogger(DavClient.class); + + private static final Duration RESPONSE_TIMEOUT_DEFAULT = Duration.ofSeconds(10); + private static final String COLLECTED_ADDRESS_BOOK_PATH = "/addressbooks/%s/collected/%s.vcf"; + + private final HttpClient client; + private final DavConfiguration davConfiguration; + private final Function + adminCredentialWithDelegatedFunction; + + public DavClient(DavConfiguration davConfiguration) { + this.client = HttpClient.create() + .baseUrl(davConfiguration.baseUrl().toString()) + .responseTimeout(davConfiguration.responseTimeout().orElse(RESPONSE_TIMEOUT_DEFAULT)); + this.davConfiguration = davConfiguration; + + davConfiguration.trustAllSslCerts().ifPresent(trustAllSslCerts -> + client.secure(sslContextSpec -> sslContextSpec.sslContext( + SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)))); + + this.adminCredentialWithDelegatedFunction = openPaasUsername -> new UsernamePasswordCredentials(davConfiguration.adminCredential().getUserName() + "&" + openPaasUsername, + davConfiguration.adminCredential().getPassword()); + } + + public Mono existsCollectedContact(String username, String userId, + String collectedId) { + Preconditions.checkArgument(StringUtils.isNotEmpty(userId), "OpenPaas user id should not be empty"); + Preconditions.checkArgument(StringUtils.isNotEmpty(collectedId), "Collected id should not be empty"); + + return client + .headers(headers -> headers.add(HttpHeaderNames.ACCEPT, "application/vcard+json")) + .headers(headers -> headers.add(HttpHeaderNames.AUTHORIZATION, HttpUtils.createBasicAuthenticationToken(adminCredentialWithDelegatedFunction.apply(username)))) + .get() + .uri(String.format(COLLECTED_ADDRESS_BOOK_PATH, userId, collectedId)) + .responseSingle((response, byteBufMono) -> switch (response.status().code()) { + case 200 -> Mono.just(true); + case 404 -> Mono.just(false); + default -> + Mono.error(new DavClientException("Unexpected status code: " + response.status().code() + + " when checking contact exists for openPaasUserId: " + userId + " and collectedId: " + collectedId)); + }); + } + + public Mono createCollectedContact(String username, String userId, + CardDavCreationObjectRequest creationObjectRequest) { + return client + .headers(headers -> headers.add(HttpHeaderNames.ACCEPT, "application/vcard+json")) + .headers(headers -> { + headers.add(HttpHeaderNames.CONTENT_TYPE, "text/vcard"); + headers.add(HttpHeaderNames.AUTHORIZATION, HttpUtils.createBasicAuthenticationToken(adminCredentialWithDelegatedFunction.apply(username))); + }) + .put() + .uri(String.format(COLLECTED_ADDRESS_BOOK_PATH, userId, creationObjectRequest.uid())) + .send(Mono.just(Unpooled.wrappedBuffer(creationObjectRequest.toVCard().getBytes()))) + .responseSingle((response, byteBufMono) -> switch (response.status().code()) { + case 201 -> Mono.empty(); + case 204 -> { + LOGGER.info("Contact for user {} and collected id {} already exists", userId, creationObjectRequest.uid()); + yield Mono.empty(); + } + default -> + Mono.error(new DavClientException("Unexpected status code: " + response.status().code() + + " when creating contact for user: " + userId + " and collected id: " + creationObjectRequest.uid())); + }); + } + + public Mono getUserParticipationStatus(String userId, String eventUid, + String userEmail) { + return findAllUsersCalendars(userId, eventUid) + .flatMap(calendarURI -> + getContainingVCalendar(eventUid, calendarURI) + .flatMapMany(vcalendar -> Flux.fromIterable(vcalendar.getComponents("VEVENT")))) + .collectList() + .flatMap(events -> doGetUserParticipationStatus(events, userEmail)) + .map(x -> new PartStat(x.value())); + } + + private Mono doGetUserParticipationStatus(List vEvents, String userEmail) { + if (vEvents.size() == 1) { + return Mono.just(vEvents.getFirst()) + .map(CalendarParticipantsField::from) + .map(participantsField -> + participantsField.findParticipantByMailTo(userEmail) + .flatMap(CalendarAttendeeField::participationStatus)) + .map(OptionConverters::toJava) + .flatMap(Mono::justOrEmpty) + .doOnNext(System.out::println); + } else { + // TODO: handle recurring events + return Mono.empty(); + } + } + + private Mono getContainingVCalendar(String eventUid, URI calendarURI) { + return client.headers(headers -> headers.add(HttpHeaderNames.ACCEPT, "application/xml")) + .headers(headers -> headers.add("Depth", "1")) + .headers(headers -> headers.add(HttpHeaderNames.AUTHORIZATION, + HttpUtils.createBasicAuthenticationToken( + davConfiguration.adminCredential().getUserName(), + davConfiguration.adminCredential().getPassword()))) + .request(HttpMethod.valueOf("REPORT")) + .uri(calendarURI.getPath()) + .send(Mono.just(Unpooled.wrappedBuffer(new GetCalendarByEventIdRequestBody(eventUid).value().getBytes()))) + .responseSingle((response, byteBufMono) -> { + if (response.status() == HttpResponseStatus.MULTI_STATUS) { + return byteBufMono.asString(StandardCharsets.UTF_8) + .flatMap(multiStatusResponse -> + extractVCalendarFromResponse(XMLUtil.parse(multiStatusResponse, DavMultistatus.class))); + } else { + return Mono.empty(); + } + }); + } + + public Mono setUserParticipationStatus(String userId, String eventUuid, + PartStat partStat) { + return Mono.empty(); + } + + private Flux findAllUsersCalendars(String userId, String username) { + return client.headers(headers -> headers.add(HttpHeaderNames.ACCEPT, "application/xml")) + .headers(headers -> headers.add(HttpHeaderNames.AUTHORIZATION, + HttpUtils.createBasicAuthenticationToken( + davConfiguration.adminCredential().getUserName(), + davConfiguration.adminCredential().getPassword()))) + .request(HttpMethod.valueOf("PROPFIND")) + .uri(String.format("/calendars/%s", userId)) + .responseSingle((response, byteBufMono) -> { + if (response.status() == HttpResponseStatus.MULTI_STATUS) { + return byteBufMono.asString(StandardCharsets.UTF_8) + .map(multiStatusResponse -> XMLUtil.parse(multiStatusResponse, + DavMultistatus.class)) + .map(this::extractCalendarURIsFromResponse); + } else { + return Mono.empty(); + } + }).flatMapMany(Flux::fromIterable); + } + + private static final Pattern CALENDAR_URI_PATTERN = Pattern.compile("/calendars/[^/]+/[^/]+/"); + + private List extractCalendarURIsFromResponse(DavMultistatus multistatus) { + List hrefs = new ArrayList<>(); + + for (DavResponse response : multistatus.getResponses()) { + response.getHref().getValue().ifPresent(href -> { + if (CALENDAR_URI_PATTERN.matcher(href).matches()) { + if (!(href.endsWith("inbox/") || href.endsWith("outbox/"))) { + hrefs.add(URI.create(href)); + } + } + }); + } + + LOGGER.trace("Found user calendars: {}", hrefs); + + return hrefs; + } + + private static @NotNull Mono extractVCalendarFromResponse(DavMultistatus multistatus) { + return Flux.fromIterable(multistatus.getResponses()) + .next() + .map(davResponse -> davResponse.getPropstat().getProp().getCalendarData()) + .flatMap(Mono::justOrEmpty) + .map(calendarData -> + CalendarEventParsed.parseICal4jCalendar( + IOUtils.toInputStream(calendarData.getValue(), StandardCharsets.UTF_8))); + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClientException.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClientException.java similarity index 85% rename from tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClientException.java rename to tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClientException.java index a1c6c425a5..1107ff641e 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavClientException.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/DavClientException.java @@ -16,15 +16,15 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav; -public class CardDavClientException extends RuntimeException { +public class DavClientException extends RuntimeException { - public CardDavClientException(String message) { + public DavClientException(String message) { super(message); } - public CardDavClientException(String message, Throwable cause) { + public DavClientException(String message, Throwable cause) { super(message, cause); } } diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationObjectRequest.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/CardDavCreationObjectRequest.java similarity index 98% rename from tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationObjectRequest.java rename to tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/CardDavCreationObjectRequest.java index fb541cc4ea..33c66726fc 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/carddav/CardDavCreationObjectRequest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/CardDavCreationObjectRequest.java @@ -16,7 +16,7 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav.request; import java.util.List; import java.util.Optional; diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/GetCalendarByEventIdRequestBody.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/GetCalendarByEventIdRequestBody.java new file mode 100644 index 0000000000..066be6be56 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/request/GetCalendarByEventIdRequestBody.java @@ -0,0 +1,43 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.request; + +public record GetCalendarByEventIdRequestBody(String vEventUid) { + + public String value() { + return """ + + + + + + + + + + %s + + + + + + """.formatted(vEventUid); + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/CalendarData.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/CalendarData.java new file mode 100644 index 0000000000..856494f0c9 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/CalendarData.java @@ -0,0 +1,38 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import javax.xml.bind.annotation.XmlValue; + +public class CalendarData { + + @XmlValue + private String value; + + public String getValue() { + return value; + } + + @Override + public String toString() { + return "CalCalendarData{" + + "'" + value + '\'' + + '}'; + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavHref.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavHref.java new file mode 100644 index 0000000000..313f48f840 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavHref.java @@ -0,0 +1,39 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import java.util.Optional; + +import javax.xml.bind.annotation.XmlValue; + +public class DavHref { + @XmlValue + private String value; + + public Optional getValue() { + return Optional.ofNullable(value); + } + + @Override + public String toString() { + return "DavHref{" + + "'" + value + '\'' + + '}'; + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavMultistatus.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavMultistatus.java new file mode 100644 index 0000000000..f13b5805bf --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavMultistatus.java @@ -0,0 +1,46 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "multistatus", namespace = "DAV:") +public class DavMultistatus { + + @XmlElement(name = "response", namespace = "DAV:") + private List responses; + + public List getResponses() { + if (responses == null) { + return new ArrayList<>(); + } + return responses; + } + + @Override + public String toString() { + return responses.stream().map(DavResponse::toString) + .collect(Collectors.joining(", ", "{", "}")); + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavProp.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavProp.java new file mode 100644 index 0000000000..cdf58e9c24 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavProp.java @@ -0,0 +1,39 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import java.util.Optional; + +import javax.xml.bind.annotation.XmlElement; + +public class DavProp { + @XmlElement(name = "calendar-data", namespace = "urn:ietf:params:xml:ns:caldav") + private CalendarData calendarData; + + public Optional getCalendarData() { + return Optional.ofNullable(calendarData); + } + + @Override + public String toString() { + return "DavProp{" + + "calendarData=" + calendarData + + '}'; + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavPropstat.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavPropstat.java new file mode 100644 index 0000000000..3318c3d3b0 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavPropstat.java @@ -0,0 +1,44 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import javax.xml.bind.annotation.XmlElement; + +public class DavPropstat { + @XmlElement(name = "status", namespace = "DAV:") + private DavStatus status; + + @XmlElement(name = "prop", namespace = "DAV:") + private DavProp prop; + + public DavStatus getStatus() { + return status; + } + + public DavProp getProp() { + return prop; + } + + @Override + public String toString() { + return "DavPropstat{" + + "status=" + status + + '}'; + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavResponse.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavResponse.java new file mode 100644 index 0000000000..c1715e92c9 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavResponse.java @@ -0,0 +1,44 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import javax.xml.bind.annotation.XmlElement; + +public class DavResponse { + @XmlElement(name = "href", namespace = "DAV:") + private DavHref href; + + @XmlElement(name = "propstat", namespace = "DAV:") + private DavPropstat propstat; + + public DavHref getHref() { + return href; + } + + public DavPropstat getPropstat() { + return propstat; + } + + @Override + public String toString() { + return "DavResponse{" + + "href=" + href + + '}'; + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavStatus.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavStatus.java new file mode 100644 index 0000000000..2aab8f5df2 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/DavStatus.java @@ -0,0 +1,38 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import javax.xml.bind.annotation.XmlValue; + +public class DavStatus { + + @XmlValue + private String value; + + public String getValue() { + return value; + } + + @Override + public String toString() { + return "DavStatus{" + + "'" + value + '\'' + + '}'; + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/XMLUtil.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/XMLUtil.java new file mode 100644 index 0000000000..342d40c9d6 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/dav/xml/XMLUtil.java @@ -0,0 +1,49 @@ +/******************************************************************** + * As a subpart of Twake Mail, this file is edited by Linagora. * + * * + * https://twake-mail.com/ * + * https://linagora.com * + * * + * This file is subject to The Affero Gnu Public License * + * version 3. * + * * + * https://www.gnu.org/licenses/agpl-3.0.en.html * + * * + * This program is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * + * PURPOSE. See the GNU Affero General Public License for * + * more details. * + ********************************************************************/ + +package com.linagora.tmail.dav.xml; + +import java.io.File; +import java.io.StringReader; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +public class XMLUtil { + + public static T parse(File xmlFile, Class clazz) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(clazz); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return clazz.cast(unmarshaller.unmarshal(xmlFile)); + } catch (JAXBException e) { + throw new RuntimeException("Failed to parse the given XML file at: " + xmlFile.getAbsolutePath(), e); + } + } + + public static T parse(String xml, Class clazz) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(clazz); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return clazz.cast(unmarshaller.unmarshal(new StringReader(xml))); + } catch (JAXBException e) { + throw new RuntimeException("Failed to parse the given XML string", e); + } + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/mailet/CardDavCollectedContact.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/mailet/CardDavCollectedContact.java index 09ca3f0b51..873fade285 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/mailet/CardDavCollectedContact.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/mailet/CardDavCollectedContact.java @@ -32,9 +32,9 @@ import com.google.common.collect.ImmutableList; import com.linagora.tmail.api.OpenPaasRestClient; -import com.linagora.tmail.carddav.CardDavClient; -import com.linagora.tmail.carddav.CardDavCreationFactory; -import com.linagora.tmail.carddav.CardDavCreationObjectRequest; +import com.linagora.tmail.dav.CardDavUtils; +import com.linagora.tmail.dav.DavClient; +import com.linagora.tmail.dav.request.CardDavCreationObjectRequest; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -46,12 +46,12 @@ public class CardDavCollectedContact extends GenericMailet { private static final Logger LOGGER = LoggerFactory.getLogger(CardDavCollectedContact.class); private final OpenPaasRestClient openPaasRestClient; - private final CardDavClient cardDavClient; + private final DavClient davClient; @Inject - public CardDavCollectedContact(OpenPaasRestClient openPaasRestClient, CardDavClient cardDavClient) { + public CardDavCollectedContact(OpenPaasRestClient openPaasRestClient, DavClient davClient) { this.openPaasRestClient = openPaasRestClient; - this.cardDavClient = cardDavClient; + this.davClient = davClient; } @Override @@ -66,15 +66,15 @@ public void service(Mail mail) throws MessagingException { private Mono collectedContactProcess(MailAddress sender, List recipients) { return openPaasRestClient.searchOpenPaasUserId(sender.asString()) .flatMapMany(openPassUserId -> Flux.fromIterable(recipients) - .map(CardDavCreationFactory::create) + .map(CardDavUtils::createObjectCreationRequest) .flatMap(cardDavCreationObjectRequest -> createCollectedContactIfNotExists(sender, openPassUserId, cardDavCreationObjectRequest))) .then(); } private Mono createCollectedContactIfNotExists(MailAddress sender, String openPassUserId, CardDavCreationObjectRequest cardDavCreationObjectRequest) { - return cardDavClient.existsCollectedContact(sender.asString(), openPassUserId, cardDavCreationObjectRequest.uid()) + return davClient.existsCollectedContact(sender.asString(), openPassUserId, cardDavCreationObjectRequest.uid()) .filter(FunctionalUtils.identityPredicate().negate()) - .flatMap(exists -> cardDavClient.createCollectedContact(sender.asString(), openPassUserId, cardDavCreationObjectRequest)) + .flatMap(exists -> davClient.createCollectedContact(sender.asString(), openPassUserId, cardDavCreationObjectRequest)) .onErrorResume(error -> { LOGGER.error("Error while creating collected contact if not exists.", error); return Mono.empty(); diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/CardDavCollectedContactIntegrationTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/CardDavCollectedContactIntegrationTest.java index e91f1aabb6..7fabe5840d 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/CardDavCollectedContactIntegrationTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/CardDavCollectedContactIntegrationTest.java @@ -58,8 +58,8 @@ import com.google.inject.Provides; import com.google.inject.util.Modules; import com.linagora.tmail.api.OpenPaasServerExtension; -import com.linagora.tmail.carddav.CardDavCreationFactory; -import com.linagora.tmail.carddav.CardDavServerExtension; +import com.linagora.tmail.dav.CardDavUtils; +import com.linagora.tmail.dav.DavServerExtension; import com.linagora.tmail.configuration.OpenPaasConfiguration; import com.linagora.tmail.james.jmap.contact.InMemoryEmailAddressContactSearchEngineModule; import com.linagora.tmail.mailet.CardDavCollectedContact; @@ -75,7 +75,7 @@ public class CardDavCollectedContactIntegrationTest { static OpenPaasServerExtension openPaasServerExtension = new OpenPaasServerExtension(); @RegisterExtension - static CardDavServerExtension cardDavServerExtension = new CardDavServerExtension(); + static DavServerExtension cardDavServerExtension = new DavServerExtension(); private TemporaryJamesServer jamesServer; @@ -94,7 +94,7 @@ void setup(@TempDir File temporaryFolder) throws Exception { .withOverrides(new AbstractModule() { @Override protected void configure() { - install(new OpenPaasModule.CardDavModule()); + install(new OpenPaasModule.DavModule()); } @Provides @@ -133,7 +133,7 @@ void tearDown() { @Test void shouldPUTCreateCollectedContactWhenContactDoesNotExist() throws Exception { // Setup mock server - String contactUid = CardDavCreationFactory.createContactUid(BOB.asMailAddress()); + String contactUid = CardDavUtils.createContactUid(BOB.asMailAddress()); String openPassUid = UUID.randomUUID().toString(); openPaasServerExtension.setSearchEmailExist(ALICE.asString(), openPassUid); // Contact does not exist @@ -150,7 +150,7 @@ void shouldPUTCreateCollectedContactWhenContactDoesNotExist() throws Exception { @Test void shouldNotPUTCreateCollectedContactWhenContactExists() throws Exception { // Setup mock server - String contactUid = CardDavCreationFactory.createContactUid(BOB.asMailAddress()); + String contactUid = CardDavUtils.createContactUid(BOB.asMailAddress()); String openPassUid = UUID.randomUUID().toString(); openPaasServerExtension.setSearchEmailExist(ALICE.asString(), openPassUid); // Contact exists @@ -167,7 +167,7 @@ void shouldNotPUTCreateCollectedContactWhenContactExists() throws Exception { @Test void shouldNotPUTCreateCollectedContactWhenSearchEmailDoesNotExist() throws Exception { // Setup mock server - String contactUid = CardDavCreationFactory.createContactUid(BOB.asMailAddress()); + String contactUid = CardDavUtils.createContactUid(BOB.asMailAddress()); String openPassUid = UUID.randomUUID().toString(); openPaasServerExtension.setSearchEmailNotFound(ALICE.asString()); cardDavServerExtension.setCollectedContactExists(ALICE_OPENPAAS_USER_NAME, openPassUid, contactUid, !COLLECTED_CONTACT_EXISTS); @@ -183,8 +183,8 @@ void shouldNotPUTCreateCollectedContactWhenSearchEmailDoesNotExist() throws Exce @Test void shouldPUTCreateCollectedContactMultipleTimesWhenMultipleRecipients() throws Exception { // Setup mock server - String bobContactUid = CardDavCreationFactory.createContactUid(BOB.asMailAddress()); - String cedricContactUid = CardDavCreationFactory.createContactUid(CEDRIC.asMailAddress()); + String bobContactUid = CardDavUtils.createContactUid(BOB.asMailAddress()); + String cedricContactUid = CardDavUtils.createContactUid(CEDRIC.asMailAddress()); String aliceOpenPassId = UUID.randomUUID().toString(); openPaasServerExtension.setSearchEmailExist(ALICE.asString(), aliceOpenPassId); cardDavServerExtension.setCollectedContactExists(ALICE_OPENPAAS_USER_NAME, aliceOpenPassId, bobContactUid, !COLLECTED_CONTACT_EXISTS); @@ -224,8 +224,8 @@ void shouldPUTCreateCollectedContactMultipleTimesWhenMultipleRecipients() throws @Test void shouldPUTCreateCollectedContactForContactDoesNotExistWhenMultipleRecipients() throws Exception { // Setup mock server - String bobContactUid = CardDavCreationFactory.createContactUid(BOB.asMailAddress()); - String cedricContactUid = CardDavCreationFactory.createContactUid(CEDRIC.asMailAddress()); + String bobContactUid = CardDavUtils.createContactUid(BOB.asMailAddress()); + String cedricContactUid = CardDavUtils.createContactUid(CEDRIC.asMailAddress()); String aliceOpenPassId = UUID.randomUUID().toString(); openPaasServerExtension.setSearchEmailExist(ALICE.asString(), aliceOpenPassId); cardDavServerExtension.setCollectedContactExists(ALICE_OPENPAAS_USER_NAME, aliceOpenPassId, bobContactUid, COLLECTED_CONTACT_EXISTS); diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/CardDavConfigurationTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/CardDavConfigurationTest.java index 342593d839..e1974b4e6c 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/CardDavConfigurationTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/CardDavConfigurationTest.java @@ -36,7 +36,7 @@ class CardDavConfigurationTest { @Test void shouldRespectBeanContract() { - EqualsVerifier.forClass(CardDavConfiguration.class) + EqualsVerifier.forClass(DavConfiguration.class) .verify(); } @@ -49,13 +49,13 @@ void fromShouldReturnTheConfigurationWhenAllParametersAreGiven() throws URISynta configuration.addProperty("carddav.rest.client.trust.all.ssl.certs", "true"); configuration.addProperty("carddav.rest.client.response.timeout", "500"); - CardDavConfiguration expected = new CardDavConfiguration( + DavConfiguration expected = new DavConfiguration( new UsernamePasswordCredentials("jhon_doe", "123"), new URI("http://localhost:8080"), Optional.of(true) , Optional.of(Duration.ofMillis(500))); - assertThat(CardDavConfiguration.from(configuration)) + assertThat(DavConfiguration.from(configuration)) .isEqualTo(expected); } @@ -65,7 +65,7 @@ void fromShouldThrowWhenCardDavApiUriNotConfigured() { configuration.addProperty("carddav.admin.user", "jhon_doe"); configuration.addProperty("carddav.admin.password", "123"); - assertThatThrownBy(() -> CardDavConfiguration.from(configuration)) + assertThatThrownBy(() -> DavConfiguration.from(configuration)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("carddav.api.uri should not be empty"); } @@ -78,7 +78,7 @@ void fromShouldThrowWhenCardDavAdminUserNotConfigured() { configuration.addProperty("carddav.rest.client.trust.all.ssl.certs", "true"); configuration.addProperty("carddav.rest.client.response.timeout", "500"); - assertThatThrownBy(() -> CardDavConfiguration.from(configuration)) + assertThatThrownBy(() -> DavConfiguration.from(configuration)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("carddav.admin.user should not be empty"); } diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavCreationObjectRequestTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/CardDavCreationObjectRequestTest.java similarity index 96% rename from tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavCreationObjectRequestTest.java rename to tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/CardDavCreationObjectRequestTest.java index a87dbce032..80affe49b9 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavCreationObjectRequestTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/CardDavCreationObjectRequestTest.java @@ -16,7 +16,7 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav; import static org.assertj.core.api.Assertions.assertThat; @@ -28,6 +28,8 @@ import ezvcard.parameter.EmailType; +import com.linagora.tmail.dav.request.CardDavCreationObjectRequest; + public class CardDavCreationObjectRequestTest { @Test diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavClientTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavClientTest.java similarity index 91% rename from tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavClientTest.java rename to tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavClientTest.java index 0bc5ce09de..06b13de6bc 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavClientTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavClientTest.java @@ -16,9 +16,9 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav; -import static com.linagora.tmail.carddav.CardDavServerExtension.CARD_DAV_ADMIN_WITH_DELEGATED_AUTHORIZATION; +import static com.linagora.tmail.dav.DavServerExtension.CARD_DAV_ADMIN_WITH_DELEGATED_AUTHORIZATION; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -38,18 +38,20 @@ import ezvcard.parameter.EmailType; -public class CardDavClientTest { +import com.linagora.tmail.dav.request.CardDavCreationObjectRequest; + +public class DavClientTest { private static final String OPENPAAS_USER_NAME = "openpaasUserName1"; private static final String OPENPAAS_USER_ID = "openpaasUserId1"; @RegisterExtension - static CardDavServerExtension cardDavServerExtension = new CardDavServerExtension(); + static DavServerExtension cardDavServerExtension = new DavServerExtension(); - private CardDavClient client; + private DavClient client; @BeforeEach void setup() { - client = new CardDavClient.OpenpaasCardDavClient(cardDavServerExtension.getCardDavConfiguration()); + client = new DavClient(cardDavServerExtension.getCardDavConfiguration()); } @Test @@ -79,7 +81,7 @@ void existsCollectedContactShouldReturnFalseWhenHTTPResponseIs500(ClientAndServe .withStatusCode(500)); assertThatThrownBy(() -> client.existsCollectedContact(OPENPAAS_USER_NAME, OPENPAAS_USER_ID, collectedContactUid).block()) - .isInstanceOf(CardDavClientException.class); + .isInstanceOf(DavClientException.class); } @Test @@ -120,6 +122,6 @@ void createCollectedContactShouldThrowWhenHTTPResponseIs404(ClientAndServer mock new MailAddress("anbach4@lina.com"))); assertThatThrownBy(() -> client.createCollectedContact(OPENPAAS_USER_NAME, OPENPAAS_USER_ID, request).block()) - .isInstanceOf(CardDavClientException.class); + .isInstanceOf(DavClientException.class); } } diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavServerExtension.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavServerExtension.java similarity index 95% rename from tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavServerExtension.java rename to tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavServerExtension.java index 69209e0fe3..623af72cec 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/carddav/CardDavServerExtension.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/dav/DavServerExtension.java @@ -16,7 +16,7 @@ * more details. * ********************************************************************/ -package com.linagora.tmail.carddav; +package com.linagora.tmail.dav; import static org.mockserver.model.NottableString.string; @@ -40,9 +40,9 @@ import com.github.fge.lambdas.Throwing; import com.linagora.tmail.HttpUtils; -import com.linagora.tmail.configuration.CardDavConfiguration; +import com.linagora.tmail.configuration.DavConfiguration; -public class CardDavServerExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { +public class DavServerExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { public static final String CARD_DAV_ADMIN = "admin"; public static final String CARD_DAV_ADMIN_PASSWORD = "secret123"; @@ -132,8 +132,8 @@ public void assertCreateCollectedContactWasCalled(String openPassUserName, Strin VerificationTimes.exactly(times)); } - public CardDavConfiguration getCardDavConfiguration() { - return new CardDavConfiguration( + public DavConfiguration getCardDavConfiguration() { + return new DavConfiguration( new UsernamePasswordCredentials(CARD_DAV_ADMIN, CARD_DAV_ADMIN_PASSWORD), getBaseUrl(), Optional.of(true),