diff --git a/symphony-bdk-core/build.gradle b/symphony-bdk-core/build.gradle
index 139ce401d..e524a0d19 100644
--- a/symphony-bdk-core/build.gradle
+++ b/symphony-bdk-core/build.gradle
@@ -81,20 +81,25 @@ dependencies {
// OpenAPI code generation
def apiBaseUrl = "https://raw.githubusercontent.com/finos/symphony-api-spec/a8efe8a6193769d0657fc57758918138aa4483bb"
+
+def apiBaseUrlOverrides = [
+ Streams: "https://raw.githubusercontent.com/Tahak-symphony/symphony-api-spec/BE-9867_user_streams"
+]
def generatedFolder = "${layout.buildDirectory.get()}/generated/openapi"
def apisToGenerate = [
Agent: 'agent/agent-api-public-deprecated.yaml',
Pod : 'pod/pod-api-public-deprecated.yaml',
Auth : 'authenticator/authenticator-api-public-deprecated.yaml',
Login: 'login/login-api-public.yaml',
- Users: 'users/users-api-public.yaml'
+ Users: 'users/users-api-public.yaml',
+ Streams: 'streams/streams-api-public.yaml'
]
sourceSets.main.java.srcDirs += "$generatedFolder/src/main/java"
apisToGenerate.each { api, path ->
def downloadTask = tasks.register("download$api", Download) {
- src "$apiBaseUrl/$path"
+ src "${apiBaseUrlOverrides.getOrDefault(api, apiBaseUrl)}/$path"
dest "${layout.buildDirectory.get()}/openapi/$api/${path.split("/")[1]}"
overwrite false
useETag "all"
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 17f0305bb..bdc39ed9e 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
@@ -49,6 +49,7 @@
import com.symphony.bdk.gen.api.StreamsApi;
import com.symphony.bdk.gen.api.SystemApi;
import com.symphony.bdk.gen.api.UserApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
import com.symphony.bdk.gen.api.UsersApi;
import com.symphony.bdk.gen.api.model.UserV2;
import com.symphony.bdk.http.api.ApiClient;
@@ -76,6 +77,7 @@ class ServiceFactory {
private final ApiClient podClient;
private final ApiClient agentClient;
+ private final ApiClient streamClient;
private final ApiClient datafeedAgentClient;
private final ApiClient datahoseAgentClient;
private final AuthSession authSession;
@@ -101,6 +103,7 @@ public ServiceFactory(
this.config = config;
this.podClient = apiClientFactory.getPodClient();
this.agentClient = apiClientFactory.getAgentClient();
+ this.streamClient = apiClientFactory.getStreamClient();
this.datafeedAgentClient = apiClientFactory.getDatafeedAgentClient();
this.datahoseAgentClient = apiClientFactory.getDatahoseAgentClient();
this.authSession = authSession;
@@ -149,7 +152,7 @@ public UserService getUserService() {
*/
public StreamService getStreamService() {
return new StreamService(new StreamsApi(podClient), new RoomMembershipApi(podClient), new ShareApi(agentClient),
- new StreamContextApi(agentClient), authSession, retryBuilder);
+ new StreamContextApi(agentClient), new UserStreamsApi(streamClient), authSession, retryBuilder);
}
public DisclaimerService getDisclaimerService() {
diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/client/ApiClientFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/client/ApiClientFactory.java
index 07c1ba682..c8dd9dc45 100644
--- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/client/ApiClientFactory.java
+++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/client/ApiClientFactory.java
@@ -31,6 +31,7 @@
public class ApiClientFactory {
private static final String USERS_CONTEXT_PATH = "";
+ private static final String STREAMS_CONTEXT_PATH = "";
private static final String LOGIN_CONTEXT_PATH = "/login";
private static final String POD_CONTEXT_PATH = "/pod";
private static final String AGENT_CONTEXT_PATH = "/agent";
@@ -83,6 +84,10 @@ public ApiClient getUsersClient() {
return buildClient(USERS_CONTEXT_PATH, this.config.getPod());
}
+ public ApiClient getStreamClient() {
+ return buildClient(STREAMS_CONTEXT_PATH, this.config.getPod());
+ }
+
/**
* Returns a fully initialized {@link ApiClient} for KeyManager API.
*
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 984a0ce4a..fd28278aa 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
@@ -7,15 +7,17 @@
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.StreamArrayResponse;
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;
-import org.apiguardian.api.API;
+import org.apiguardian.api.API;
import org.jspecify.annotations.Nullable;
+
import java.util.List;
/**
@@ -31,7 +33,7 @@ public interface OboStreamService {
* @return The created IM
* @see Create IM or MIM
*/
- Stream create(Long... uids);
+ Stream create(Long... uids);
/**
* Create a new single or multi party instant message conversation between the caller and specified users.
@@ -65,7 +67,7 @@ public interface OboStreamService {
/**
* {@link StreamService#getStream(String)}
*
- * @param streamId The stream id.
+ * @param streamId The stream id.
* @return The information about the stream with the given id.
* @see Stream Info V2
*/
@@ -83,7 +85,7 @@ public interface OboStreamService {
/**
* {@link StreamService#listStreams(StreamFilter)}
*
- * @param filter The stream searching criteria.
+ * @param filter The stream searching criteria.
* @return The list of streams retrieved according to the searching criteria.
* @see List Streams
*/
@@ -92,8 +94,8 @@ public interface OboStreamService {
/**
* {@link StreamService#listStreams(StreamFilter, PaginationAttribute)}
*
- * @param filter The stream searching criteria.
- * @param pagination The skip and limit for pagination.
+ * @param filter The stream searching criteria.
+ * @param pagination The skip and limit for pagination.
* @return The list of streams retrieved according to the searching criteria.
* @see List Streams
*/
@@ -112,8 +114,8 @@ public interface OboStreamService {
/**
* {@link StreamService#listAllStreams(StreamFilter, StreamPaginationAttribute)}
*
- * @param filter The stream searching criteria.
- * @param pagination The chunkSize and totalSize for pagination.
+ * @param filter The stream searching criteria.
+ * @param pagination The chunkSize and totalSize for pagination.
* @return a {@link java.util.stream.Stream} of matching streams according to the searching criteria.
* @see List Streams
*/
@@ -175,8 +177,8 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* {@link StreamService#addMemberToRoom(Long, String)}
*
- * @param userId The id of the user to be added to the given room
- * @param roomId The room id
+ * @param userId The id of the user to be added to the given room
+ * @param roomId The room id
* @see Add Member
*/
void addMemberToRoom(Long userId, String roomId);
@@ -184,8 +186,8 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* {@link StreamService#removeMemberFromRoom(Long, String)}
*
- * @param userId The id of the user to be removed from the given room
- * @param roomId The room id
+ * @param userId The id of the user to be removed from the given room
+ * @param roomId The room id
* @see Remove Member
*/
void removeMemberFromRoom(Long userId, String roomId);
@@ -193,8 +195,8 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* {@link StreamService#share(String, ShareContent)}
*
- * @param streamId The stream id.
- * @param content The third-party {@link ShareContent} to be shared.
+ * @param streamId The stream id.
+ * @param content The third-party {@link ShareContent} to be shared.
* @return Message contains share content
* @see Share
*/
@@ -203,8 +205,8 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* {@link StreamService#promoteUserToRoomOwner(Long, String)}
*
- * @param userId The id of the user to be promoted to room owner.
- * @param roomId The room id.
+ * @param userId The id of the user to be promoted to room owner.
+ * @param roomId The room id.
* @see Promote Owner
*/
void promoteUserToRoomOwner(Long userId, String roomId);
@@ -212,8 +214,8 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* {@link StreamService#demoteUserToRoomParticipant(Long, String)}
*
- * @param userId The id of the user to be demoted to room participant.
- * @param roomId The room id.
+ * @param userId The id of the user to be demoted to room participant.
+ * @param roomId The room id.
* @see Demote Owner
*/
void demoteUserToRoomParticipant(Long userId, String roomId);
@@ -230,13 +232,35 @@ java.util.stream.Stream searchAllRooms(V2RoomSearchCriteria query,
/**
* Return a representation of the conversation in Markdown format
* Returned data includes :
- * - stream title
- * - stream properties
- * - stream members
- * - stream last messages
+ * - stream title
+ * - stream properties
+ * - stream members
+ * - stream last messages
*
* @param streamId
* @return A String containing markdown representation of the conversation
*/
String getStreamContext(String streamId);
+
+ /**
+ * Lists the authenticated user's active chat streams matching specified filtering criteria.
+ *
+ * @param limit The maximum number of streams to return.
+ * @param includeHidden Whether to include hidden streams in the results.
+ * @param onlyUnread If true, only returns streams that contain unread messages.
+ * @param channel Filter streams by channel type. Allowed values: Whatsapp, Wechat, Line, SMS, Symphony.
+ * @param external Filter streams to include external chats.
+ * @param internal Filter streams to include internal chats.
+ * @param cursor Opaque pagination cursor returned as nextCursor by a previous call.
+ * @return A {@link StreamArrayResponse} containing the list of active chat streams and next cursor.
+ * @see List User Streams
+ */
+ StreamArrayResponse getUserStreams(@Nullable Integer limit,
+ @Nullable Boolean includeHidden,
+ @Nullable Boolean onlyUnread,
+ @Nullable String channel,
+ @Nullable Boolean external,
+ @Nullable Boolean internal,
+ @Nullable String cursor);
+
}
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 9f9da24e0..21bfaa327 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
@@ -16,10 +16,12 @@
import com.symphony.bdk.gen.api.ShareApi;
import com.symphony.bdk.gen.api.StreamContextApi;
import com.symphony.bdk.gen.api.StreamsApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
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.StreamArrayResponse;
import com.symphony.bdk.gen.api.model.StreamAttributes;
import com.symphony.bdk.gen.api.model.StreamFilter;
import com.symphony.bdk.gen.api.model.UserId;
@@ -67,28 +69,31 @@ public class StreamService implements OboStreamService, OboService retryBuilder;
public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, ShareApi shareApi,
- StreamContextApi streamContextApi,
+ StreamContextApi streamContextApi, UserStreamsApi userStreamsApi,
AuthSession authSession, RetryWithRecoveryBuilder> retryBuilder) {
this.streamsApi = streamsApi;
this.roomMembershipApi = membershipApi;
this.shareApi = shareApi;
this.streamContextApi = streamContextApi;
+ this.userStreamsApi = userStreamsApi;
this.authSession = authSession;
this.retryBuilder = RetryWithRecoveryBuilder.copyWithoutRecoveryStrategies(retryBuilder)
.recoveryStrategy(ApiException::isUnauthorized, authSession::refresh);
}
public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, ShareApi shareApi,
- StreamContextApi streamContextApi,
+ StreamContextApi streamContextApi, UserStreamsApi userStreamsApi,
RetryWithRecoveryBuilder> retryBuilder) {
this.streamsApi = streamsApi;
this.roomMembershipApi = membershipApi;
this.shareApi = shareApi;
this.streamContextApi = streamContextApi;
+ this.userStreamsApi = userStreamsApi;
this.authSession = null;
this.retryBuilder = RetryWithRecoveryBuilder.copyWithoutRecoveryStrategies(retryBuilder);
}
@@ -98,7 +103,7 @@ public StreamService(StreamsApi streamsApi, RoomMembershipApi membershipApi, Sha
*/
@Override
public OboStreamService obo(AuthSession oboSession) {
- return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, oboSession, retryBuilder);
+ return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, userStreamsApi, oboSession, retryBuilder);
}
/**
@@ -509,6 +514,17 @@ public String getStreamContext(String streamId) {
() -> streamContextApi.v1StreamContext(toUrlSafeIdIfNeeded(streamId), authSession.getSessionToken(), authSession.getKeyManagerToken()));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public StreamArrayResponse getUserStreams(@Nullable Integer limit, @Nullable Boolean includeHidden,
+ @Nullable Boolean onlyUnread, @Nullable String channel, @Nullable Boolean external, @Nullable Boolean internal,
+ @Nullable String cursor) {
+ return executeAndRetry("getUserStreams", userStreamsApi.getApiClient().getBasePath(),
+ () -> userStreamsApi.listUserStreams(authSession.getSessionToken(), limit, includeHidden, onlyUnread, channel, external, internal, cursor));
+ }
+
private T executeAndRetry(String name, String address, SupplierWithApiException supplier) {
checkAuthSession(authSession);
return RetryWithRecovery.executeAndRetry(retryBuilder, name, address, supplier);
diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/ServiceFactoryTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/ServiceFactoryTest.java
index 4e151e335..ad4458a0a 100644
--- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/ServiceFactoryTest.java
+++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/ServiceFactoryTest.java
@@ -56,6 +56,7 @@ void setUp() throws BdkConfigException {
when(this.apiClientFactory.getPodClient()).thenReturn(mPodClient);
when(this.apiClientFactory.getAgentClient()).thenReturn(mock(ApiClient.class));
+ when(this.apiClientFactory.getStreamClient()).thenReturn(mock(ApiClient.class));
ApiClient datafeedAgentClient = mock(ApiClient.class);
when(datafeedAgentClient.getBasePath()).thenReturn("/agent");
@@ -75,6 +76,7 @@ void getUserServiceTest() {
void getStreamServiceTest() {
StreamService streamService = this.serviceFactory.getStreamService();
assertNotNull(streamService);
+ verify(this.apiClientFactory).getStreamClient();
}
@Test
diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/client/ApiClientFactoryTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/client/ApiClientFactoryTest.java
index 4a6c2ab6a..698184444 100644
--- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/client/ApiClientFactoryTest.java
+++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/client/ApiClientFactoryTest.java
@@ -46,6 +46,13 @@ void testGetUsersClient() {
assertEquals("https://pod-host:443", usersClient.getBasePath());
}
+ @Test
+ void testGetStreamClient() {
+ final ApiClient streamClient = this.factory.getStreamClient();
+ assertEquals(ApiClientJersey2.class, streamClient.getClass());
+ assertEquals("https://pod-host:443", streamClient.getBasePath());
+ }
+
@Test
void testGetRelayClient() {
final ApiClient relayClient = this.factory.getRelayClient();
diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/service/stream/StreamServiceTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/service/stream/StreamServiceTest.java
index dc18ec929..ba576b940 100644
--- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/service/stream/StreamServiceTest.java
+++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/service/stream/StreamServiceTest.java
@@ -3,6 +3,7 @@
import static com.symphony.bdk.core.util.IdUtil.fromUrlSafeId;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -23,10 +24,12 @@
import com.symphony.bdk.gen.api.ShareApi;
import com.symphony.bdk.gen.api.StreamContextApi;
import com.symphony.bdk.gen.api.StreamsApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
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.StreamArrayResponse;
import com.symphony.bdk.gen.api.model.StreamAttributes;
import com.symphony.bdk.gen.api.model.StreamFilter;
import com.symphony.bdk.gen.api.model.StreamType;
@@ -80,6 +83,7 @@ public class StreamServiceTest {
private static final String V3_ROOM_UPDATE = "/pod/v3/room/{id}/update";
private static final String V3_SHARE = "/agent/v3/stream/{sid}/share";
private static final String V1_STREAM_CONTEXT = "/agent/v1/stream/{sid}/context";
+ private static final String V4_USER_STREAMS = "/v4/streams/user";
private StreamService service;
private MockApiClient mockApiClient;
@@ -87,6 +91,7 @@ public class StreamServiceTest {
private AuthSession authSession;
private StreamsApi streamsApi;
private StreamContextApi streamContextApi;
+ private UserStreamsApi userStreamsApi;
private ShareApi shareApi;
@BeforeEach
@@ -95,13 +100,15 @@ void setUp() {
this.authSession = mock(AuthSession.class);
ApiClient podClient = mockApiClient.getApiClient("/pod");
ApiClient agentClient = mockApiClient.getApiClient("/agent");
+ ApiClient streamClient = mockApiClient.getApiClient("");
this.spyRoomMembershipApi = spy(new RoomMembershipApi(podClient));
this.streamsApi = spy(new StreamsApi(podClient));
this.shareApi = new ShareApi(agentClient);
this.streamContextApi = new StreamContextApi(agentClient);
+ this.userStreamsApi = spy(new UserStreamsApi(streamClient));
this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
- this.authSession, new RetryWithRecoveryBuilder<>());
+ this.userStreamsApi, this.authSession, new RetryWithRecoveryBuilder<>());
when(authSession.getSessionToken()).thenReturn("1234");
when(authSession.getKeyManagerToken()).thenReturn("1234");
@@ -110,7 +117,7 @@ void setUp() {
@Test
void nonOboEndpointShouldThrowExceptionInOboMode() {
this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
- new RetryWithRecoveryBuilder<>());
+ this.userStreamsApi, new RetryWithRecoveryBuilder<>());
assertThrows(IllegalStateException.class, () -> this.service.getStream(""));
}
@@ -121,7 +128,7 @@ void getStreamInOboMode() throws IOException {
JsonHelper.readFromClasspath("/stream/v2_stream_attributes.json"));
this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
- new RetryWithRecoveryBuilder<>());
+ this.userStreamsApi, new RetryWithRecoveryBuilder<>());
V2StreamAttributes stream = this.service.obo(this.authSession).getStream("p9B316LKDto7iOECc8Xuz3qeWsc0bdA");
assertEquals("p9B316LKDto7iOECc8Xuz3qeWsc0bdA", stream.getId());
@@ -524,7 +531,7 @@ void getStreamContextInOboMode() {
this.mockApiClient.onGet(V1_STREAM_CONTEXT.replace("{sid}", "p9B316LKDto7iOECc8Xuz3qeWsc0bdA"), "\"Markdown Context\"");
this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
- new RetryWithRecoveryBuilder<>());
+ this.userStreamsApi, new RetryWithRecoveryBuilder<>());
String context = this.service.obo(this.authSession).getStreamContext("p9B316LKDto7iOECc8Xuz3qeWsc0bdA");
assertEquals("Markdown Context", context);
@@ -537,6 +544,52 @@ void getStreamContextTestFailed() {
assertThrows(ApiRuntimeException.class, () -> this.service.getStreamContext("p9B316LKDto7iOECc8Xuz3qeWsc0bdA"));
}
+ @Test
+ void getUserStreamsTest() throws ApiException {
+ this.mockApiClient.onGet(V4_USER_STREAMS,
+ "{\"streams\": [{\"id\": \"p9B316LKDto7iOECc8Xuz3qeWsc0bdA\", \"active\": true}], \"nextCursor\": \"cursor123\"}");
+
+ StreamArrayResponse response = this.service.getUserStreams(10, false, true, "Symphony", true, false, "cursor000");
+
+ assertNotNull(response);
+ assertEquals("cursor123", response.getNextCursor());
+ assertEquals(1, response.getStreams().size());
+ assertEquals("p9B316LKDto7iOECc8Xuz3qeWsc0bdA", response.getStreams().get(0).getId());
+ assertTrue(response.getStreams().get(0).getActive());
+ verify(this.userStreamsApi).listUserStreams(eq("1234"), eq(10), eq(false), eq(true), eq("Symphony"), eq(true), eq(false), eq("cursor000"));
+ }
+
+ @Test
+ void getUserStreamsInOboMode() throws ApiException {
+ this.mockApiClient.onGet(V4_USER_STREAMS,
+ "{\"streams\": [{\"id\": \"p9B316LKDto7iOECc8Xuz3qeWsc0bdA\", \"active\": true}], \"nextCursor\": \"cursor123\"}");
+
+ this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
+ this.userStreamsApi, new RetryWithRecoveryBuilder<>());
+ StreamArrayResponse response = this.service.obo(this.authSession).getUserStreams(null, null, null, null, null, null, null);
+
+ assertNotNull(response);
+ assertEquals("cursor123", response.getNextCursor());
+ assertEquals(1, response.getStreams().size());
+ assertEquals("p9B316LKDto7iOECc8Xuz3qeWsc0bdA", response.getStreams().get(0).getId());
+ verify(this.userStreamsApi).listUserStreams(eq("1234"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null));
+ }
+
+ @Test
+ void getUserStreamsTestFailed() {
+ this.mockApiClient.onGet(400, V4_USER_STREAMS, "{}");
+
+ assertThrows(ApiRuntimeException.class, () -> this.service.getUserStreams(10, false, true, "Symphony", true, false, "cursor000"));
+ }
+
+ @Test
+ void getUserStreamsShouldThrowExceptionWhenNoSession() {
+ this.service = new StreamService(this.streamsApi, this.spyRoomMembershipApi, this.shareApi, this.streamContextApi,
+ this.userStreamsApi, new RetryWithRecoveryBuilder<>());
+
+ assertThrows(IllegalStateException.class, () -> this.service.getUserStreams(null, null, null, null, null, null, null));
+ }
+
@Test
void createAdminIMorMIMTest() {
this.mockApiClient.onPost(V1_IM_CREATE_ADMIN, "{\n\"id\": \"xhGxbTcvTDK6EIMMrwdOrX___quztr2HdA\"\n}");
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkApiClientsConfig.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkApiClientsConfig.java
index b498c474a..b0cf40dff 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkApiClientsConfig.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkApiClientsConfig.java
@@ -1,6 +1,7 @@
package com.symphony.bdk.spring.config;
import com.symphony.bdk.gen.api.StreamContextApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
import com.symphony.bdk.http.api.ApiClient;
import com.symphony.bdk.gen.api.AppEntitlementApi;
import com.symphony.bdk.gen.api.ApplicationApi;
@@ -201,6 +202,12 @@ public StreamContextApi streamsContextApi(@Qualifier("agentApiClient") ApiClient
return new StreamContextApi(agentApiClient);
}
+ @Bean
+ @ConditionalOnMissingBean
+ public UserStreamsApi userStreamsApi(@Qualifier("streamApiClient") ApiClient streamApiClient) {
+ return new UserStreamsApi(streamApiClient);
+ }
+
@Bean
@ConditionalOnMissingBean
public SystemApi systemApi(@Qualifier("agentApiClient") ApiClient agentApiClient) {
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 30ed49ad2..6e938319d 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
@@ -59,6 +59,14 @@ public ApiClient agentApiClient(ApiClientFactory apiClientFactory, Optional botSession,
+ BdkConfig config) {
+ ApiClient client = apiClientFactory.getStreamClient();
+ addCommonJwtConfig(client, botSession, config);
+ return client;
+ }
+
@Bean(name = "datafeedAgentApiClient")
public ApiClient datafeedAgentApiClient(ApiClientFactory apiClientFactory, Optional botSession,
BdkConfig config) {
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkOboServiceConfig.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkOboServiceConfig.java
index 6abcf7c5e..aef449714 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkOboServiceConfig.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkOboServiceConfig.java
@@ -29,6 +29,7 @@
import com.symphony.bdk.gen.api.StreamContextApi;
import com.symphony.bdk.gen.api.StreamsApi;
import com.symphony.bdk.gen.api.UserApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
import com.symphony.bdk.gen.api.UsersApi;
import com.symphony.bdk.template.api.TemplateEngine;
@@ -74,8 +75,8 @@ public SessionService oboSessionService(SessionApi sessionApi, BdkConfig config)
@Bean
@ConditionalOnMissingBean
public StreamService oboStreamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipApi, ShareApi shareApi,
- StreamContextApi streamContextApi, BdkConfig config) {
- return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, new RetryWithRecoveryBuilder<>().retryConfig(config.getRetry()));
+ StreamContextApi streamContextApi, UserStreamsApi userStreamsApi, BdkConfig config) {
+ return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, userStreamsApi, new RetryWithRecoveryBuilder<>().retryConfig(config.getRetry()));
}
@Bean
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkServiceConfig.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkServiceConfig.java
index 5228a722e..f479931fb 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkServiceConfig.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkServiceConfig.java
@@ -34,6 +34,7 @@
import com.symphony.bdk.gen.api.StreamsApi;
import com.symphony.bdk.gen.api.SystemApi;
import com.symphony.bdk.gen.api.UserApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
import com.symphony.bdk.gen.api.UsersApi;
import com.symphony.bdk.spring.service.BotInfoService;
import com.symphony.bdk.template.api.TemplateEngine;
@@ -60,8 +61,8 @@ public SessionService sessionService(SessionApi sessionApi, AuthSession botSessi
@Bean
@ConditionalOnMissingBean
public StreamService streamService(StreamsApi streamsApi, RoomMembershipApi roomMembershipApi, ShareApi shareApi, StreamContextApi streamContextApi,
- AuthSession botSession, BdkConfig config) {
- return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, botSession, new RetryWithRecoveryBuilder<>().retryConfig(config.getRetry()));
+ UserStreamsApi userStreamsApi, AuthSession botSession, BdkConfig config) {
+ return new StreamService(streamsApi, roomMembershipApi, shareApi, streamContextApi, userStreamsApi, botSession, new RetryWithRecoveryBuilder<>().retryConfig(config.getRetry()));
}
@Bean
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 7bc1eac1f..9af684b3a 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
@@ -14,6 +14,7 @@
import com.symphony.bdk.core.service.datafeed.impl.DatahoseLoopImpl;
import com.symphony.bdk.core.service.health.HealthService;
import com.symphony.bdk.gen.api.SystemApi;
+import com.symphony.bdk.gen.api.UserStreamsApi;
import com.symphony.bdk.http.api.ApiClient;
import com.symphony.bdk.spring.annotation.SlashAnnotationProcessor;
import com.symphony.bdk.spring.config.BdkActivityConfig;
@@ -64,6 +65,8 @@ void shouldLoadContextWithSuccess() {
assertThat(context).hasSingleBean(HealthService.class);
assertThat(context).hasSingleBean(DatafeedAsyncLauncherService.class);
assertThat(context).hasSingleBean(RealTimeEventsDispatcher.class);
+ assertThat(context).hasSingleBean(UserStreamsApi.class);
+ assertThat(context).hasBean("streamApiClient");
// verify datahose not enabled by default
assertThat(context).doesNotHaveBean(DatahoseLoopImpl.class);
@@ -237,6 +240,11 @@ void shouldAddAuthenticationIfCommonJwtEnabled() {
ApiClient podClient = (ApiClient) context.getBean("podApiClient");
assertThat(podClient.getAuthentications()).isNotEmpty();
assertThat(podClient.getAuthentications()).containsKey("bearerAuth");
+
+ assertThat(context).hasBean("streamApiClient");
+ ApiClient streamClient = (ApiClient) context.getBean("streamApiClient");
+ assertThat(streamClient.getAuthentications()).isNotEmpty();
+ assertThat(streamClient.getAuthentications()).containsKey("bearerAuth");
});
}
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
index f9c7aec99..b9d107fd0 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
@@ -76,6 +76,19 @@ void shouldCreatePodClient() {
when(factory.getPodClient()).thenReturn(mock(ApiClient.class));
assertNotNull(config.podApiClient(factory, Optional.ofNullable(authSession), bdkConfig));
}
+
+ @Test
+ void shouldCreateStreamApiClient() {
+ final BdkCoreConfig config = new BdkCoreConfig();
+ final BdkConfig bdkConfig = new BdkConfig();
+ BdkCommonJwtConfig bdkCommonJwtConfig = new BdkCommonJwtConfig();
+ bdkCommonJwtConfig.setEnabled(true);
+ bdkConfig.setCommonJwt(bdkCommonJwtConfig);
+ final ApiClientFactory factory = mock(ApiClientFactory.class);
+ final AuthSession authSession = mock(AuthSession.class);
+ when(factory.getStreamClient()).thenReturn(mock(ApiClient.class));
+ assertNotNull(config.streamApiClient(factory, Optional.ofNullable(authSession), bdkConfig));
+ }
@Test
void shouldCreateKeyAuthApiClient() {
final BdkCoreConfig config = new BdkCoreConfig();