From 188247cec1da196022049e1a40b66da5c0edc8a1 Mon Sep 17 00:00:00 2001 From: Elias Croze Date: Mon, 12 Oct 2020 16:02:54 +0200 Subject: [PATCH 1/5] APP-3104: First implementation of fluent OBO --- docs/authentication.md | 9 +- .../symphony/bdk/core/OboServiceFactory.java | 80 +++++++++ .../symphony/bdk/core/OboServicesFacade.java | 57 +++++++ .../com/symphony/bdk/core/ServiceFactory.java | 35 +--- .../com/symphony/bdk/core/SymphonyBdk.java | 18 +- .../core/service/message/MessageService.java | 132 +-------------- .../service/message/OboMessageService.java | 158 ++++++++++++++++++ .../core/service/stream/OboStreamService.java | 47 +++--- .../core/service/stream/StreamService.java | 96 +---------- .../bdk/core/service/user/OboUserService.java | 41 +++-- .../bdk/core/service/user/UserService.java | 90 +--------- .../bdk/core/OboServiceFactoryTest.java | 38 +++++ .../bdk/core/OboServicesFacadeTest.java | 36 ++++ .../symphony/bdk/core/SymphonyBdkTest.java | 15 +- .../com/symphony/bdk/examples/AuthMain.java | 10 +- .../bdk/examples/UserExampleMain.java | 2 +- 16 files changed, 468 insertions(+), 396 deletions(-) create mode 100644 symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java create mode 100644 symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java create mode 100644 symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java create mode 100644 symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java create mode 100644 symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java diff --git a/docs/authentication.md b/docs/authentication.md index dfa4b235b..17451a673 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -156,7 +156,8 @@ public class Example { ### OBO (On Behalf Of) authentication > Read more about OBO authentication [here](https://developers.symphony.com/symphony-developer/docs/obo-overview) -The following example shows how to retrieve OBO sessions using `username` (type `String`) or `userId` (type `Long`): +The following example shows how to retrieve OBO sessions using `username` (type `String`) or `userId` (type `Long`) +and to call services which have OBO endpoints (users, streams and messages so far): ```java public class Example { @@ -169,7 +170,11 @@ public class Example { final AuthSession oboSessionUserId = bdk.obo(123456789L); // list streams OBO user "user.name" - bdk.streams().listStreams(oboSessionUsername, new StreamFilter()); + bdk.obo(oboSessionUsername).streams().listStreams(new StreamFilter()); + + // or send a message OBO: + Message message = Message.builder().content("Hello, World").build(); + bdk.obo(oboSessionUserId).messages().send("streamID", message); } } ``` diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java new file mode 100644 index 000000000..d35fb618d --- /dev/null +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java @@ -0,0 +1,80 @@ +package com.symphony.bdk.core; + +import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.client.ApiClientFactory; +import com.symphony.bdk.core.config.model.BdkConfig; +import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; +import com.symphony.bdk.core.service.message.OboMessageService; +import com.symphony.bdk.core.service.stream.OboStreamService; +import com.symphony.bdk.core.service.user.OboUserService; +import com.symphony.bdk.gen.api.MessagesApi; +import com.symphony.bdk.gen.api.RoomMembershipApi; +import com.symphony.bdk.gen.api.ShareApi; +import com.symphony.bdk.gen.api.StreamsApi; +import com.symphony.bdk.gen.api.UserApi; +import com.symphony.bdk.gen.api.UsersApi; +import com.symphony.bdk.http.api.ApiClient; +import com.symphony.bdk.http.api.ApiException; +import com.symphony.bdk.template.api.TemplateEngine; + +import org.apiguardian.api.API; + +/** + * Factory responsible for creating BDK OBO-enabled service instances for {@link OboServicesFacade}. + * : + * + */ +@API(status = API.Status.INTERNAL) +public class OboServiceFactory { + + protected final ApiClient podClient; + protected final ApiClient agentClient; + protected final AuthSession authSession; + protected final TemplateEngine templateEngine; + protected final BdkConfig config; + protected final RetryWithRecoveryBuilder retryBuilder; + + public OboServiceFactory(ApiClientFactory apiClientFactory, AuthSession authSession, BdkConfig config) { + this.podClient = apiClientFactory.getPodClient(); + this.agentClient = apiClientFactory.getAgentClient(); + this.authSession = authSession; + this.templateEngine = TemplateEngine.getDefaultImplementation(); + this.config = config; + this.retryBuilder = new RetryWithRecoveryBuilder<>() + .retryConfig(config.getRetry()) + .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); + } + + /** + * Returns a fully initialized {@link OboUserService} + * + * @return a new {@link OboUserService} instance + */ + public OboUserService getObUserService() { + return new OboUserService(new UserApi(podClient), new UsersApi(podClient), authSession, retryBuilder); + } + + /** + * Returns a fully initialized {@link OboStreamService} + * + * @return a new {@link OboStreamService} instance + */ + public OboStreamService getOboStreamService() { + return new OboStreamService(new StreamsApi(podClient), new RoomMembershipApi(podClient), new ShareApi(agentClient), + authSession, retryBuilder); + } + + /** + * Returns a fully initialized {@link OboMessageService} + * + * @return a new {@link OboMessageService} instance + */ + public OboMessageService getOboMessageService() { + return new OboMessageService(new MessagesApi(this.agentClient), this.authSession, this.templateEngine, + this.retryBuilder); + } +} diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java new file mode 100644 index 000000000..cdf5288d8 --- /dev/null +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java @@ -0,0 +1,57 @@ +package com.symphony.bdk.core; + +import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.client.ApiClientFactory; +import com.symphony.bdk.core.config.model.BdkConfig; +import com.symphony.bdk.core.service.message.OboMessageService; +import com.symphony.bdk.core.service.stream.OboStreamService; +import com.symphony.bdk.core.service.user.OboUserService; + +import org.apiguardian.api.API; + +/** + * Entry point for OBO-enabled services. + */ +@API(status = API.Status.EXPERIMENTAL) +public class OboServicesFacade { + + private final OboStreamService oboStreamService; + private final OboUserService oboUserService; + private final OboMessageService oboMessageService; + + public OboServicesFacade(BdkConfig config, AuthSession oboSession) { + final OboServiceFactory serviceFactory = new OboServiceFactory(new ApiClientFactory(config), oboSession, config); + + oboStreamService = serviceFactory.getOboStreamService(); + oboUserService = serviceFactory.getObUserService(); + oboMessageService = serviceFactory.getOboMessageService(); + } + + /** + * Get the {@link OboStreamService} using the provided OBO session in constructor. + * + * @return an {@link OboStreamService} instance with the provided OBO session. + */ + public OboStreamService streams() { + return oboStreamService; + } + + /** + * Get the {@link OboUserService} using the provided OBO session in constructor. + * + * @return an {@link OboUserService} instance with the provided OBO session. + */ + public OboUserService users() { + return oboUserService; + } + + /** + * Get the {@link OboMessageService} using the provided OBO session in constructor. + * The returned message service instance. + * + * @return an {@link OboMessageService} instance with the provided OBO session. + */ + public OboMessageService messages() { + return oboMessageService; + } +} diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java index f8e2ee30f..c65f13e4d 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java @@ -4,12 +4,12 @@ import com.symphony.bdk.core.client.ApiClientFactory; import com.symphony.bdk.core.config.model.BdkConfig; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.service.message.MessageService; import com.symphony.bdk.core.service.SessionService; import com.symphony.bdk.core.service.datafeed.DatafeedService; import com.symphony.bdk.core.service.datafeed.DatafeedVersion; import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV1; import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV2; +import com.symphony.bdk.core.service.message.MessageService; import com.symphony.bdk.core.service.stream.StreamService; import com.symphony.bdk.core.service.user.UserService; import com.symphony.bdk.gen.api.AttachmentsApi; @@ -25,11 +25,6 @@ import com.symphony.bdk.gen.api.StreamsApi; import com.symphony.bdk.gen.api.UserApi; import com.symphony.bdk.gen.api.UsersApi; -import com.symphony.bdk.http.api.ApiClient; - -import com.symphony.bdk.http.api.ApiException; - -import com.symphony.bdk.template.api.TemplateEngine; import org.apiguardian.api.API; @@ -45,30 +40,16 @@ * */ @API(status = API.Status.INTERNAL) -class ServiceFactory { - - private final ApiClient podClient; - private final ApiClient agentClient; - private final AuthSession authSession; - private final BdkConfig config; - private final TemplateEngine templateEngine; - private final RetryWithRecoveryBuilder retryBuilder; +class ServiceFactory extends OboServiceFactory { public ServiceFactory(ApiClientFactory apiClientFactory, AuthSession authSession, BdkConfig config) { - this.podClient = apiClientFactory.getPodClient(); - this.agentClient = apiClientFactory.getAgentClient(); - this.authSession = authSession; - this.config = config; - this.templateEngine = TemplateEngine.getDefaultImplementation(); - this.retryBuilder = new RetryWithRecoveryBuilder<>() - .retryConfig(config.getRetry()) - .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); + super(apiClientFactory, authSession, config); } /** * Returns a fully initialized {@link UserService}. * - * @return an new {@link UserService} instance. + * @return a new {@link UserService} instance. */ public UserService getUserService() { return new UserService(new UserApi(podClient), new UsersApi(podClient), authSession, retryBuilder); @@ -77,7 +58,7 @@ public UserService getUserService() { /** * Returns a fully initialized {@link StreamService}. * - * @return an new {@link StreamService} instance. + * @return a new {@link StreamService} instance. */ public StreamService getStreamService() { return new StreamService(new StreamsApi(podClient), new RoomMembershipApi(podClient), new ShareApi(agentClient), @@ -87,7 +68,7 @@ public StreamService getStreamService() { /** * Returns a fully initialized {@link SessionService}. * - * @return an new {@link SessionService} instance. + * @return a new {@link SessionService} instance. */ public SessionService getSessionService() { return new SessionService(new SessionApi(podClient), @@ -97,7 +78,7 @@ public SessionService getSessionService() { /** * Returns a fully initialized {@link DatafeedService}. * - * @return an new {@link DatafeedService} instance. + * @return a new {@link DatafeedService} instance. */ public DatafeedService getDatafeedService() { if (DatafeedVersion.of(config.getDatafeed().getVersion()) == DatafeedVersion.V2) { @@ -109,7 +90,7 @@ public DatafeedService getDatafeedService() { /** * Returns a fully initialized {@link MessageService}. * - * @return an new {@link MessageService} instance. + * @return a new {@link MessageService} instance. */ public MessageService getMessageService() { return new MessageService( diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java index 52a5364e2..e05f11caf 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java @@ -9,9 +9,9 @@ import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException; import com.symphony.bdk.core.client.ApiClientFactory; import com.symphony.bdk.core.config.model.BdkConfig; -import com.symphony.bdk.core.service.message.MessageService; import com.symphony.bdk.core.service.SessionService; import com.symphony.bdk.core.service.datafeed.DatafeedService; +import com.symphony.bdk.core.service.message.MessageService; import com.symphony.bdk.core.service.stream.StreamService; import com.symphony.bdk.core.service.user.UserService; import com.symphony.bdk.core.util.ServiceLookup; @@ -31,6 +31,7 @@ @API(status = API.Status.EXPERIMENTAL) public class SymphonyBdk { + private final BdkConfig config; private final AuthSession botSession; private final UserV2 botInfo; @@ -50,11 +51,13 @@ public SymphonyBdk(BdkConfig config) throws AuthInitializationException, AuthUna protected SymphonyBdk(BdkConfig config, ApiClientFactory apiClientFactory) throws AuthInitializationException, AuthUnauthorizedException { + this.config = config; final AuthenticatorFactory authenticatorFactory = new AuthenticatorFactory(config, apiClientFactory); this.botSession = authenticatorFactory.getBotAuthenticator().authenticateBot(); this.oboAuthenticator = config.isOboConfigured() ? authenticatorFactory.getOboAuthenticator() : null; - this.extensionAppAuthenticator = config.isOboConfigured() ? authenticatorFactory.getExtensionAppAuthenticator() : null; + this.extensionAppAuthenticator = + config.isOboConfigured() ? authenticatorFactory.getExtensionAppAuthenticator() : null; // service init final ServiceFactory serviceFactory = new ServiceFactory(apiClientFactory, this.botSession, config); @@ -148,6 +151,16 @@ public AuthSession obo(String username) throws AuthUnauthorizedException { return this.getOboAuthenticator().authenticateByUsername(username); } + /** + * Get an {@link OboServicesFacade} gathering all OBO enabled services + * + * @param oboSession the OBO session to use + * @return an {@link OboServicesFacade} instance using the provided OBO session + */ + public OboServicesFacade obo(AuthSession oboSession) { + return new OboServicesFacade(config, oboSession); + } + /** * Returns the {@link ExtensionAppAuthenticator}. * @@ -166,6 +179,7 @@ public ExtensionAppAuthenticator appAuthenticator() { public AuthSession botSession() { return this.botSession; } + /** * Returns the bot information. * diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java index d9076c27f..2ce18d509 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java @@ -1,17 +1,10 @@ package com.symphony.bdk.core.service.message; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; - import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.service.message.model.Attachment; -import com.symphony.bdk.core.service.message.model.Message; import com.symphony.bdk.core.service.pagination.PaginatedApi; import com.symphony.bdk.core.service.pagination.PaginatedService; import com.symphony.bdk.core.service.stream.constant.AttachmentSort; -import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.AttachmentsApi; import com.symphony.bdk.gen.api.DefaultApi; import com.symphony.bdk.gen.api.MessageApi; @@ -29,21 +22,14 @@ import com.symphony.bdk.gen.api.model.V4ImportedMessage; import com.symphony.bdk.gen.api.model.V4Message; import com.symphony.bdk.gen.api.model.V4Stream; -import com.symphony.bdk.http.api.ApiClient; -import com.symphony.bdk.http.api.ApiClientBodyPart; -import com.symphony.bdk.http.api.ApiException; import com.symphony.bdk.http.api.util.ApiUtils; -import com.symphony.bdk.http.api.util.TypeReference; import com.symphony.bdk.template.api.TemplateEngine; import lombok.extern.slf4j.Slf4j; import org.apiguardian.api.API; -import java.io.File; import java.time.Instant; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -55,18 +41,14 @@ */ @Slf4j @API(status = API.Status.STABLE) -public class MessageService { +public class MessageService extends OboMessageService { - private final MessagesApi messagesApi; private final MessageApi messageApi; private final MessageSuppressionApi messageSuppressionApi; private final StreamsApi streamsApi; private final PodApi podApi; private final AttachmentsApi attachmentsApi; private final DefaultApi defaultApi; - private final AuthSession authSession; - private final TemplateEngine templateEngine; - private final RetryWithRecoveryBuilder retryBuilder; public MessageService( final MessagesApi messagesApi, @@ -80,25 +62,13 @@ public MessageService( final TemplateEngine templateEngine, final RetryWithRecoveryBuilder retryBuilder ) { - this.messagesApi = messagesApi; + super(messagesApi, authSession, templateEngine, retryBuilder); this.messageApi = messageApi; this.messageSuppressionApi = messageSuppressionApi; this.streamsApi = streamsApi; this.podApi = podApi; this.attachmentsApi = attachmentsApi; - this.authSession = authSession; - this.templateEngine = templateEngine; this.defaultApi = defaultApi; - this.retryBuilder = retryBuilder; - } - - /** - * Returns the {@link TemplateEngine} that can be used to load templates from classpath or file system. - * - * @return the template engine - */ - public TemplateEngine templates() { - return this.templateEngine; } /** @@ -165,100 +135,6 @@ public Stream getMessagesStream(@Nonnull String streamId, @Nonnull In return new PaginatedService<>(api, actualChunkSize, actualTotalSize).stream(); } - /** - * Sends a message to the stream ID of the passed {@link V4Stream} object. - * - * @param stream the stream to send the message to - * @param message the message payload in MessageML - * @return a {@link V4Message} object containing the details of the sent message - * @see Create Message v4 - * @deprecated this method will be replaced by {@link MessageService#send(V4Stream, Message)} - */ - @Deprecated - @API(status = API.Status.DEPRECATED) - public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) { - return send(stream.getStreamId(), message); - } - - /** - * Sends a message to the stream ID passed in parameter. - * - * @param streamId the ID of the stream to send the message to - * @param message the message payload in MessageML - * @return a {@link V4Message} object containing the details of the sent message - * @see Create Message v4 - * @deprecated this method will be replaced by {@link MessageService#send(String, Message)} - */ - @Deprecated - @API(status = API.Status.DEPRECATED) - public V4Message send(@Nonnull String streamId, @Nonnull String message) { - return this.send(streamId, Message.builder().content(message).build()); - } - - /** - * Sends a message to the stream ID passed in parameter. - * - * @param stream the stream to send the message to - * @param message the message to send to the stream - * @return a {@link V4Message} object containing the details of the sent message - * @see Create Message v4 - */ - public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) { - return this.send(stream.getStreamId(), message); - } - - /** - * Sends a message to the stream ID passed in parameter. - * - * @param streamId the ID of the stream to send the message to - * @param message the message to send to the stream - * @return a {@link V4Message} object containing the details of the sent message - * @see Create Message v4 - */ - public V4Message send(@Nonnull String streamId, @Nonnull Message message) { - return this.executeAndRetry("send", () -> - this.doSend(streamId, message, this.authSession.getSessionToken(), this.authSession.getKeyManagerToken()) - ); - } - - /** - * The generated {@link MessagesApi#v4StreamSidMessageCreatePost(String, String, String, String, String, String, File, File)} - * does not allow to send multiple attachments as well as in-memory files, so we have to "manually" process this call. - */ - private V4Message doSend(String streamId, Message message, String sessionToken, String keyManagerToken) throws ApiException { - final ApiClient apiClient = this.messagesApi.getApiClient(); - final Map form = new HashMap<>(); - form.put("message", message.getContent()); - form.put("data", message.getData()); - form.put("version", message.getVersion()); - form.put("attachment", toApiClientBodyParts(message.getAttachments())); - form.put("preview", toApiClientBodyParts(message.getPreviews())); - - final Map headers = new HashMap<>(); - headers.put("sessionToken", apiClient.parameterToString(sessionToken)); - headers.put("keyManagerToken", apiClient.parameterToString(keyManagerToken)); - - return apiClient.invokeAPI( - "/v4/stream/" + apiClient.escapeString(streamId) + "/message/create", - "POST", - emptyList(), - null, // for 'multipart/form-data', body can be null - headers, - emptyMap(), - form, - apiClient.selectHeaderAccept("application/json"), - apiClient.selectHeaderContentType("multipart/form-data"), - new String[0], - new TypeReference() {} - ).getData(); - } - - private static ApiClientBodyPart[] toApiClientBodyParts(List attachments) { - return attachments.stream() - .map(a -> new ApiClientBodyPart(a.getContent(), a.getFilename())) - .toArray(ApiClientBodyPart[]::new); - } - /** * Downloads the attachment body by the stream ID, message ID and attachment ID. * @@ -423,8 +299,4 @@ public MessageMetadataResponse getMessageRelationships(@Nonnull String messageId private static Long getEpochMillis(Instant instant) { return instant == null ? null : instant.toEpochMilli(); } - - private T executeAndRetry(String name, SupplierWithApiException supplier) { - return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); - } } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java new file mode 100644 index 000000000..d551735db --- /dev/null +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java @@ -0,0 +1,158 @@ +package com.symphony.bdk.core.service.message; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.retry.RetryWithRecovery; +import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; +import com.symphony.bdk.core.service.message.model.Attachment; +import com.symphony.bdk.core.service.message.model.Message; +import com.symphony.bdk.core.util.function.SupplierWithApiException; +import com.symphony.bdk.gen.api.MessagesApi; +import com.symphony.bdk.gen.api.model.V4Message; +import com.symphony.bdk.gen.api.model.V4Stream; +import com.symphony.bdk.http.api.ApiClient; +import com.symphony.bdk.http.api.ApiClientBodyPart; +import com.symphony.bdk.http.api.ApiException; +import com.symphony.bdk.http.api.util.TypeReference; +import com.symphony.bdk.template.api.TemplateEngine; + +import org.apiguardian.api.API; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; + +/** + * Service class for managing messages. This exposed OBO-enabled endpoints only. + * + * @see Message API + */ +@API(status = API.Status.STABLE) +public class OboMessageService { + + protected final MessagesApi messagesApi; + protected final AuthSession authSession; + private final TemplateEngine templateEngine; + private final RetryWithRecoveryBuilder retryBuilder; + + public OboMessageService(MessagesApi messagesApi, AuthSession authSession, TemplateEngine templateEngine, + RetryWithRecoveryBuilder retryBuilder) { + this.messagesApi = messagesApi; + this.authSession = authSession; + this.templateEngine = templateEngine; + this.retryBuilder = retryBuilder; + } + + /** + * Returns the {@link TemplateEngine} that can be used to load templates from classpath or file system. + * + * @return the template engine + */ + public TemplateEngine templates() { + return this.templateEngine; + } + + /** + * Sends a message to the stream ID of the passed {@link V4Stream} object. + * + * @param stream the stream to send the message to + * @param message the message payload in MessageML + * @return a {@link V4Message} object containing the details of the sent message + * @see Create Message v4 + * @deprecated this method will be replaced by {@link MessageService#send(V4Stream, Message)} + */ + @Deprecated + @API(status = API.Status.DEPRECATED) + public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) { + return send(stream.getStreamId(), message); + } + + /** + * Sends a message to the stream ID passed in parameter. + * + * @param streamId the ID of the stream to send the message to + * @param message the message payload in MessageML + * @return a {@link V4Message} object containing the details of the sent message + * @see Create Message v4 + * @deprecated this method will be replaced by {@link MessageService#send(String, Message)} + */ + @Deprecated + @API(status = API.Status.DEPRECATED) + public V4Message send(@Nonnull String streamId, @Nonnull String message) { + return this.send(streamId, Message.builder().content(message).build()); + } + + /** + * Sends a message to the stream ID passed in parameter. + * + * @param stream the stream to send the message to + * @param message the message to send to the stream + * @return a {@link V4Message} object containing the details of the sent message + * @see Create Message v4 + */ + public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) { + return this.send(stream.getStreamId(), message); + } + + /** + * Sends a message to the stream ID passed in parameter. + * + * @param streamId the ID of the stream to send the message to + * @param message the message to send to the stream + * @return a {@link V4Message} object containing the details of the sent message + * @see Create Message v4 + */ + public V4Message send(@Nonnull String streamId, @Nonnull Message message) { + return this.executeAndRetry("send", () -> + this.doSend(streamId, message, this.authSession.getSessionToken(), this.authSession.getKeyManagerToken()) + ); + } + + protected T executeAndRetry(String name, SupplierWithApiException supplier) { + return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); + } + + /** + * The generated {@link MessagesApi#v4StreamSidMessageCreatePost(String, String, String, String, String, String, File, File)} + * does not allow to send multiple attachments as well as in-memory files, so we have to "manually" process this call. + */ + private V4Message doSend(String streamId, Message message, String sessionToken, String keyManagerToken) throws + ApiException { + final ApiClient apiClient = this.messagesApi.getApiClient(); + final Map form = new HashMap<>(); + form.put("message", message.getContent()); + form.put("data", message.getData()); + form.put("version", message.getVersion()); + form.put("attachment", toApiClientBodyParts(message.getAttachments())); + form.put("preview", toApiClientBodyParts(message.getPreviews())); + + final Map headers = new HashMap<>(); + headers.put("sessionToken", apiClient.parameterToString(sessionToken)); + headers.put("keyManagerToken", apiClient.parameterToString(keyManagerToken)); + + return apiClient.invokeAPI( + "/v4/stream/" + apiClient.escapeString(streamId) + "/message/create", + "POST", + emptyList(), + null, // for 'multipart/form-data', body can be null + headers, + emptyMap(), + form, + apiClient.selectHeaderAccept("application/json"), + apiClient.selectHeaderContentType("multipart/form-data"), + new String[0], + new TypeReference() {} + ).getData(); + } + + private static ApiClientBodyPart[] toApiClientBodyParts(List attachments) { + return attachments.stream() + .map(a -> new ApiClientBodyPart(a.getContent(), a.getFilename())) + .toArray(ApiClientBodyPart[]::new); + } +} diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java index 5b0c5076c..71f916004 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java @@ -19,118 +19,117 @@ import java.util.List; +/** + * Service class for managing streams. This exposes OBO-enabled endpoints only. + */ @API(status = API.Status.STABLE) -class OboStreamService { +public class OboStreamService { protected final StreamsApi streamsApi; protected final RoomMembershipApi roomMembershipApi; protected final ShareApi shareApi; + protected final AuthSession authSession; protected final RetryWithRecoveryBuilder retryBuilder; - protected OboStreamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipApi, ShareApi shareApi, RetryWithRecoveryBuilder retryBuilder) { + public OboStreamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipApi, ShareApi shareApi, + AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { this.streamsApi = streamsApi; this.roomMembershipApi = roomMembershipApi; this.shareApi = shareApi; + this.authSession = authSession; this.retryBuilder = retryBuilder; } /** * {@link StreamService#getStreamInfo(String)} * - * @param authSession Bot Session or Obo Session * @param streamId The stream id * @return The information about the stream with the given id. * @see Stream Info V2 */ - public V2StreamAttributes getStreamInfo(AuthSession authSession, String streamId) { + public V2StreamAttributes getStreamInfo(String streamId) { return executeAndRetry("getStreamInfo", - () -> streamsApi.v2StreamsSidInfoGet(streamId, authSession.getSessionToken()), authSession); + () -> streamsApi.v2StreamsSidInfoGet(streamId, authSession.getSessionToken())); } /** * {@link StreamService#listStreams(StreamFilter)} * - * @param authSession Bot Session or Obo Session * @param filter The stream searching criteria * @return The list of streams retrieved according to the searching criteria. * @see List Streams */ - public List listStreams(AuthSession authSession, StreamFilter filter) { + public List listStreams(StreamFilter filter) { return executeAndRetry("listStreams", - () -> streamsApi.v1StreamsListPost(authSession.getSessionToken(), null, null, filter), authSession); + () -> streamsApi.v1StreamsListPost(authSession.getSessionToken(), null, null, filter)); } /** * {@link StreamService#addMemberToRoom(Long, String)} * - * @param authSession Bot Session or Obo Session * @param userId The id of the user to be added to the given room * @param roomId The room id * @see Add Member */ - public void addMemberToRoom(AuthSession authSession, Long userId, String roomId) { + public void addMemberToRoom( Long userId, String roomId) { UserId user = new UserId().id(userId); executeAndRetry("addMemberToRoom", - () -> roomMembershipApi.v1RoomIdMembershipAddPost(roomId, authSession.getSessionToken(), user), authSession); + () -> roomMembershipApi.v1RoomIdMembershipAddPost(roomId, authSession.getSessionToken(), user)); } /** * {@link StreamService#removeMemberFromRoom(Long, String)} * - * @param authSession Bot Session or Obo Session * @param userId The id of the user to be removed from the given room * @param roomId The room id * @see Remove Member */ - public void removeMemberFromRoom(AuthSession authSession, Long userId, String roomId) { + public void removeMemberFromRoom(Long userId, String roomId) { UserId user = new UserId().id(userId); executeAndRetry("removeMemberFrom", - () -> roomMembershipApi.v1RoomIdMembershipRemovePost(roomId, authSession.getSessionToken(), user), authSession); + () -> roomMembershipApi.v1RoomIdMembershipRemovePost(roomId, authSession.getSessionToken(), user)); } /** * {@link StreamService#share(String, ShareContent)} * - * @param authSession Bot Session or Obo Session * @param streamId The stream id. * @param content The third-party {@link ShareContent} to be shared. * @return Message contains share content * @see Share */ - public V2Message share(AuthSession authSession, String streamId, ShareContent content) { + public V2Message share(String streamId, ShareContent content) { return executeAndRetry("share", - () -> shareApi.v3StreamSidSharePost(streamId, authSession.getSessionToken(), content, authSession.getKeyManagerToken()), authSession); + () -> shareApi.v3StreamSidSharePost(streamId, authSession.getSessionToken(), content, authSession.getKeyManagerToken())); } /** * {@link StreamService#promoteUserToRoomOwner(Long, String)} * - * @param authSession Bot Session or Obo Session. * @param userId The id of the user to be promoted to room owner. * @param roomId The room id. * @see Promote Owner */ - public void promoteUserToRoomOwner(AuthSession authSession, Long userId, String roomId) { + public void promoteUserToRoomOwner(Long userId, String roomId) { UserId user = new UserId().id(userId); executeAndRetry("promoteUserToOwner", - () -> roomMembershipApi.v1RoomIdMembershipPromoteOwnerPost(roomId, authSession.getSessionToken(), user), authSession); + () -> roomMembershipApi.v1RoomIdMembershipPromoteOwnerPost(roomId, authSession.getSessionToken(), user)); } /** * {@link StreamService#demoteUserToRoomParticipant(Long, String)} * - * @param authSession Bot Session or Obo Session. * @param userId The id of the user to be demoted to room participant. * @param roomId The room id. * @see Demote Owner */ - public void demoteUserToRoomParticipant(AuthSession authSession, Long userId, String roomId) { + public void demoteUserToRoomParticipant(Long userId, String roomId) { UserId user = new UserId().id(userId); executeAndRetry("demoteUserToParticipant", - () -> roomMembershipApi.v1RoomIdMembershipDemoteOwnerPost(roomId, authSession.getSessionToken(), user), authSession); + () -> roomMembershipApi.v1RoomIdMembershipDemoteOwnerPost(roomId, authSession.getSessionToken(), user)); } - protected T executeAndRetry(String name, SupplierWithApiException supplier, AuthSession authSession) { + protected T executeAndRetry(String name, SupplierWithApiException supplier) { final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) .clearRecoveryStrategies() // to remove refresh on bot session put by default .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java index bbf772d0b..7789e8663 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java @@ -1,24 +1,17 @@ package com.symphony.bdk.core.service.stream; import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.RoomMembershipApi; import com.symphony.bdk.gen.api.ShareApi; import com.symphony.bdk.gen.api.StreamsApi; import com.symphony.bdk.gen.api.model.MemberInfo; import com.symphony.bdk.gen.api.model.RoomDetail; -import com.symphony.bdk.gen.api.model.ShareContent; import com.symphony.bdk.gen.api.model.Stream; -import com.symphony.bdk.gen.api.model.StreamAttributes; -import com.symphony.bdk.gen.api.model.StreamFilter; import com.symphony.bdk.gen.api.model.V2AdminStreamFilter; import com.symphony.bdk.gen.api.model.V2AdminStreamList; import com.symphony.bdk.gen.api.model.V2MembershipList; -import com.symphony.bdk.gen.api.model.V2Message; import com.symphony.bdk.gen.api.model.V2RoomSearchCriteria; -import com.symphony.bdk.gen.api.model.V2StreamAttributes; import com.symphony.bdk.gen.api.model.V3RoomAttributes; import com.symphony.bdk.gen.api.model.V3RoomDetail; import com.symphony.bdk.gen.api.model.V3RoomSearchResults; @@ -48,12 +41,9 @@ @API(status = API.Status.STABLE) public class StreamService extends OboStreamService { - private final AuthSession authSession; - public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, ShareApi shareApi, AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - super(streamsApi, membershipApi, shareApi, retryBuilder); - this.authSession = authSession; + super(streamsApi, membershipApi, shareApi, authSession, retryBuilder); } /** @@ -155,29 +145,6 @@ public V3RoomDetail updateRoom(String roomId, V3RoomAttributes roomAttributes) { () -> streamsApi.v3RoomIdUpdatePost(roomId, authSession.getSessionToken(), roomAttributes)); } - /** - * Retrieve a list of all streams of which the requesting user is a member, - * sorted by creation date (ascending). - * - * @param filter The stream searching criteria - * @return The list of streams retrieved according to the searching criteria. - * @see List Streams - */ - public List listStreams(StreamFilter filter) { - return this.listStreams(this.authSession, filter); - } - - /** - * Get information about a particular stream. - * - * @param streamId The stream id - * @return The information about the stream with the given id. - * @see Stream Info V2 - */ - public V2StreamAttributes getStreamInfo(String streamId) { - return this.getStreamInfo(this.authSession, streamId); - } - /** * Create a new single or multi party instant message conversation. * At least two user IDs must be provided or an error response will be sent. @@ -247,65 +214,4 @@ public List listRoomMembers(String roomId) { return executeAndRetry("listRoomMembers", () -> roomMembershipApi.v2RoomIdMembershipListGet(roomId, authSession.getSessionToken())); } - - /** - * Adds a new member to an existing room. - * - * @param userId The id of the user to be added to the given room - * @param roomId The room id - * @see Add Member - */ - public void addMemberToRoom(Long userId, String roomId) { - this.addMemberToRoom(this.authSession, userId, roomId); - } - - /** - * Removes an existing member from an existing room. - * - * @param userId The id of the user to be removed from the given room - * @param roomId The room id - * @see Remove Member - */ - public void removeMemberFromRoom(Long userId, String roomId) { - this.removeMemberFromRoom(this.authSession, userId, roomId); - } - - /** - * Share third-party content, such as a news article, into the specified stream. - * The stream can be a chat room, an IM, or an MIM. - * - * @param streamId The stream id. - * @param content The third-party {@link ShareContent} to be shared. - * @return Message contains share content - * @see Share - */ - public V2Message share(String streamId, ShareContent content) { - return this.share(this.authSession, streamId, content); - } - - /** - * Promotes user to owner of the chat room. - * - * @param userId The id of the user to be promoted to room owner. - * @param roomId The room id - * @see Promote Owner - */ - public void promoteUserToRoomOwner(Long userId, String roomId) { - this.promoteUserToRoomOwner(this.authSession, userId, roomId); - } - - /** - * Demotes room owner to a participant in the chat room. - * - * @param userId The id of the user to be demoted to room participant. - * @param roomId The room id. - * @see Demote Owner - */ - public void demoteUserToRoomParticipant(Long userId, String roomId) { - this.demoteUserToRoomParticipant(this.authSession, userId, roomId); - } - - private T executeAndRetry(String name, SupplierWithApiException supplier) { - return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); - } } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java index 2acda3801..4586edf98 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java @@ -20,23 +20,27 @@ import javax.annotation.Nullable; +/** + * Service class for managing users. This exposes OBO-enabled endpoints only. + */ @API(status = API.Status.INTERNAL) -class OboUserService { +public class OboUserService { protected final UserApi userApi; protected final UsersApi usersApi; + protected final AuthSession authSession; protected final RetryWithRecoveryBuilder retryBuilder; - protected OboUserService(UserApi userApi, UsersApi usersApi, RetryWithRecoveryBuilder retryBuilder) { + public OboUserService(UserApi userApi, UsersApi usersApi,AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { this.userApi = userApi; this.usersApi = usersApi; + this.authSession = authSession; this.retryBuilder = retryBuilder; } /** * {@link UserService#searchUserByIds(List, Boolean)} * - * @param authSession Bot session or Obo Session * @param uidList List of user ids * @param local If true then a local DB search will be performed and only local pod users will be * returned. If absent or false then a directory search will be performed and users @@ -44,33 +48,31 @@ protected OboUserService(UserApi userApi, UsersApi usersApi, RetryWithRecoveryBu * @return Users found by user ids * @see Users Lookup V3 */ - public List searchUserByIds(@NonNull AuthSession authSession, @NonNull List uidList, + public List searchUserByIds(@NonNull List uidList, @NonNull Boolean local) { String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); V2UserList v2UserList = executeAndRetry("searchUserByIds", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, local), authSession); + () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, local)); return v2UserList.getUsers(); } /** * {@link UserService#searchUserByIds(List)} * - * @param authSession Bot Session or Obo Session * @param uidList List of user ids * @return Users found by user ids * @see Users Lookup V3 */ - public List searchUserByIds(@NonNull AuthSession authSession, @NonNull List uidList) { + public List searchUserByIds(@NonNull List uidList) { String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); V2UserList v2UserList = executeAndRetry("searchUserByIds", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, false), authSession); + () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, false)); return v2UserList.getUsers(); } /** * {@link UserService#searchUserByEmails(List, Boolean)} * - * @param authSession Bot Session or Obo Session * @param emailList List of emails * @param local If true then a local DB search will be performed and only local pod users will be * returned. If absent or false then a directory search will be performed and users @@ -78,48 +80,45 @@ public List searchUserByIds(@NonNull AuthSession authSession, @NonNull L * @return Users found by emails. * @see Users Lookup V3 */ - public List searchUserByEmails(@NonNull AuthSession authSession, @NonNull List emailList, + public List searchUserByEmails(@NonNull List emailList, @NonNull Boolean local) { String emails = String.join(",", emailList); V2UserList v2UserList = executeAndRetry("searchUserByEmails", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, local), authSession); + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, local)); return v2UserList.getUsers(); } /** * {@link UserService#searchUserByEmails(List)} * - * @param authSession Bot Session or Obo Session * @param emailList List of emails * @return Users found by emails * @see Users Lookup V3 */ - public List searchUserByEmails(@NonNull AuthSession authSession, @NonNull List emailList) { + public List searchUserByEmails(@NonNull List emailList) { String emails = String.join(",", emailList); V2UserList v2UserList = executeAndRetry("searchUserByEmails", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, false), authSession); + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, false)); return v2UserList.getUsers(); } /** * {@link UserService#searchUserByUsernames(List)} * - * @param authSession Bot Session or Obo Session * @param usernameList List of usernames * @return Users found by usernames * @see Users Lookup V3 */ - public List searchUserByUsernames(@NonNull AuthSession authSession, @NonNull List usernameList) { + public List searchUserByUsernames(@NonNull List usernameList) { String usernames = String.join(",", usernameList); V2UserList v2UserList = executeAndRetry("searchUserByUsernames", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, null, usernames, true), authSession); + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, null, usernames, true)); return v2UserList.getUsers(); } /** * {@link UserService#searchUserBySearchQuery(UserSearchQuery, Boolean)} * - * @param authSession Bot Session or Obo Session * @param query Searching query containing complicated information like title, location, company... * @param local If true then a local DB search will be performed and only local pod users will be * returned. If absent or false then a directory search will be performed and users @@ -127,14 +126,14 @@ public List searchUserByUsernames(@NonNull AuthSession authSession, @Non * @return List of users found by query * @see Search Users */ - public List searchUserBySearchQuery(@NonNull AuthSession authSession, @NonNull UserSearchQuery query, + public List searchUserBySearchQuery(@NonNull UserSearchQuery query, @Nullable Boolean local) { UserSearchResults results = executeAndRetry("searchUserBySearchQuery", - () -> usersApi.v1UserSearchPost(authSession.getSessionToken(), query, null, null, local), authSession); + () -> usersApi.v1UserSearchPost(authSession.getSessionToken(), query, null, null, local)); return results.getUsers(); } - protected T executeAndRetry(String name, SupplierWithApiException supplier, AuthSession authSession) { + protected T executeAndRetry(String name, SupplierWithApiException supplier) { final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) .clearRecoveryStrategies() // to remove refresh on bot session put by default .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java index 92b44842c..6f32d9760 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java @@ -1,11 +1,9 @@ package com.symphony.bdk.core.service.user; import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; import com.symphony.bdk.core.service.user.constant.RoleId; import com.symphony.bdk.core.service.user.mapper.UserDetailMapper; -import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.UserApi; import com.symphony.bdk.gen.api.UsersApi; import com.symphony.bdk.gen.api.model.Avatar; @@ -16,9 +14,7 @@ import com.symphony.bdk.gen.api.model.StringId; import com.symphony.bdk.gen.api.model.UserDetail; import com.symphony.bdk.gen.api.model.UserFilter; -import com.symphony.bdk.gen.api.model.UserSearchQuery; import com.symphony.bdk.gen.api.model.UserStatus; -import com.symphony.bdk.gen.api.model.UserV2; import com.symphony.bdk.gen.api.model.V2UserDetail; import lombok.NonNull; @@ -32,8 +28,6 @@ import java.util.List; import java.util.stream.Collectors; -import javax.annotation.Nullable; - /** * Service class for managing users. @@ -53,11 +47,8 @@ @API(status = API.Status.STABLE) public class UserService extends OboUserService { - private final AuthSession authSession; - public UserService(UserApi userApi, UsersApi usersApi, AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - super(userApi, usersApi, retryBuilder); - this.authSession = authSession; + super(userApi, usersApi, authSession, retryBuilder); } /** @@ -284,83 +275,4 @@ public void updateStatusOfUser(@NonNull Long uid, @NonNull UserStatus status) { executeAndRetry("updateStatusOfUser", () -> userApi.v1AdminUserUidStatusUpdatePost(authSession.getSessionToken(), uid, status)); } - - /** - * Search user by list of user ids - * - * @param uidList List of user ids - * @param local If true then a local DB search will be performed and only local pod users will be - * returned. If absent or false then a directory search will be performed and users - * from other pods who are visible to the calling user will also be returned. - * @return Users found by user ids - * @see Users Lookup V3 - */ - public List searchUserByIds(@NonNull List uidList, @NonNull Boolean local) { - return this.searchUserByIds(this.authSession, uidList, local); - } - - /** - * Search user by list of user ids - * - * @param uidList List of user ids - * @return Users found by user ids - * @see Users Lookup V3 - */ - public List searchUserByIds(@NonNull List uidList) { - return this.searchUserByIds(this.authSession, uidList); - } - - /** - * Search user by list of email addresses. - * - * @param emailList List of email addresses - * @param local If true then a local DB search will be performed and only local pod users will be - * returned. If absent or false then a directory search will be performed and users - * from other pods who are visible to the calling user will also be returned. - * @return Users found by emails. - * @see Users Lookup V3 - */ - public List searchUserByEmails(@NonNull List emailList, @NonNull Boolean local) { - return this.searchUserByEmails(this.authSession, emailList, local); - } - - /** - * Search user by list of email addresses. - * - * @param emailList List of email addresses - * @return Users found by emails. - * @see Users Lookup V3 - */ - public List searchUserByEmails(@NonNull List emailList) { - return this.searchUserByEmails(this.authSession, emailList); - } - - /** - * Search user by list of usernames. - * - * @param usernameList List of usernames - * @return Users found by usernames - * @see Users Lookup V3 - */ - public List searchUserByUsernames(@NonNull List usernameList) { - return this.searchUserByUsernames(this.authSession, usernameList); - } - - /** - * Search user by a complicated search query. - * - * @param query Searching query containing complicated information like title, location, company... - * @param local If true then a local DB search will be performed and only local pod users will be - * returned. If absent or false then a directory search will be performed and users - * from other pods who are visible to the calling user will also be returned. - * @return List of users found by query - * @see Search Users - */ - public List searchUserBySearchQuery(@NonNull UserSearchQuery query, @Nullable Boolean local) { - return this.searchUserBySearchQuery(this.authSession, query, local); - } - - private T executeAndRetry(String name, SupplierWithApiException supplier) { - return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); - } } diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java new file mode 100644 index 000000000..101a61921 --- /dev/null +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java @@ -0,0 +1,38 @@ +package com.symphony.bdk.core; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; + +import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.client.ApiClientFactory; +import com.symphony.bdk.core.config.BdkConfigLoader; +import com.symphony.bdk.core.config.exception.BdkConfigException; +import com.symphony.bdk.core.config.model.BdkConfig; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class OboServiceFactoryTest { + + private OboServiceFactory oboServiceFactory; + + @BeforeEach + void setUp() throws BdkConfigException { + this.oboServiceFactory = new OboServiceFactory(mock(ApiClientFactory.class), mock(AuthSession.class), new BdkConfig()); + } + + @Test + void getOboUserServiceTest() { + assertNotNull(this.oboServiceFactory.getObUserService()); + } + + @Test + void getOboStreamServiceTest() { + assertNotNull(this.oboServiceFactory.getOboStreamService()); + } + + @Test + void getOboMessageServiceTest() { + assertNotNull(this.oboServiceFactory.getOboMessageService()); + } +} diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java new file mode 100644 index 000000000..9a0b27765 --- /dev/null +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java @@ -0,0 +1,36 @@ +package com.symphony.bdk.core; + +import static org.mockito.Mockito.mock; + +import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.config.model.BdkConfig; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class OboServicesFacadeTest { + + private OboServicesFacade oboServicesFacade; + + @BeforeEach + void setUp() { + oboServicesFacade = new OboServicesFacade(new BdkConfig(), mock(AuthSession.class)); + Assertions.assertNotNull(oboServicesFacade.messages()); + } + + @Test + void testOboStreams() { + Assertions.assertNotNull(oboServicesFacade.streams()); + } + + @Test + void testOboUsers() { + Assertions.assertNotNull(oboServicesFacade.users()); + } + + @Test + void testOboMessages() { + Assertions.assertNotNull(oboServicesFacade.messages()); + } +} diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java index dce01013b..3b9647128 100644 --- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java @@ -1,8 +1,6 @@ package com.symphony.bdk.core; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -103,6 +101,17 @@ void getHttpClientBuilderTest() { assertNotNull(builder); } + @Test + void getOboServiceFacade() throws AuthUnauthorizedException { + this.mockApiClient.onPost(LOGIN_PUBKEY_APP_AUTHENTICATE, "{ \"token\": \"1234\", \"name\": \"sessionToken\" }"); + this.mockApiClient.onPost(LOGIN_PUBKEY_OBO_USERID_AUTHENTICATE.replace("{userId}", "123456"), "{ \"token\": \"1234\", \"name\": \"sessionToken\" }"); + + AuthSession oboSession = this.symphonyBdk.obo(123456L); + final OboServicesFacade obo = this.symphonyBdk.obo(oboSession); + + assertNotNull(obo); + } + @Test void oboAuthenticateTest() throws AuthUnauthorizedException { this.mockApiClient.onPost(LOGIN_PUBKEY_APP_AUTHENTICATE, "{ \"token\": \"1234\", \"name\": \"sessionToken\" }"); diff --git a/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/AuthMain.java b/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/AuthMain.java index 40b5b7022..40e2b19d7 100644 --- a/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/AuthMain.java +++ b/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/AuthMain.java @@ -7,11 +7,14 @@ import com.symphony.bdk.core.auth.exception.AuthInitializationException; import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException; import com.symphony.bdk.core.config.exception.BdkConfigException; +import com.symphony.bdk.core.service.message.model.Message; import com.symphony.bdk.gen.api.model.StreamFilter; import com.symphony.bdk.gen.api.model.V4Message; import lombok.extern.slf4j.Slf4j; +import java.util.Arrays; + /** * This very basic example demonstrates how send a message using both regular and OBO authentication modes. */ @@ -19,7 +22,7 @@ public class AuthMain { private static final String STREAM = "2IFEMquh3pOHAxcgLF8jU3___ozwgwIVdA"; - private static final String MESSAGE = "Hello, World!"; + private static final Message MESSAGE = Message.builder().content("Hello, World").build(); public static void main(String[] args) throws BdkConfigException, AuthInitializationException, AuthUnauthorizedException { @@ -31,6 +34,9 @@ public static void main(String[] args) throws BdkConfigException, AuthInitializa log.info("Regular message sent : {}", regularMessage.getMessageId()); AuthSession oboSession = bdk.obo("user.name"); - bdk.streams().listStreams(oboSession, new StreamFilter()); + + bdk.obo(oboSession).streams().listStreams(new StreamFilter()); + bdk.obo(oboSession).messages().send(STREAM, MESSAGE); + bdk.obo(oboSession).users().searchUserByUsernames(Arrays.asList("user.name")); } } diff --git a/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/UserExampleMain.java b/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/UserExampleMain.java index 8220c48bd..aafc402cf 100644 --- a/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/UserExampleMain.java +++ b/symphony-bdk-examples/bdk-core-examples/src/main/java/com/symphony/bdk/examples/UserExampleMain.java @@ -38,7 +38,7 @@ public static void main(String[] args) throws Exception { AuthSession oboSession = bdk.obo("hong.le"); StreamFilter streamFilter = new StreamFilter().addStreamTypesItem(new StreamType().type(StreamType.TypeEnum.IM)); - List streamsList = bdk.streams().listStreams(oboSession, streamFilter); + List streamsList = bdk.obo(oboSession).streams().listStreams(streamFilter); log.info("Streams List: {}", streamsList); } } From 5cbe499375e7f541344bb20b4a007129c15f4564 Mon Sep 17 00:00:00 2001 From: Elias Croze Date: Tue, 13 Oct 2020 15:16:46 +0200 Subject: [PATCH 2/5] Refactored OBO service classes --- .../symphony/bdk/core/OboServiceFactory.java | 80 ------------ .../symphony/bdk/core/OboServicesFacade.java | 8 +- .../symphony/bdk/core/service/OboService.java | 22 ++++ .../core/service/message/MessageService.java | 116 +++++++++++++++++- .../service/message/OboMessageService.java | 100 ++------------- .../core/service/stream/OboStreamService.java | 74 ++--------- .../core/service/stream/StreamService.java | 95 +++++++++++++- .../bdk/core/service/user/OboUserService.java | 79 ++---------- .../bdk/core/service/user/UserService.java | 105 +++++++++++++++- .../bdk/core/OboServiceFactoryTest.java | 38 ------ 10 files changed, 360 insertions(+), 357 deletions(-) delete mode 100644 symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java create mode 100644 symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java delete mode 100644 symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java deleted file mode 100644 index d35fb618d..000000000 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServiceFactory.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.symphony.bdk.core; - -import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.client.ApiClientFactory; -import com.symphony.bdk.core.config.model.BdkConfig; -import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.service.message.OboMessageService; -import com.symphony.bdk.core.service.stream.OboStreamService; -import com.symphony.bdk.core.service.user.OboUserService; -import com.symphony.bdk.gen.api.MessagesApi; -import com.symphony.bdk.gen.api.RoomMembershipApi; -import com.symphony.bdk.gen.api.ShareApi; -import com.symphony.bdk.gen.api.StreamsApi; -import com.symphony.bdk.gen.api.UserApi; -import com.symphony.bdk.gen.api.UsersApi; -import com.symphony.bdk.http.api.ApiClient; -import com.symphony.bdk.http.api.ApiException; -import com.symphony.bdk.template.api.TemplateEngine; - -import org.apiguardian.api.API; - -/** - * Factory responsible for creating BDK OBO-enabled service instances for {@link OboServicesFacade}. - * : - *
    - *
  • {@link OboUserService}
  • - *
  • {@link OboStreamService}
  • - *
  • {@link OboMessageService}
  • - *
- */ -@API(status = API.Status.INTERNAL) -public class OboServiceFactory { - - protected final ApiClient podClient; - protected final ApiClient agentClient; - protected final AuthSession authSession; - protected final TemplateEngine templateEngine; - protected final BdkConfig config; - protected final RetryWithRecoveryBuilder retryBuilder; - - public OboServiceFactory(ApiClientFactory apiClientFactory, AuthSession authSession, BdkConfig config) { - this.podClient = apiClientFactory.getPodClient(); - this.agentClient = apiClientFactory.getAgentClient(); - this.authSession = authSession; - this.templateEngine = TemplateEngine.getDefaultImplementation(); - this.config = config; - this.retryBuilder = new RetryWithRecoveryBuilder<>() - .retryConfig(config.getRetry()) - .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); - } - - /** - * Returns a fully initialized {@link OboUserService} - * - * @return a new {@link OboUserService} instance - */ - public OboUserService getObUserService() { - return new OboUserService(new UserApi(podClient), new UsersApi(podClient), authSession, retryBuilder); - } - - /** - * Returns a fully initialized {@link OboStreamService} - * - * @return a new {@link OboStreamService} instance - */ - public OboStreamService getOboStreamService() { - return new OboStreamService(new StreamsApi(podClient), new RoomMembershipApi(podClient), new ShareApi(agentClient), - authSession, retryBuilder); - } - - /** - * Returns a fully initialized {@link OboMessageService} - * - * @return a new {@link OboMessageService} instance - */ - public OboMessageService getOboMessageService() { - return new OboMessageService(new MessagesApi(this.agentClient), this.authSession, this.templateEngine, - this.retryBuilder); - } -} diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java index cdf5288d8..8e08fee90 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java @@ -20,11 +20,11 @@ public class OboServicesFacade { private final OboMessageService oboMessageService; public OboServicesFacade(BdkConfig config, AuthSession oboSession) { - final OboServiceFactory serviceFactory = new OboServiceFactory(new ApiClientFactory(config), oboSession, config); + final ServiceFactory serviceFactory = new ServiceFactory(new ApiClientFactory(config), oboSession, config); - oboStreamService = serviceFactory.getOboStreamService(); - oboUserService = serviceFactory.getObUserService(); - oboMessageService = serviceFactory.getOboMessageService(); + oboStreamService = serviceFactory.getStreamService(); + oboUserService = serviceFactory.getUserService(); + oboMessageService = serviceFactory.getMessageService(); } /** diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java new file mode 100644 index 000000000..44acad23b --- /dev/null +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java @@ -0,0 +1,22 @@ +package com.symphony.bdk.core.service; + +import com.symphony.bdk.core.auth.AuthSession; + +import org.apiguardian.api.API; + +/** + * Interface which returns an OBO-enabled service class from a given obo session. + * + * @param type returned by the {@link #obo(AuthSession)} function. + */ +@API(status = API.Status.INTERNAL) +public interface OboService { + + /** + * Returns a new service instance with OBO-enabled endpoints from a given obo session. + * + * @param oboSession the obo session + * @return the instance of the service class with OBO-enabled endpoints + */ + S obo(AuthSession oboSession); +} diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java index 2ce18d509..5cf46743c 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/MessageService.java @@ -1,10 +1,18 @@ package com.symphony.bdk.core.service.message; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; +import com.symphony.bdk.core.service.OboService; +import com.symphony.bdk.core.service.message.model.Attachment; +import com.symphony.bdk.core.service.message.model.Message; import com.symphony.bdk.core.service.pagination.PaginatedApi; import com.symphony.bdk.core.service.pagination.PaginatedService; import com.symphony.bdk.core.service.stream.constant.AttachmentSort; +import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.AttachmentsApi; import com.symphony.bdk.gen.api.DefaultApi; import com.symphony.bdk.gen.api.MessageApi; @@ -22,14 +30,21 @@ import com.symphony.bdk.gen.api.model.V4ImportedMessage; import com.symphony.bdk.gen.api.model.V4Message; import com.symphony.bdk.gen.api.model.V4Stream; +import com.symphony.bdk.http.api.ApiClient; +import com.symphony.bdk.http.api.ApiClientBodyPart; +import com.symphony.bdk.http.api.ApiException; import com.symphony.bdk.http.api.util.ApiUtils; +import com.symphony.bdk.http.api.util.TypeReference; import com.symphony.bdk.template.api.TemplateEngine; import lombok.extern.slf4j.Slf4j; import org.apiguardian.api.API; +import java.io.File; import java.time.Instant; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -41,14 +56,18 @@ */ @Slf4j @API(status = API.Status.STABLE) -public class MessageService extends OboMessageService { +public class MessageService implements OboMessageService, OboService { + private final MessagesApi messagesApi; private final MessageApi messageApi; private final MessageSuppressionApi messageSuppressionApi; private final StreamsApi streamsApi; private final PodApi podApi; private final AttachmentsApi attachmentsApi; private final DefaultApi defaultApi; + private final AuthSession authSession; + private final TemplateEngine templateEngine; + private final RetryWithRecoveryBuilder retryBuilder; public MessageService( final MessagesApi messagesApi, @@ -62,13 +81,30 @@ public MessageService( final TemplateEngine templateEngine, final RetryWithRecoveryBuilder retryBuilder ) { - super(messagesApi, authSession, templateEngine, retryBuilder); + this.messagesApi = messagesApi; this.messageApi = messageApi; this.messageSuppressionApi = messageSuppressionApi; this.streamsApi = streamsApi; this.podApi = podApi; this.attachmentsApi = attachmentsApi; + this.authSession = authSession; + this.templateEngine = templateEngine; this.defaultApi = defaultApi; + this.retryBuilder = retryBuilder; + } + + @Override + public OboMessageService obo(AuthSession oboSession) { + return new MessageService(messagesApi, messageApi, messageSuppressionApi, streamsApi, podApi, attachmentsApi, + defaultApi, oboSession, templateEngine, retryBuilder); + } + + /** + * {@inheritDoc} + */ + @Override + public TemplateEngine templates() { + return this.templateEngine; } /** @@ -135,6 +171,78 @@ public Stream getMessagesStream(@Nonnull String streamId, @Nonnull In return new PaginatedService<>(api, actualChunkSize, actualTotalSize).stream(); } + /** + * {@inheritDoc} + */ + @Override + public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) { + return send(stream.getStreamId(), message); + } + + /** + * {@inheritDoc} + */ + @Override + public V4Message send(@Nonnull String streamId, @Nonnull String message) { + return this.send(streamId, Message.builder().content(message).build()); + } + + /** + * {@inheritDoc} + */ + @Override + public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) { + return this.send(stream.getStreamId(), message); + } + + /** + * {@inheritDoc} + */ + @Override + public V4Message send(@Nonnull String streamId, @Nonnull Message message) { + return this.executeAndRetry("send", () -> + this.doSend(streamId, message, this.authSession.getSessionToken(), this.authSession.getKeyManagerToken()) + ); + } + + /** + * The generated {@link MessagesApi#v4StreamSidMessageCreatePost(String, String, String, String, String, String, File, File)} + * does not allow to send multiple attachments as well as in-memory files, so we have to "manually" process this call. + */ + private V4Message doSend(String streamId, Message message, String sessionToken, String keyManagerToken) throws ApiException { + final ApiClient apiClient = this.messagesApi.getApiClient(); + final Map form = new HashMap<>(); + form.put("message", message.getContent()); + form.put("data", message.getData()); + form.put("version", message.getVersion()); + form.put("attachment", toApiClientBodyParts(message.getAttachments())); + form.put("preview", toApiClientBodyParts(message.getPreviews())); + + final Map headers = new HashMap<>(); + headers.put("sessionToken", apiClient.parameterToString(sessionToken)); + headers.put("keyManagerToken", apiClient.parameterToString(keyManagerToken)); + + return apiClient.invokeAPI( + "/v4/stream/" + apiClient.escapeString(streamId) + "/message/create", + "POST", + emptyList(), + null, // for 'multipart/form-data', body can be null + headers, + emptyMap(), + form, + apiClient.selectHeaderAccept("application/json"), + apiClient.selectHeaderContentType("multipart/form-data"), + new String[0], + new TypeReference() {} + ).getData(); + } + + private static ApiClientBodyPart[] toApiClientBodyParts(List attachments) { + return attachments.stream() + .map(a -> new ApiClientBodyPart(a.getContent(), a.getFilename())) + .toArray(ApiClientBodyPart[]::new); + } + /** * Downloads the attachment body by the stream ID, message ID and attachment ID. * @@ -299,4 +407,8 @@ public MessageMetadataResponse getMessageRelationships(@Nonnull String messageId private static Long getEpochMillis(Instant instant) { return instant == null ? null : instant.toEpochMilli(); } + + private T executeAndRetry(String name, SupplierWithApiException supplier) { + return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); + } } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java index d551735db..7191a8e3b 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/message/OboMessageService.java @@ -1,61 +1,28 @@ package com.symphony.bdk.core.service.message; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; - -import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; -import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.service.message.model.Attachment; import com.symphony.bdk.core.service.message.model.Message; -import com.symphony.bdk.core.util.function.SupplierWithApiException; -import com.symphony.bdk.gen.api.MessagesApi; import com.symphony.bdk.gen.api.model.V4Message; import com.symphony.bdk.gen.api.model.V4Stream; -import com.symphony.bdk.http.api.ApiClient; -import com.symphony.bdk.http.api.ApiClientBodyPart; -import com.symphony.bdk.http.api.ApiException; -import com.symphony.bdk.http.api.util.TypeReference; import com.symphony.bdk.template.api.TemplateEngine; import org.apiguardian.api.API; -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import javax.annotation.Nonnull; /** - * Service class for managing messages. This exposed OBO-enabled endpoints only. + * Service interface exposing OBO-enabled endpoints to manage messages. * * @see Message API */ @API(status = API.Status.STABLE) -public class OboMessageService { - - protected final MessagesApi messagesApi; - protected final AuthSession authSession; - private final TemplateEngine templateEngine; - private final RetryWithRecoveryBuilder retryBuilder; - - public OboMessageService(MessagesApi messagesApi, AuthSession authSession, TemplateEngine templateEngine, - RetryWithRecoveryBuilder retryBuilder) { - this.messagesApi = messagesApi; - this.authSession = authSession; - this.templateEngine = templateEngine; - this.retryBuilder = retryBuilder; - } +public interface OboMessageService { /** * Returns the {@link TemplateEngine} that can be used to load templates from classpath or file system. * * @return the template engine */ - public TemplateEngine templates() { - return this.templateEngine; - } + TemplateEngine templates(); /** * Sends a message to the stream ID of the passed {@link V4Stream} object. @@ -68,9 +35,7 @@ public TemplateEngine templates() { */ @Deprecated @API(status = API.Status.DEPRECATED) - public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) { - return send(stream.getStreamId(), message); - } + V4Message send(@Nonnull V4Stream stream, @Nonnull String message); /** * Sends a message to the stream ID passed in parameter. @@ -83,9 +48,7 @@ public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) { */ @Deprecated @API(status = API.Status.DEPRECATED) - public V4Message send(@Nonnull String streamId, @Nonnull String message) { - return this.send(streamId, Message.builder().content(message).build()); - } + V4Message send(@Nonnull String streamId, @Nonnull String message); /** * Sends a message to the stream ID passed in parameter. @@ -95,9 +58,7 @@ public V4Message send(@Nonnull String streamId, @Nonnull String message) { * @return a {@link V4Message} object containing the details of the sent message * @see Create Message v4 */ - public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) { - return this.send(stream.getStreamId(), message); - } + V4Message send(@Nonnull V4Stream stream, @Nonnull Message message); /** * Sends a message to the stream ID passed in parameter. @@ -107,52 +68,5 @@ public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) { * @return a {@link V4Message} object containing the details of the sent message * @see Create Message v4 */ - public V4Message send(@Nonnull String streamId, @Nonnull Message message) { - return this.executeAndRetry("send", () -> - this.doSend(streamId, message, this.authSession.getSessionToken(), this.authSession.getKeyManagerToken()) - ); - } - - protected T executeAndRetry(String name, SupplierWithApiException supplier) { - return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier); - } - - /** - * The generated {@link MessagesApi#v4StreamSidMessageCreatePost(String, String, String, String, String, String, File, File)} - * does not allow to send multiple attachments as well as in-memory files, so we have to "manually" process this call. - */ - private V4Message doSend(String streamId, Message message, String sessionToken, String keyManagerToken) throws - ApiException { - final ApiClient apiClient = this.messagesApi.getApiClient(); - final Map form = new HashMap<>(); - form.put("message", message.getContent()); - form.put("data", message.getData()); - form.put("version", message.getVersion()); - form.put("attachment", toApiClientBodyParts(message.getAttachments())); - form.put("preview", toApiClientBodyParts(message.getPreviews())); - - final Map headers = new HashMap<>(); - headers.put("sessionToken", apiClient.parameterToString(sessionToken)); - headers.put("keyManagerToken", apiClient.parameterToString(keyManagerToken)); - - return apiClient.invokeAPI( - "/v4/stream/" + apiClient.escapeString(streamId) + "/message/create", - "POST", - emptyList(), - null, // for 'multipart/form-data', body can be null - headers, - emptyMap(), - form, - apiClient.selectHeaderAccept("application/json"), - apiClient.selectHeaderContentType("multipart/form-data"), - new String[0], - new TypeReference() {} - ).getData(); - } - - private static ApiClientBodyPart[] toApiClientBodyParts(List attachments) { - return attachments.stream() - .map(a -> new ApiClientBodyPart(a.getContent(), a.getFilename())) - .toArray(ApiClientBodyPart[]::new); - } + V4Message send(@Nonnull String streamId, @Nonnull Message message); } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java index 71f916004..505fdd746 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/OboStreamService.java @@ -1,44 +1,20 @@ package com.symphony.bdk.core.service.stream; -import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; -import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.util.function.SupplierWithApiException; -import com.symphony.bdk.gen.api.RoomMembershipApi; -import com.symphony.bdk.gen.api.ShareApi; -import com.symphony.bdk.gen.api.StreamsApi; import com.symphony.bdk.gen.api.model.ShareContent; import com.symphony.bdk.gen.api.model.StreamAttributes; import com.symphony.bdk.gen.api.model.StreamFilter; -import com.symphony.bdk.gen.api.model.UserId; import com.symphony.bdk.gen.api.model.V2Message; import com.symphony.bdk.gen.api.model.V2StreamAttributes; -import com.symphony.bdk.http.api.ApiException; import org.apiguardian.api.API; import java.util.List; /** - * Service class for managing streams. This exposes OBO-enabled endpoints only. + * Service interface exposing OBO-enabled endpoints to manage streams. */ @API(status = API.Status.STABLE) -public class OboStreamService { - - protected final StreamsApi streamsApi; - protected final RoomMembershipApi roomMembershipApi; - protected final ShareApi shareApi; - protected final AuthSession authSession; - protected final RetryWithRecoveryBuilder retryBuilder; - - public OboStreamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipApi, ShareApi shareApi, - AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - this.streamsApi = streamsApi; - this.roomMembershipApi = roomMembershipApi; - this.shareApi = shareApi; - this.authSession = authSession; - this.retryBuilder = retryBuilder; - } +public interface OboStreamService { /** * {@link StreamService#getStreamInfo(String)} @@ -47,10 +23,7 @@ public OboStreamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipA * @return The information about the stream with the given id. * @see Stream Info V2 */ - public V2StreamAttributes getStreamInfo(String streamId) { - return executeAndRetry("getStreamInfo", - () -> streamsApi.v2StreamsSidInfoGet(streamId, authSession.getSessionToken())); - } + V2StreamAttributes getStreamInfo(String streamId); /** * {@link StreamService#listStreams(StreamFilter)} @@ -59,10 +32,7 @@ public V2StreamAttributes getStreamInfo(String streamId) { * @return The list of streams retrieved according to the searching criteria. * @see List Streams */ - public List listStreams(StreamFilter filter) { - return executeAndRetry("listStreams", - () -> streamsApi.v1StreamsListPost(authSession.getSessionToken(), null, null, filter)); - } + List listStreams(StreamFilter filter); /** * {@link StreamService#addMemberToRoom(Long, String)} @@ -71,11 +41,7 @@ public List listStreams(StreamFilter filter) { * @param roomId The room id * @see Add Member */ - public void addMemberToRoom( Long userId, String roomId) { - UserId user = new UserId().id(userId); - executeAndRetry("addMemberToRoom", - () -> roomMembershipApi.v1RoomIdMembershipAddPost(roomId, authSession.getSessionToken(), user)); - } + void addMemberToRoom( Long userId, String roomId); /** * {@link StreamService#removeMemberFromRoom(Long, String)} @@ -84,11 +50,7 @@ public void addMemberToRoom( Long userId, String roomId) { * @param roomId The room id * @see Remove Member */ - public void removeMemberFromRoom(Long userId, String roomId) { - UserId user = new UserId().id(userId); - executeAndRetry("removeMemberFrom", - () -> roomMembershipApi.v1RoomIdMembershipRemovePost(roomId, authSession.getSessionToken(), user)); - } + void removeMemberFromRoom(Long userId, String roomId); /** * {@link StreamService#share(String, ShareContent)} @@ -98,10 +60,7 @@ public void removeMemberFromRoom(Long userId, String roomId) { * @return Message contains share content * @see Share */ - public V2Message share(String streamId, ShareContent content) { - return executeAndRetry("share", - () -> shareApi.v3StreamSidSharePost(streamId, authSession.getSessionToken(), content, authSession.getKeyManagerToken())); - } + V2Message share(String streamId, ShareContent content); /** * {@link StreamService#promoteUserToRoomOwner(Long, String)} @@ -110,11 +69,7 @@ public V2Message share(String streamId, ShareContent content) { * @param roomId The room id. * @see Promote Owner */ - public void promoteUserToRoomOwner(Long userId, String roomId) { - UserId user = new UserId().id(userId); - executeAndRetry("promoteUserToOwner", - () -> roomMembershipApi.v1RoomIdMembershipPromoteOwnerPost(roomId, authSession.getSessionToken(), user)); - } + void promoteUserToRoomOwner(Long userId, String roomId); /** * {@link StreamService#demoteUserToRoomParticipant(Long, String)} @@ -123,16 +78,5 @@ public void promoteUserToRoomOwner(Long userId, String roomId) { * @param roomId The room id. * @see Demote Owner */ - public void demoteUserToRoomParticipant(Long userId, String roomId) { - UserId user = new UserId().id(userId); - executeAndRetry("demoteUserToParticipant", - () -> roomMembershipApi.v1RoomIdMembershipDemoteOwnerPost(roomId, authSession.getSessionToken(), user)); - } - - protected T executeAndRetry(String name, SupplierWithApiException supplier) { - final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) - .clearRecoveryStrategies() // to remove refresh on bot session put by default - .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); - return RetryWithRecovery.executeAndRetry(retryBuilderWithAuthSession, name, supplier); - } + void demoteUserToRoomParticipant(Long userId, String roomId); } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java index 7789e8663..05d9d174e 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java @@ -1,17 +1,26 @@ package com.symphony.bdk.core.service.stream; import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; +import com.symphony.bdk.core.service.OboService; +import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.RoomMembershipApi; import com.symphony.bdk.gen.api.ShareApi; import com.symphony.bdk.gen.api.StreamsApi; import com.symphony.bdk.gen.api.model.MemberInfo; import com.symphony.bdk.gen.api.model.RoomDetail; +import com.symphony.bdk.gen.api.model.ShareContent; import com.symphony.bdk.gen.api.model.Stream; +import com.symphony.bdk.gen.api.model.StreamAttributes; +import com.symphony.bdk.gen.api.model.StreamFilter; +import com.symphony.bdk.gen.api.model.UserId; import com.symphony.bdk.gen.api.model.V2AdminStreamFilter; import com.symphony.bdk.gen.api.model.V2AdminStreamList; import com.symphony.bdk.gen.api.model.V2MembershipList; +import com.symphony.bdk.gen.api.model.V2Message; import com.symphony.bdk.gen.api.model.V2RoomSearchCriteria; +import com.symphony.bdk.gen.api.model.V2StreamAttributes; import com.symphony.bdk.gen.api.model.V3RoomAttributes; import com.symphony.bdk.gen.api.model.V3RoomDetail; import com.symphony.bdk.gen.api.model.V3RoomSearchResults; @@ -39,11 +48,86 @@ */ @Slf4j @API(status = API.Status.STABLE) -public class StreamService extends OboStreamService { +public class StreamService implements OboStreamService, OboService { + + private final StreamsApi streamsApi; + private final RoomMembershipApi roomMembershipApi; + private final ShareApi shareApi; + private final AuthSession authSession; + private final RetryWithRecoveryBuilder retryBuilder; public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, ShareApi shareApi, AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - super(streamsApi, membershipApi, shareApi, authSession, retryBuilder); + this.streamsApi = streamsApi; + this.roomMembershipApi = membershipApi; + this.shareApi = shareApi; + this.authSession = authSession; + this.retryBuilder = retryBuilder; + } + + @Override + public OboStreamService obo(AuthSession oboSession) { + return new StreamService(streamsApi, roomMembershipApi, shareApi, oboSession, retryBuilder); + } + + /** + * {@inheritDoc} + */ + public V2StreamAttributes getStreamInfo(String streamId) { + return executeAndRetry("getStreamInfo", + () -> streamsApi.v2StreamsSidInfoGet(streamId, authSession.getSessionToken())); + } + + /** + * {@inheritDoc} + */ + public List listStreams(StreamFilter filter) { + return executeAndRetry("listStreams", + () -> streamsApi.v1StreamsListPost(authSession.getSessionToken(), null, null, filter)); + } + + /** + * {@inheritDoc} + */ + public void addMemberToRoom( Long userId, String roomId) { + UserId user = new UserId().id(userId); + executeAndRetry("addMemberToRoom", + () -> roomMembershipApi.v1RoomIdMembershipAddPost(roomId, authSession.getSessionToken(), user)); + } + + /** + * {@inheritDoc} + */ + public void removeMemberFromRoom(Long userId, String roomId) { + UserId user = new UserId().id(userId); + executeAndRetry("removeMemberFrom", + () -> roomMembershipApi.v1RoomIdMembershipRemovePost(roomId, authSession.getSessionToken(), user)); + } + + /** + * {@inheritDoc} + */ + public V2Message share(String streamId, ShareContent content) { + return executeAndRetry("share", + () -> shareApi.v3StreamSidSharePost(streamId, authSession.getSessionToken(), content, authSession.getKeyManagerToken())); + } + + /** + * {@inheritDoc} + */ + public void promoteUserToRoomOwner(Long userId, String roomId) { + UserId user = new UserId().id(userId); + executeAndRetry("promoteUserToOwner", + () -> roomMembershipApi.v1RoomIdMembershipPromoteOwnerPost(roomId, authSession.getSessionToken(), user)); + } + + /** + * {@inheritDoc} + */ + public void demoteUserToRoomParticipant(Long userId, String roomId) { + UserId user = new UserId().id(userId); + executeAndRetry("demoteUserToParticipant", + () -> roomMembershipApi.v1RoomIdMembershipDemoteOwnerPost(roomId, authSession.getSessionToken(), user)); } /** @@ -214,4 +298,11 @@ public List listRoomMembers(String roomId) { return executeAndRetry("listRoomMembers", () -> roomMembershipApi.v2RoomIdMembershipListGet(roomId, authSession.getSessionToken())); } + + private T executeAndRetry(String name, SupplierWithApiException supplier) { + final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) + .clearRecoveryStrategies() // to remove refresh on bot session put by default + .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); + return RetryWithRecovery.executeAndRetry(retryBuilderWithAuthSession, name, supplier); + } } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java index 4586edf98..cd6a6124b 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java @@ -1,42 +1,20 @@ package com.symphony.bdk.core.service.user; -import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.retry.RetryWithRecovery; -import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; -import com.symphony.bdk.core.util.function.SupplierWithApiException; -import com.symphony.bdk.gen.api.UserApi; -import com.symphony.bdk.gen.api.UsersApi; import com.symphony.bdk.gen.api.model.UserSearchQuery; -import com.symphony.bdk.gen.api.model.UserSearchResults; import com.symphony.bdk.gen.api.model.UserV2; -import com.symphony.bdk.gen.api.model.V2UserList; -import com.symphony.bdk.http.api.ApiException; import lombok.NonNull; import org.apiguardian.api.API; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nullable; /** - * Service class for managing users. This exposes OBO-enabled endpoints only. + * Service interface exposing OBO-enabled endpoints to manage users. */ -@API(status = API.Status.INTERNAL) -public class OboUserService { - - protected final UserApi userApi; - protected final UsersApi usersApi; - protected final AuthSession authSession; - protected final RetryWithRecoveryBuilder retryBuilder; - - public OboUserService(UserApi userApi, UsersApi usersApi,AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - this.userApi = userApi; - this.usersApi = usersApi; - this.authSession = authSession; - this.retryBuilder = retryBuilder; - } +@API(status = API.Status.STABLE) +public interface OboUserService { /** * {@link UserService#searchUserByIds(List, Boolean)} @@ -48,13 +26,7 @@ public OboUserService(UserApi userApi, UsersApi usersApi,AuthSession authSession * @return Users found by user ids * @see Users Lookup V3 */ - public List searchUserByIds(@NonNull List uidList, - @NonNull Boolean local) { - String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); - V2UserList v2UserList = executeAndRetry("searchUserByIds", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, local)); - return v2UserList.getUsers(); - } + List searchUserByIds(@NonNull List uidList, @NonNull Boolean local); /** * {@link UserService#searchUserByIds(List)} @@ -63,12 +35,7 @@ public List searchUserByIds(@NonNull List uidList, * @return Users found by user ids * @see Users Lookup V3 */ - public List searchUserByIds(@NonNull List uidList) { - String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); - V2UserList v2UserList = executeAndRetry("searchUserByIds", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, false)); - return v2UserList.getUsers(); - } + List searchUserByIds(@NonNull List uidList); /** * {@link UserService#searchUserByEmails(List, Boolean)} @@ -80,13 +47,7 @@ public List searchUserByIds(@NonNull List uidList) { * @return Users found by emails. * @see Users Lookup V3 */ - public List searchUserByEmails(@NonNull List emailList, - @NonNull Boolean local) { - String emails = String.join(",", emailList); - V2UserList v2UserList = executeAndRetry("searchUserByEmails", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, local)); - return v2UserList.getUsers(); - } + List searchUserByEmails(@NonNull List emailList, @NonNull Boolean local); /** * {@link UserService#searchUserByEmails(List)} @@ -95,12 +56,7 @@ public List searchUserByEmails(@NonNull List emailList, * @return Users found by emails * @see Users Lookup V3 */ - public List searchUserByEmails(@NonNull List emailList) { - String emails = String.join(",", emailList); - V2UserList v2UserList = executeAndRetry("searchUserByEmails", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, false)); - return v2UserList.getUsers(); - } + List searchUserByEmails(@NonNull List emailList); /** * {@link UserService#searchUserByUsernames(List)} @@ -109,12 +65,7 @@ public List searchUserByEmails(@NonNull List emailList) { * @return Users found by usernames * @see Users Lookup V3 */ - public List searchUserByUsernames(@NonNull List usernameList) { - String usernames = String.join(",", usernameList); - V2UserList v2UserList = executeAndRetry("searchUserByUsernames", - () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, null, usernames, true)); - return v2UserList.getUsers(); - } + List searchUserByUsernames(@NonNull List usernameList); /** * {@link UserService#searchUserBySearchQuery(UserSearchQuery, Boolean)} @@ -126,17 +77,5 @@ public List searchUserByUsernames(@NonNull List usernameList) { * @return List of users found by query * @see Search Users */ - public List searchUserBySearchQuery(@NonNull UserSearchQuery query, - @Nullable Boolean local) { - UserSearchResults results = executeAndRetry("searchUserBySearchQuery", - () -> usersApi.v1UserSearchPost(authSession.getSessionToken(), query, null, null, local)); - return results.getUsers(); - } - - protected T executeAndRetry(String name, SupplierWithApiException supplier) { - final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) - .clearRecoveryStrategies() // to remove refresh on bot session put by default - .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); - return RetryWithRecovery.executeAndRetry(retryBuilderWithAuthSession, name, supplier); - } + List searchUserBySearchQuery(@NonNull UserSearchQuery query, @Nullable Boolean local); } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java index 6f32d9760..a0ebdf000 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java @@ -1,9 +1,12 @@ package com.symphony.bdk.core.service.user; import com.symphony.bdk.core.auth.AuthSession; +import com.symphony.bdk.core.retry.RetryWithRecovery; import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder; +import com.symphony.bdk.core.service.OboService; import com.symphony.bdk.core.service.user.constant.RoleId; import com.symphony.bdk.core.service.user.mapper.UserDetailMapper; +import com.symphony.bdk.core.util.function.SupplierWithApiException; import com.symphony.bdk.gen.api.UserApi; import com.symphony.bdk.gen.api.UsersApi; import com.symphony.bdk.gen.api.model.Avatar; @@ -14,8 +17,13 @@ import com.symphony.bdk.gen.api.model.StringId; import com.symphony.bdk.gen.api.model.UserDetail; import com.symphony.bdk.gen.api.model.UserFilter; +import com.symphony.bdk.gen.api.model.UserSearchQuery; +import com.symphony.bdk.gen.api.model.UserSearchResults; import com.symphony.bdk.gen.api.model.UserStatus; +import com.symphony.bdk.gen.api.model.UserV2; import com.symphony.bdk.gen.api.model.V2UserDetail; +import com.symphony.bdk.gen.api.model.V2UserList; +import com.symphony.bdk.http.api.ApiException; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -28,6 +36,8 @@ import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nullable; + /** * Service class for managing users. @@ -45,10 +55,92 @@ */ @Slf4j @API(status = API.Status.STABLE) -public class UserService extends OboUserService { +public class UserService implements OboUserService, OboService { + + private final UserApi userApi; + private final UsersApi usersApi; + private final AuthSession authSession; + private final RetryWithRecoveryBuilder retryBuilder; + + public UserService(UserApi userApi, UsersApi usersApi, AuthSession authSession, + RetryWithRecoveryBuilder retryBuilder) { + this.userApi = userApi; + this.usersApi = usersApi; + this.authSession = authSession; + this.retryBuilder = retryBuilder; + } + + @Override + public OboUserService obo(AuthSession oboSession) { + return new UserService(userApi, usersApi, oboSession, retryBuilder); + } + + /** + * {@inheritDoc} + */ + @Override + public List searchUserByIds(@NonNull List uidList, + @NonNull Boolean local) { + String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); + V2UserList v2UserList = executeAndRetry("searchUserByIds", + () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, local)); + return v2UserList.getUsers(); + } + + /** + * {@inheritDoc} + */ + @Override + public List searchUserByIds(@NonNull List uidList) { + String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); + V2UserList v2UserList = executeAndRetry("searchUserByIds", + () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, false)); + return v2UserList.getUsers(); + } + + /** + * {@inheritDoc} + */ + @Override + public List searchUserByEmails(@NonNull List emailList, + @NonNull Boolean local) { + String emails = String.join(",", emailList); + V2UserList v2UserList = executeAndRetry("searchUserByEmails", + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, local)); + return v2UserList.getUsers(); + } - public UserService(UserApi userApi, UsersApi usersApi, AuthSession authSession, RetryWithRecoveryBuilder retryBuilder) { - super(userApi, usersApi, authSession, retryBuilder); + /** + * {@inheritDoc} + */ + @Override + public List searchUserByEmails(@NonNull List emailList) { + String emails = String.join(",", emailList); + V2UserList v2UserList = executeAndRetry("searchUserByEmails", + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, false)); + return v2UserList.getUsers(); + } + + /** + * {@inheritDoc} + */ + @Override + public List searchUserByUsernames(@NonNull List usernameList) { + String usernames = String.join(",", usernameList); + V2UserList v2UserList = executeAndRetry("searchUserByUsernames", + () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, null, usernames, true)); + return v2UserList.getUsers(); + } + + /** + * {@inheritDoc} + */ + @Override + public List searchUserBySearchQuery(@NonNull UserSearchQuery query, + @Nullable Boolean local) { + UserSearchResults results = executeAndRetry("searchUserBySearchQuery", + () -> usersApi.v1UserSearchPost(authSession.getSessionToken(), query, null, null, local)); + return results.getUsers(); } /** @@ -275,4 +367,11 @@ public void updateStatusOfUser(@NonNull Long uid, @NonNull UserStatus status) { executeAndRetry("updateStatusOfUser", () -> userApi.v1AdminUserUidStatusUpdatePost(authSession.getSessionToken(), uid, status)); } + + private T executeAndRetry(String name, SupplierWithApiException supplier) { + final RetryWithRecoveryBuilder retryBuilderWithAuthSession = RetryWithRecoveryBuilder.from(retryBuilder) + .clearRecoveryStrategies() // to remove refresh on bot session put by default + .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); + return RetryWithRecovery.executeAndRetry(retryBuilderWithAuthSession, name, supplier); + } } diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java deleted file mode 100644 index 101a61921..000000000 --- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServiceFactoryTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.symphony.bdk.core; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.mock; - -import com.symphony.bdk.core.auth.AuthSession; -import com.symphony.bdk.core.client.ApiClientFactory; -import com.symphony.bdk.core.config.BdkConfigLoader; -import com.symphony.bdk.core.config.exception.BdkConfigException; -import com.symphony.bdk.core.config.model.BdkConfig; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class OboServiceFactoryTest { - - private OboServiceFactory oboServiceFactory; - - @BeforeEach - void setUp() throws BdkConfigException { - this.oboServiceFactory = new OboServiceFactory(mock(ApiClientFactory.class), mock(AuthSession.class), new BdkConfig()); - } - - @Test - void getOboUserServiceTest() { - assertNotNull(this.oboServiceFactory.getObUserService()); - } - - @Test - void getOboStreamServiceTest() { - assertNotNull(this.oboServiceFactory.getOboStreamService()); - } - - @Test - void getOboMessageServiceTest() { - assertNotNull(this.oboServiceFactory.getOboMessageService()); - } -} From 40b5d3c6f595fd7692fba13fc05d0c819df5215c Mon Sep 17 00:00:00 2001 From: Elias Croze Date: Tue, 13 Oct 2020 15:34:18 +0200 Subject: [PATCH 3/5] Removed lombok.NonNull annotations --- .../com/symphony/bdk/core/ServiceFactory.java | 23 +++++++- .../auth/impl/AuthSessionOboCertImpl.java | 6 +- .../auth/impl/OboAuthenticatorCertImpl.java | 5 +- .../symphony/bdk/core/service/OboService.java | 2 +- .../bdk/core/service/user/OboUserService.java | 14 ++--- .../bdk/core/service/user/UserService.java | 55 +++++++++---------- 6 files changed, 61 insertions(+), 44 deletions(-) diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java index c65f13e4d..c66160923 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/ServiceFactory.java @@ -26,6 +26,11 @@ import com.symphony.bdk.gen.api.UserApi; import com.symphony.bdk.gen.api.UsersApi; +import com.symphony.bdk.http.api.ApiClient; + +import com.symphony.bdk.http.api.ApiException; +import com.symphony.bdk.template.api.TemplateEngine; + import org.apiguardian.api.API; /** @@ -40,10 +45,24 @@ * */ @API(status = API.Status.INTERNAL) -class ServiceFactory extends OboServiceFactory { +class ServiceFactory { + + private final ApiClient podClient; + private final ApiClient agentClient; + private final AuthSession authSession; + private final TemplateEngine templateEngine; + private final BdkConfig config; + private final RetryWithRecoveryBuilder retryBuilder; public ServiceFactory(ApiClientFactory apiClientFactory, AuthSession authSession, BdkConfig config) { - super(apiClientFactory, authSession, config); + this.podClient = apiClientFactory.getPodClient(); + this.agentClient = apiClientFactory.getAgentClient(); + this.authSession = authSession; + this.templateEngine = TemplateEngine.getDefaultImplementation(); + this.config = config; + this.retryBuilder = new RetryWithRecoveryBuilder<>() + .retryConfig(config.getRetry()) + .recoveryStrategy(ApiException::isUnauthorized, authSession::refresh); } /** diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthSessionOboCertImpl.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthSessionOboCertImpl.java index 9793feceb..519c235b1 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthSessionOboCertImpl.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthSessionOboCertImpl.java @@ -5,9 +5,9 @@ import com.symphony.bdk.core.auth.OboAuthenticator; import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException; -import lombok.NonNull; import org.apiguardian.api.API; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -22,13 +22,13 @@ public class AuthSessionOboCertImpl implements AuthSession { private String sessionToken; - public AuthSessionOboCertImpl(@NonNull OboAuthenticatorCertImpl authenticator, @NonNull Long userId) { + public AuthSessionOboCertImpl(@Nonnull OboAuthenticatorCertImpl authenticator, @Nonnull Long userId) { this.authenticator = authenticator; this.userId = userId; this.username = null; } - public AuthSessionOboCertImpl(@NonNull OboAuthenticatorCertImpl authenticator, @NonNull String username) { + public AuthSessionOboCertImpl(@Nonnull OboAuthenticatorCertImpl authenticator, @Nonnull String username) { this.authenticator = authenticator; this.username = username; this.userId = null; diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/OboAuthenticatorCertImpl.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/OboAuthenticatorCertImpl.java index fa19d99bf..e65dd5756 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/OboAuthenticatorCertImpl.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/OboAuthenticatorCertImpl.java @@ -10,7 +10,6 @@ import com.symphony.bdk.gen.api.model.OboAuthResponse; import com.symphony.bdk.gen.api.model.Token; -import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.apiguardian.api.API; @@ -57,7 +56,7 @@ public AuthSession authenticateByUserId(@Nonnull Long userId) throws AuthUnautho return authSession; } - protected String retrieveOboSessionTokenByUserId(@NonNull Long userId) throws AuthUnauthorizedException { + protected String retrieveOboSessionTokenByUserId(@Nonnull Long userId) throws AuthUnauthorizedException { final String appSessionToken = this.retrieveAppSessionToken(); try { OboAuthResponse oboAuthResponse = this.authenticationApi.v1AppUserUidAuthenticatePost(userId, appSessionToken); @@ -72,7 +71,7 @@ protected String retrieveOboSessionTokenByUserId(@NonNull Long userId) throws Au } } - protected String retrieveOboSessionTokenByUsername(@NonNull String username) throws AuthUnauthorizedException { + protected String retrieveOboSessionTokenByUsername(@Nonnull String username) throws AuthUnauthorizedException { final String appSessionToken = this.retrieveAppSessionToken(); try { OboAuthResponse oboAuthResponse = this.authenticationApi.v1AppUsernameUsernameAuthenticatePost(username, appSessionToken); diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java index 44acad23b..0acfe8080 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java @@ -9,7 +9,7 @@ * * @param type returned by the {@link #obo(AuthSession)} function. */ -@API(status = API.Status.INTERNAL) +@API(status = API.Status.STABLE) public interface OboService { /** diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java index cd6a6124b..6cf95426a 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/OboUserService.java @@ -3,11 +3,11 @@ import com.symphony.bdk.gen.api.model.UserSearchQuery; import com.symphony.bdk.gen.api.model.UserV2; -import lombok.NonNull; import org.apiguardian.api.API; import java.util.List; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -26,7 +26,7 @@ public interface OboUserService { * @return Users found by user ids * @see Users Lookup V3 */ - List searchUserByIds(@NonNull List uidList, @NonNull Boolean local); + List searchUserByIds(@Nonnull List uidList, @Nonnull Boolean local); /** * {@link UserService#searchUserByIds(List)} @@ -35,7 +35,7 @@ public interface OboUserService { * @return Users found by user ids * @see Users Lookup V3 */ - List searchUserByIds(@NonNull List uidList); + List searchUserByIds(@Nonnull List uidList); /** * {@link UserService#searchUserByEmails(List, Boolean)} @@ -47,7 +47,7 @@ public interface OboUserService { * @return Users found by emails. * @see Users Lookup V3 */ - List searchUserByEmails(@NonNull List emailList, @NonNull Boolean local); + List searchUserByEmails(@Nonnull List emailList, @Nonnull Boolean local); /** * {@link UserService#searchUserByEmails(List)} @@ -56,7 +56,7 @@ public interface OboUserService { * @return Users found by emails * @see Users Lookup V3 */ - List searchUserByEmails(@NonNull List emailList); + List searchUserByEmails(@Nonnull List emailList); /** * {@link UserService#searchUserByUsernames(List)} @@ -65,7 +65,7 @@ public interface OboUserService { * @return Users found by usernames * @see Users Lookup V3 */ - List searchUserByUsernames(@NonNull List usernameList); + List searchUserByUsernames(@Nonnull List usernameList); /** * {@link UserService#searchUserBySearchQuery(UserSearchQuery, Boolean)} @@ -77,5 +77,5 @@ public interface OboUserService { * @return List of users found by query * @see Search Users */ - List searchUserBySearchQuery(@NonNull UserSearchQuery query, @Nullable Boolean local); + List searchUserBySearchQuery(@Nonnull UserSearchQuery query, @Nullable Boolean local); } diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java index a0ebdf000..5ef35fc9a 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/user/UserService.java @@ -25,7 +25,7 @@ import com.symphony.bdk.gen.api.model.V2UserList; import com.symphony.bdk.http.api.ApiException; -import lombok.NonNull; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apiguardian.api.API; @@ -36,6 +36,7 @@ import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -79,8 +80,7 @@ public OboUserService obo(AuthSession oboSession) { * {@inheritDoc} */ @Override - public List searchUserByIds(@NonNull List uidList, - @NonNull Boolean local) { + public List searchUserByIds(@Nonnull List uidList, @Nonnull Boolean local) { String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); V2UserList v2UserList = executeAndRetry("searchUserByIds", () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, local)); @@ -91,7 +91,7 @@ public List searchUserByIds(@NonNull List uidList, * {@inheritDoc} */ @Override - public List searchUserByIds(@NonNull List uidList) { + public List searchUserByIds(@Nonnull List uidList) { String uids = uidList.stream().map(String::valueOf).collect(Collectors.joining(",")); V2UserList v2UserList = executeAndRetry("searchUserByIds", () -> usersApi.v3UsersGet(authSession.getSessionToken(), uids, null, null, false)); @@ -102,8 +102,8 @@ public List searchUserByIds(@NonNull List uidList) { * {@inheritDoc} */ @Override - public List searchUserByEmails(@NonNull List emailList, - @NonNull Boolean local) { + public List searchUserByEmails(@Nonnull List emailList, + @Nonnull Boolean local) { String emails = String.join(",", emailList); V2UserList v2UserList = executeAndRetry("searchUserByEmails", () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, local)); @@ -114,7 +114,7 @@ public List searchUserByEmails(@NonNull List emailList, * {@inheritDoc} */ @Override - public List searchUserByEmails(@NonNull List emailList) { + public List searchUserByEmails(@Nonnull List emailList) { String emails = String.join(",", emailList); V2UserList v2UserList = executeAndRetry("searchUserByEmails", () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, emails, null, false)); @@ -125,7 +125,7 @@ public List searchUserByEmails(@NonNull List emailList) { * {@inheritDoc} */ @Override - public List searchUserByUsernames(@NonNull List usernameList) { + public List searchUserByUsernames(@Nonnull List usernameList) { String usernames = String.join(",", usernameList); V2UserList v2UserList = executeAndRetry("searchUserByUsernames", () -> usersApi.v3UsersGet(authSession.getSessionToken(), null, null, usernames, true)); @@ -136,8 +136,7 @@ public List searchUserByUsernames(@NonNull List usernameList) { * {@inheritDoc} */ @Override - public List searchUserBySearchQuery(@NonNull UserSearchQuery query, - @Nullable Boolean local) { + public List searchUserBySearchQuery(@Nonnull UserSearchQuery query, @Nullable Boolean local) { UserSearchResults results = executeAndRetry("searchUserBySearchQuery", () -> usersApi.v1UserSearchPost(authSession.getSessionToken(), query, null, null, local)); return results.getUsers(); @@ -150,7 +149,7 @@ public List searchUserBySearchQuery(@NonNull UserSearchQuery query, * @return Details of the user. * @see Get User v2 */ - public V2UserDetail getUserDetailByUid(@NonNull Long uid) { + public V2UserDetail getUserDetailByUid(@Nonnull Long uid) { return executeAndRetry("getUserDetailByUid", () -> userApi.v2AdminUserUidGet(authSession.getSessionToken(), uid)); } @@ -173,7 +172,7 @@ public List listUsersDetail() { * @see Find Users V1 * @see com.symphony.bdk.core.service.user.constant.UserFeature */ - public List listUsersDetail(@NonNull UserFilter filter) { + public List listUsersDetail(@Nonnull UserFilter filter) { List userDetailList = executeAndRetry("listUsersDetail", () -> userApi.v1AdminUserFindPost(authSession.getSessionToken(), filter, null, null)); return userDetailList.stream() @@ -188,7 +187,7 @@ public List listUsersDetail(@NonNull UserFilter filter) { * @param roleId Role Id * @see Add Role */ - public void addRoleToUser(@NonNull Long uid, @NonNull RoleId roleId) { + public void addRoleToUser(@Nonnull Long uid, @Nonnull RoleId roleId) { StringId stringId = new StringId().id(roleId.name()); executeAndRetry("addRoleToUser", () -> userApi.v1AdminUserUidRolesAddPost(authSession.getSessionToken(), uid, stringId)); @@ -201,7 +200,7 @@ public void addRoleToUser(@NonNull Long uid, @NonNull RoleId roleId) { * @param roleId Role Id * @see Remove Role */ - public void removeRoleFromUser(@NonNull Long uid, @NonNull RoleId roleId) { + public void removeRoleFromUser(@Nonnull Long uid, @Nonnull RoleId roleId) { StringId stringId = new StringId().id(roleId.name()); executeAndRetry("removeRoleFromUser", () -> userApi.v1AdminUserUidRolesRemovePost(authSession.getSessionToken(), uid, stringId)); @@ -214,7 +213,7 @@ public void removeRoleFromUser(@NonNull Long uid, @NonNull RoleId roleId) { * @return List of avatar urls of the user * @see User Avatar */ - public List getAvatarFromUser(@NonNull Long uid) { + public List getAvatarFromUser(@Nonnull Long uid) { return executeAndRetry("getAvatarFromUser", () -> userApi.v1AdminUserUidAvatarGet(authSession.getSessionToken(), uid)); } @@ -226,7 +225,7 @@ public List getAvatarFromUser(@NonNull Long uid) { * @param image The avatar image for the user profile picture.The image must be a base64-encoded. * @see Update User Avatar */ - public void updateAvatarOfUser(@NonNull Long uid, @NonNull String image) { + public void updateAvatarOfUser(@Nonnull Long uid, @Nonnull String image) { AvatarUpdate avatarUpdate = new AvatarUpdate().image(image); executeAndRetry("updateAvatarOfUser", () -> userApi.v1AdminUserUidAvatarUpdatePost(authSession.getSessionToken(), uid, avatarUpdate)); @@ -239,7 +238,7 @@ public void updateAvatarOfUser(@NonNull Long uid, @NonNull String image) { * @param image The avatar image in bytes array for the user profile picture. * @see Update User Avatar */ - public void updateAvatarOfUser(@NonNull Long uid, @NonNull byte[] image) { + public void updateAvatarOfUser(@Nonnull Long uid, @Nonnull byte[] image) { String imageBase64 = Base64.getEncoder().encodeToString(image); this.updateAvatarOfUser(uid, imageBase64); } @@ -251,7 +250,7 @@ public void updateAvatarOfUser(@NonNull Long uid, @NonNull byte[] image) { * @param imageStream The avatar image input stream for the user profile picture. * @see Update User Avatar */ - public void updateAvatarOfUser(@NonNull Long uid, @NonNull InputStream imageStream) throws IOException { + public void updateAvatarOfUser(@Nonnull Long uid, @Nonnull InputStream imageStream) throws IOException { byte[] bytes = IOUtils.toByteArray(imageStream); this.updateAvatarOfUser(uid, bytes); } @@ -263,7 +262,7 @@ public void updateAvatarOfUser(@NonNull Long uid, @NonNull InputStream imageStre * @return Disclaimer assigned to the user. * @see User Disclaimer */ - public Disclaimer getDisclaimerAssignedToUser(@NonNull Long uid) { + public Disclaimer getDisclaimerAssignedToUser(@Nonnull Long uid) { return executeAndRetry("getDisclaimerAssignedToUser", () -> userApi.v1AdminUserUidDisclaimerGet(authSession.getSessionToken(), uid)); } @@ -274,7 +273,7 @@ public Disclaimer getDisclaimerAssignedToUser(@NonNull Long uid) { * @param uid User Id * @see Unassign User Disclaimer */ - public void unAssignDisclaimerFromUser(@NonNull Long uid) { + public void unAssignDisclaimerFromUser(@Nonnull Long uid) { executeAndRetry("unAssignDisclaimerFromUser", () -> userApi.v1AdminUserUidDisclaimerDelete(authSession.getSessionToken(), uid)); } @@ -286,7 +285,7 @@ public void unAssignDisclaimerFromUser(@NonNull Long uid) { * @param disclaimerId Disclaimer to be assigned * @see Update User Disclaimer */ - public void assignDisclaimerToUser(@NonNull Long uid, @NonNull String disclaimerId) { + public void assignDisclaimerToUser(@Nonnull Long uid, @Nonnull String disclaimerId) { StringId stringId = new StringId().id(disclaimerId); executeAndRetry("assignDisclaimerToUser", () -> userApi.v1AdminUserUidDisclaimerUpdatePost(authSession.getSessionToken(), uid, stringId)); @@ -300,7 +299,7 @@ public void assignDisclaimerToUser(@NonNull Long uid, @NonNull String disclaimer * @return List of delegates assigned to an user. * @see User Delegates */ - public List getDelegatesAssignedToUser(@NonNull Long uid) { + public List getDelegatesAssignedToUser(@Nonnull Long uid) { return executeAndRetry("getDelegatesAssignedToUser", () -> userApi.v1AdminUserUidDelegatesGet(authSession.getSessionToken(), uid)); } @@ -313,8 +312,8 @@ public List getDelegatesAssignedToUser(@NonNull Long uid) { * @param actionEnum Action to be performed * @see Update User Delegates */ - public void updateDelegatesAssignedToUser(@NonNull Long uid, @NonNull Long delegatedUserId, - @NonNull DelegateAction.ActionEnum actionEnum) { + public void updateDelegatesAssignedToUser(@Nonnull Long uid, @Nonnull Long delegatedUserId, + @Nonnull DelegateAction.ActionEnum actionEnum) { DelegateAction delegateAction = new DelegateAction().action(actionEnum).userId(delegatedUserId); executeAndRetry("updateDelegatesAssignedToUser", () -> userApi.v1AdminUserUidDelegatesUpdatePost(authSession.getSessionToken(), uid, delegateAction)); @@ -327,7 +326,7 @@ public void updateDelegatesAssignedToUser(@NonNull Long uid, @NonNull Long deleg * @return List of feature entitlements of the user. * @see User Features */ - public List getFeatureEntitlementsOfUser(@NonNull Long uid) { + public List getFeatureEntitlementsOfUser(@Nonnull Long uid) { return executeAndRetry("getFeatureEntitlementsOfUser", () -> userApi.v1AdminUserUidFeaturesGet(authSession.getSessionToken(), uid)); } @@ -339,7 +338,7 @@ public List getFeatureEntitlementsOfUser(@NonNull Long uid) { * @param features List of feature entitlements to be updated * @see Update User Features */ - public void updateFeatureEntitlementsOfUser(@NonNull Long uid, @NonNull List features) { + public void updateFeatureEntitlementsOfUser(@Nonnull Long uid, @Nonnull List features) { executeAndRetry("updateFeatureEntitlementsOfUser", () -> userApi.v1AdminUserUidFeaturesUpdatePost(authSession.getSessionToken(), uid, features)); } @@ -351,7 +350,7 @@ public void updateFeatureEntitlementsOfUser(@NonNull Long uid, @NonNull ListUser Status */ - public UserStatus getStatusOfUser(@NonNull Long uid) { + public UserStatus getStatusOfUser(@Nonnull Long uid) { return executeAndRetry("getStatusOfUser", () -> userApi.v1AdminUserUidStatusGet(authSession.getSessionToken(), uid)); } @@ -363,7 +362,7 @@ public UserStatus getStatusOfUser(@NonNull Long uid) { * @param status Status to be updated to the user * @see Update User Status */ - public void updateStatusOfUser(@NonNull Long uid, @NonNull UserStatus status) { + public void updateStatusOfUser(@Nonnull Long uid, @Nonnull UserStatus status) { executeAndRetry("updateStatusOfUser", () -> userApi.v1AdminUserUidStatusUpdatePost(authSession.getSessionToken(), uid, status)); } From b7996ab93931276ad1a5712564b1a164836c2a9d Mon Sep 17 00:00:00 2001 From: Elias Croze Date: Tue, 13 Oct 2020 15:38:15 +0200 Subject: [PATCH 4/5] Renamed OboServicesFacade into OboServices --- .../{OboServicesFacade.java => OboServices.java} | 4 ++-- .../java/com/symphony/bdk/core/SymphonyBdk.java | 8 ++++---- ...ervicesFacadeTest.java => OboServicesTest.java} | 14 +++++++------- .../com/symphony/bdk/core/SymphonyBdkTest.java | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) rename symphony-bdk-core/src/main/java/com/symphony/bdk/core/{OboServicesFacade.java => OboServices.java} (94%) rename symphony-bdk-core/src/test/java/com/symphony/bdk/core/{OboServicesFacadeTest.java => OboServicesTest.java} (52%) diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServices.java similarity index 94% rename from symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java rename to symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServices.java index 8e08fee90..453f7d0a8 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServicesFacade.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/OboServices.java @@ -13,13 +13,13 @@ * Entry point for OBO-enabled services. */ @API(status = API.Status.EXPERIMENTAL) -public class OboServicesFacade { +public class OboServices { private final OboStreamService oboStreamService; private final OboUserService oboUserService; private final OboMessageService oboMessageService; - public OboServicesFacade(BdkConfig config, AuthSession oboSession) { + public OboServices(BdkConfig config, AuthSession oboSession) { final ServiceFactory serviceFactory = new ServiceFactory(new ApiClientFactory(config), oboSession, config); oboStreamService = serviceFactory.getStreamService(); diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java index e05f11caf..8963ef944 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java @@ -152,13 +152,13 @@ public AuthSession obo(String username) throws AuthUnauthorizedException { } /** - * Get an {@link OboServicesFacade} gathering all OBO enabled services + * Get an {@link OboServices} gathering all OBO enabled services * * @param oboSession the OBO session to use - * @return an {@link OboServicesFacade} instance using the provided OBO session + * @return an {@link OboServices} instance using the provided OBO session */ - public OboServicesFacade obo(AuthSession oboSession) { - return new OboServicesFacade(config, oboSession); + public OboServices obo(AuthSession oboSession) { + return new OboServices(config, oboSession); } /** diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java similarity index 52% rename from symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java rename to symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java index 9a0b27765..9c4a04231 100644 --- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesFacadeTest.java +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java @@ -9,28 +9,28 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class OboServicesFacadeTest { +public class OboServicesTest { - private OboServicesFacade oboServicesFacade; + private OboServices oboServices; @BeforeEach void setUp() { - oboServicesFacade = new OboServicesFacade(new BdkConfig(), mock(AuthSession.class)); - Assertions.assertNotNull(oboServicesFacade.messages()); + oboServices = new OboServices(new BdkConfig(), mock(AuthSession.class)); + Assertions.assertNotNull(oboServices.messages()); } @Test void testOboStreams() { - Assertions.assertNotNull(oboServicesFacade.streams()); + Assertions.assertNotNull(oboServices.streams()); } @Test void testOboUsers() { - Assertions.assertNotNull(oboServicesFacade.users()); + Assertions.assertNotNull(oboServices.users()); } @Test void testOboMessages() { - Assertions.assertNotNull(oboServicesFacade.messages()); + Assertions.assertNotNull(oboServices.messages()); } } diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java index 3b9647128..3159c0efb 100644 --- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/SymphonyBdkTest.java @@ -107,7 +107,7 @@ void getOboServiceFacade() throws AuthUnauthorizedException { this.mockApiClient.onPost(LOGIN_PUBKEY_OBO_USERID_AUTHENTICATE.replace("{userId}", "123456"), "{ \"token\": \"1234\", \"name\": \"sessionToken\" }"); AuthSession oboSession = this.symphonyBdk.obo(123456L); - final OboServicesFacade obo = this.symphonyBdk.obo(oboSession); + final OboServices obo = this.symphonyBdk.obo(oboSession); assertNotNull(obo); } From 187ff5180ef89c2f2b3d697689ef4fdfed62de67 Mon Sep 17 00:00:00 2001 From: Elias Croze Date: Tue, 13 Oct 2020 18:29:04 +0200 Subject: [PATCH 5/5] Exposed OboAuthenticator in BdkCoreConfig --- .../symphony/bdk/core/service/OboService.java | 6 +-- .../core/service/stream/StreamService.java | 3 ++ .../symphony/bdk/core/OboServicesTest.java | 16 ++++-- .../bdk/spring/config/BdkCoreConfig.java | 11 ++++ .../SymphonyBdkAutoConfigurationTest.java | 53 +++++++++++++++++++ 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java index 0acfe8080..753f74bc7 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/OboService.java @@ -5,7 +5,7 @@ import org.apiguardian.api.API; /** - * Interface which returns an OBO-enabled service class from a given obo session. + * Interface which returns an OBO-enabled service class from a given OBO session. * * @param type returned by the {@link #obo(AuthSession)} function. */ @@ -13,9 +13,9 @@ public interface OboService { /** - * Returns a new service instance with OBO-enabled endpoints from a given obo session. + * Returns a new service instance with OBO-enabled endpoints from a given OBO session. * - * @param oboSession the obo session + * @param oboSession the OBO session * @return the instance of the service class with OBO-enabled endpoints */ S obo(AuthSession oboSession); diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java index 05d9d174e..e41a76806 100644 --- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java +++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/service/stream/StreamService.java @@ -66,6 +66,9 @@ public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, Sha } @Override + /** + * {@inheritDoc} + */ public OboStreamService obo(AuthSession oboSession) { return new StreamService(streamsApi, roomMembershipApi, shareApi, oboSession, retryBuilder); } diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java index 9c4a04231..e42e06fcc 100644 --- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java +++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/OboServicesTest.java @@ -1,11 +1,15 @@ package com.symphony.bdk.core; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import com.symphony.bdk.core.auth.AuthSession; import com.symphony.bdk.core.config.model.BdkConfig; +import com.symphony.bdk.core.service.message.OboMessageService; +import com.symphony.bdk.core.service.stream.OboStreamService; +import com.symphony.bdk.core.service.user.OboUserService; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,21 +20,23 @@ public class OboServicesTest { @BeforeEach void setUp() { oboServices = new OboServices(new BdkConfig(), mock(AuthSession.class)); - Assertions.assertNotNull(oboServices.messages()); } @Test void testOboStreams() { - Assertions.assertNotNull(oboServices.streams()); + assertNotNull(oboServices.streams()); + assertTrue(oboServices.streams() instanceof OboStreamService); } @Test void testOboUsers() { - Assertions.assertNotNull(oboServices.users()); + assertNotNull(oboServices.users()); + assertTrue(oboServices.users() instanceof OboUserService); } @Test void testOboMessages() { - Assertions.assertNotNull(oboServices.messages()); + assertNotNull(oboServices.messages()); + assertTrue(oboServices.messages() instanceof OboMessageService); } } diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java index 2404dd25e..d4e2afac3 100644 --- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java +++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java @@ -1,5 +1,6 @@ package com.symphony.bdk.spring.config; +import com.symphony.bdk.core.auth.OboAuthenticator; import com.symphony.bdk.http.jersey2.ApiClientBuilderProviderJersey2; import com.symphony.bdk.http.api.ApiClient; import com.symphony.bdk.core.auth.AuthSession; @@ -74,4 +75,14 @@ public AuthSession botSession(AuthenticatorFactory authenticatorFactory) { throw new BeanInitializationException("Unable to authenticate bot", e); } } + + @Bean + @ConditionalOnProperty(name = "bdk.app.appId") + public OboAuthenticator oboAuthenticator(AuthenticatorFactory authenticatorFactory) { + try { + return authenticatorFactory.getOboAuthenticator(); + } catch (AuthInitializationException e) { + throw new BeanInitializationException("Unable to use OBO authentication", e); + } + } } diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/SymphonyBdkAutoConfigurationTest.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/SymphonyBdkAutoConfigurationTest.java index 4a6eb8012..abcbe6e65 100644 --- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/SymphonyBdkAutoConfigurationTest.java +++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/SymphonyBdkAutoConfigurationTest.java @@ -1,10 +1,15 @@ package com.symphony.bdk.spring; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import com.symphony.bdk.core.auth.OboAuthenticator; +import com.symphony.bdk.core.auth.exception.AuthInitializationException; import com.symphony.bdk.spring.service.DatafeedAsyncLauncherService; +import org.assertj.core.api.AbstractThrowableAssert; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.BeanInitializationException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -42,6 +47,54 @@ void shouldLoadContextWithSuccess() { // verify that beans for cert auth have not been injected assertThat(context).doesNotHaveBean("keyAuthApiClient"); assertThat(context).doesNotHaveBean("sessionAuthApiClient"); + + //verify that bean for OBO authentication has not been injected + assertThat(context).doesNotHaveBean("oboAuthenticator"); + }); + } + + @Test + void shouldInitializeOboAuthenticatorIfAppIdSet() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues( + "bdk.scheme=http", + "bdk.host=localhost", + "bdk.context=context", + + "bdk.bot.username=tibot", + "bdk.bot.privateKeyPath=classpath:/privatekey.pem", + + "bdk.app.appId=tibapp", + "bdk.app.privateKeyPath=classpath:/privatekey.pem" + ) + .withUserConfiguration(SymphonyBdkMockedConfiguration.class) + .withConfiguration(AutoConfigurations.of(SymphonyBdkAutoConfiguration.class)); + + contextRunner.run(context -> { + assertThat(context).hasBean("oboAuthenticator"); + assertThat(context).hasSingleBean(OboAuthenticator.class); + }); + } + + @Test + void shouldFailOnOboAuthenticatorInitializationIfNotProperlyConfigured() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues( + "bdk.scheme=http", + "bdk.host=localhost", + "bdk.context=context", + + "bdk.bot.username=tibot", + "bdk.bot.privateKeyPath=classpath:/privatekey.pem", + + "bdk.app.appId=tibapp" + ) + .withUserConfiguration(SymphonyBdkMockedConfiguration.class) + .withConfiguration(AutoConfigurations.of(SymphonyBdkAutoConfiguration.class)); + + contextRunner.run(context -> { + assertThat(context).hasFailed(); + assertThat(context).getFailure().hasRootCauseInstanceOf(AuthInitializationException.class); }); }