diff --git a/src/main/java/io/getstream/client/ReactionsClient.java b/src/main/java/io/getstream/client/ReactionsClient.java index f42db8e6..abdd5343 100644 --- a/src/main/java/io/getstream/client/ReactionsClient.java +++ b/src/main/java/io/getstream/client/ReactionsClient.java @@ -12,6 +12,7 @@ import io.getstream.core.models.FeedID; import io.getstream.core.models.Paginated; import io.getstream.core.models.Reaction; +import io.getstream.core.models.ReactionBatch; import io.getstream.core.options.Filter; import io.getstream.core.options.Limit; import io.getstream.core.utils.Auth.TokenAction; @@ -33,6 +34,11 @@ public CompletableFuture get(String id) throws StreamException { return reactions.get(token, id); } + public CompletableFuture getBatch(List ids) throws StreamException { + final Token token = buildReactionsToken(secret, TokenAction.READ); + return reactions.getBatchReactions(token, ids); + } + public CompletableFuture> filter(LookupKind lookup, String id) throws StreamException { return filter(lookup, id, DefaultOptions.DEFAULT_FILTER, DefaultOptions.DEFAULT_LIMIT, ""); diff --git a/src/main/java/io/getstream/core/StreamReactions.java b/src/main/java/io/getstream/core/StreamReactions.java index 7aa2aa28..f8a08bc9 100644 --- a/src/main/java/io/getstream/core/StreamReactions.java +++ b/src/main/java/io/getstream/core/StreamReactions.java @@ -5,6 +5,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.getstream.core.utils.Request.*; import static io.getstream.core.utils.Routes.buildReactionsURL; +import static io.getstream.core.utils.Routes.buildGetReactionsBatchURL; import static io.getstream.core.utils.Serialization.*; import com.fasterxml.jackson.core.JsonProcessingException; @@ -17,6 +18,7 @@ import io.getstream.core.models.FeedID; import io.getstream.core.models.Paginated; import io.getstream.core.models.Reaction; +import io.getstream.core.models.ReactionBatch; import io.getstream.core.options.CustomQueryParameter; import io.getstream.core.options.Filter; import io.getstream.core.options.Limit; @@ -341,4 +343,29 @@ public CompletableFuture restore(Token token, String id) throws StreamExce throw new StreamException(e); } } + + public CompletableFuture getBatchReactions(Token token, List ids) throws StreamException { + checkNotNull(ids, "Reaction IDs can't be null"); + checkArgument(!ids.isEmpty(), "Reaction IDs can't be empty"); + + try { + final URL url = buildGetReactionsBatchURL(baseURL); + RequestOption optionIds = + new CustomQueryParameter( + "ids", String.join(",", ids)); + + return httpClient + .execute(buildGet(url, key, token, optionIds)) + .thenApply( + response -> { + try { + return deserialize(response, ReactionBatch.class); + } catch (StreamException | IOException e) { + throw new CompletionException(e); + } + }); + } catch (MalformedURLException | URISyntaxException e) { + throw new StreamException(e); + } + } } diff --git a/src/main/java/io/getstream/core/models/ReactionBatch.java b/src/main/java/io/getstream/core/models/ReactionBatch.java new file mode 100644 index 00000000..119dc1cf --- /dev/null +++ b/src/main/java/io/getstream/core/models/ReactionBatch.java @@ -0,0 +1,31 @@ +package io.getstream.core.models; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ReactionBatch { + + @JsonProperty("reactions") + private List reactions; + + @JsonProperty("duration") + private String duration; + + public ReactionBatch() { + } + + public ReactionBatch(List reactions) { + this.reactions = reactions; + } + + public List getReactions() { + return reactions; + } + + public void setReactions(List reactions) { + this.reactions = reactions; + } +} \ No newline at end of file diff --git a/src/main/java/io/getstream/core/utils/Routes.java b/src/main/java/io/getstream/core/utils/Routes.java index 14f16b3e..dbab60a6 100644 --- a/src/main/java/io/getstream/core/utils/Routes.java +++ b/src/main/java/io/getstream/core/utils/Routes.java @@ -24,6 +24,7 @@ public final class Routes { private static final String imagesPath = "images/"; private static final String openGraphPath = "og/"; private static final String reactionsPath = "reaction/"; + private static final String reactionsBatchPath = "reaction/get_many/"; private static final String toTargetUpdatePath = "/activity_to_targets/"; private static final String usersPath = "user/"; private static final String followStatsPath = "stats/follow/"; @@ -70,6 +71,10 @@ public static URL buildReactionsURL(URL baseURL, String path) throws MalformedUR return new URL(baseURL, basePath + reactionsPath + path); } + public static URL buildGetReactionsBatchURL(URL baseURL) throws MalformedURLException { + return new URL(baseURL, basePath + reactionsBatchPath); +} + public static URL buildUsersURL(URL baseURL) throws MalformedURLException { return new URL(baseURL, basePath + usersPath); } diff --git a/src/test/java/io/getstream/client/ReactionsClientTest.java b/src/test/java/io/getstream/client/ReactionsClientTest.java index ba4d784d..8cc878b9 100644 --- a/src/test/java/io/getstream/client/ReactionsClientTest.java +++ b/src/test/java/io/getstream/client/ReactionsClientTest.java @@ -1,11 +1,12 @@ package io.getstream.client; import io.getstream.core.LookupKind; -import io.getstream.core.models.Activity; -import io.getstream.core.models.FeedID; -import io.getstream.core.models.Paginated; -import io.getstream.core.models.Reaction; +import io.getstream.core.models.*; + import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import io.getstream.core.options.Filter; import io.getstream.core.options.Limit; @@ -85,6 +86,38 @@ public void filterWithUserID() throws Exception { assertEquals(1, result.size()); } + @Test + public void batchFetchReactions() throws Exception { + Client client = Client.builder(apiKey, secret).build(); + + Activity activity = + client + .flatFeed("flat", "reactor") + .addActivity(Activity.builder().actor("this").verb("done").object("that").build()) + .join(); + + Reaction r1=client.reactions().add("user1", "like", activity.getID()).join(); + Reaction r2=client.reactions().add("user1", "comment", activity.getID()).join(); + Reaction r3=client.reactions().add("user1", "share", activity.getID()).join(); + Reaction r4=client.reactions().add("user2", "like", activity.getID()).join(); + Reaction r5=client.reactions().add("user2", "comment", activity.getID()).join(); + Reaction r6=client.reactions().add("user3", "comment", activity.getID()).join(); + + Map reactionsRequest = Map.of(r1.getId(), r1, r2.getId(), r2, r3.getId(), r3, r4.getId(), r4, r5.getId(), r5, r6.getId(), r6); + + ReactionBatch response = client.reactions().getBatch(List.of(r1.getId(), r2.getId(), r3.getId(), r4.getId(), r5.getId(), r6.getId())).join(); + List result = response.getReactions(); + + //convert result to map and compare each id and type mapping from reactionsRequest to result + Map resultMap = result.stream().collect(Collectors.toMap(Reaction::getId, Function.identity())); + assertEquals(6, resultMap.size()); + for (Reaction r : result) { + Reaction req = reactionsRequest.get(r.getId()); + assertEquals(req.getActivityID(), r.getActivityID()); + assertEquals(req.getKind(), r.getKind()); + } + } + @Test public void pagedFilter() throws Exception { Client client = Client.builder(apiKey, secret).build();