diff --git a/src/main/java/io/getstream/client/Client.java b/src/main/java/io/getstream/client/Client.java index 00783e97..c608597f 100644 --- a/src/main/java/io/getstream/client/Client.java +++ b/src/main/java/io/getstream/client/Client.java @@ -317,6 +317,12 @@ CompletableFuture unfollow(FeedID source, FeedID target, RequestOption return stream.unfollow(token, source, target, options); } + CompletableFuture getFollowStats( + FeedID feed, String[] followerSlugs, String[] followingSlugs) throws StreamException { + final Token token = buildFollowToken(secret, TokenAction.READ); + return stream.getFollowStats(token, feed, followerSlugs, followingSlugs); + } + CompletableFuture updateActivityToTargets( FeedID feed, Activity activity, FeedID[] add, FeedID[] remove, FeedID[] newTargets) throws StreamException { diff --git a/src/main/java/io/getstream/client/Feed.java b/src/main/java/io/getstream/client/Feed.java index 8e5dd238..74c951ea 100644 --- a/src/main/java/io/getstream/client/Feed.java +++ b/src/main/java/io/getstream/client/Feed.java @@ -3,12 +3,11 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static io.getstream.core.utils.Serialization.*; +import static io.getstream.core.utils.Serialization.deserializeContainer; import com.google.common.collect.Iterables; import io.getstream.core.exceptions.StreamException; -import io.getstream.core.models.Activity; -import io.getstream.core.models.FeedID; -import io.getstream.core.models.FollowRelation; +import io.getstream.core.models.*; import io.getstream.core.options.CustomQueryParameter; import io.getstream.core.options.Limit; import io.getstream.core.options.Offset; @@ -330,6 +329,23 @@ public final CompletableFuture unfollow( }); } + public final CompletableFuture getFollowStats( + Iterable followerSlugs, Iterable followingSlugs) throws StreamException { + return client + .getFollowStats( + id, + Iterables.toArray(followerSlugs, String.class), + Iterables.toArray(followingSlugs, String.class)) + .thenApply( + response -> { + try { + return deserializeContainerSingleItem(response, FollowStats.class); + } catch (StreamException | IOException e) { + throw new CompletionException(e); + } + }); + } + public final CompletableFuture updateActivityToTargets( Activity activity, Iterable add, Iterable remove) throws StreamException { return updateActivityToTargets( diff --git a/src/main/java/io/getstream/core/Stream.java b/src/main/java/io/getstream/core/Stream.java index 02fc1bd2..68b12da1 100644 --- a/src/main/java/io/getstream/core/Stream.java +++ b/src/main/java/io/getstream/core/Stream.java @@ -20,6 +20,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @@ -372,6 +373,34 @@ public CompletableFuture unfollow( } } + public CompletableFuture getFollowStats( + Token token, + FeedID feed, + String[] followerSlugs, + String[] followingSlugs, + RequestOption... options) + throws StreamException { + try { + final URL url = followStatsPath(baseURL); + final List params = new ArrayList<>(4); + final String feedId = String.join(":", feed.getSlug(), feed.getUserID()); + params.add(new CustomQueryParameter("followers", feedId)); + params.add(new CustomQueryParameter("following", feedId)); + + if (followerSlugs != null && followerSlugs.length > 0) { + params.add(new CustomQueryParameter("followers_slugs", String.join(",", followerSlugs))); + } + if (followingSlugs != null && followingSlugs.length > 0) { + params.add(new CustomQueryParameter("following_slugs", String.join(",", followingSlugs))); + } + + return httpClient.execute( + buildGet(url, key, token, params.toArray(new CustomQueryParameter[0]))); + } catch (MalformedURLException | URISyntaxException e) { + throw new StreamException(e); + } + } + public CompletableFuture updateActivityToTargets( Token token, FeedID feed, Activity activity, FeedID[] add, FeedID[] remove, FeedID[] replace) throws StreamException { diff --git a/src/main/java/io/getstream/core/models/FollowStats.java b/src/main/java/io/getstream/core/models/FollowStats.java new file mode 100644 index 00000000..0da0d170 --- /dev/null +++ b/src/main/java/io/getstream/core/models/FollowStats.java @@ -0,0 +1,37 @@ +package io.getstream.core.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public final class FollowStats { + @JsonProperty(value = "followers") + private FollowStat followers; + + @JsonProperty(value = "following") + private FollowStat following; + + public FollowStat getFollowers() { + return followers; + } + + public FollowStat getFollowing() { + return following; + } + + public class FollowStat { + @JsonProperty(value = "count") + private int count; + + @JsonProperty(value = "feed") + private String feed; + + public int getCount() { + return count; + } + + public String getFeed() { + return feed; + } + } +} diff --git a/src/main/java/io/getstream/core/utils/Routes.java b/src/main/java/io/getstream/core/utils/Routes.java index 5ed27332..40c6026f 100644 --- a/src/main/java/io/getstream/core/utils/Routes.java +++ b/src/main/java/io/getstream/core/utils/Routes.java @@ -25,6 +25,7 @@ public final class Routes { private static final String reactionsPath = "reaction/"; private static final String toTargetUpdatePath = "/activity_to_targets/"; private static final String usersPath = "user/"; + private static final String followStatsPath = "stats/follow/"; private Routes() { /* nothing to see here */ @@ -112,6 +113,10 @@ public static URL buildUnfollowManyURL(URL baseURL) throws MalformedURLException return new URL(baseURL, basePath + unfollowManyPath); } + public static URL followStatsPath(URL baseURL) throws MalformedURLException { + return new URL(baseURL, basePath + followStatsPath); + } + private static URL buildSubdomainPath(URL baseURL, String subdomain, String apiPath, String path) throws MalformedURLException { try { diff --git a/src/main/java/io/getstream/core/utils/Serialization.java b/src/main/java/io/getstream/core/utils/Serialization.java index 976b53e0..2d7b473e 100644 --- a/src/main/java/io/getstream/core/utils/Serialization.java +++ b/src/main/java/io/getstream/core/utils/Serialization.java @@ -90,6 +90,16 @@ public static List deserializeContainer( throw deserializeException(response); } + public static T deserializeContainerSingleItem(Response response, Class element) + throws IOException, StreamException { + if (normalResponseCodes.contains(response.getCode())) { + return fromJSON( + response.getBody(), "results", mapper.getTypeFactory().constructType(element)); + } + + throw deserializeException(response); + } + public static T deserializeContainer(Response response, String wrapper, JavaType element) throws IOException, StreamException { if (normalResponseCodes.contains(response.getCode())) { diff --git a/src/test/java/io/getstream/client/FeedTest.java b/src/test/java/io/getstream/client/FeedTest.java index 9517b680..6bc07e8b 100644 --- a/src/test/java/io/getstream/client/FeedTest.java +++ b/src/test/java/io/getstream/client/FeedTest.java @@ -1,5 +1,7 @@ package io.getstream.client; +import static org.junit.Assert.assertEquals; + import com.google.common.collect.Lists; import io.getstream.client.entities.FootballMatch; import io.getstream.client.entities.Match; @@ -7,8 +9,11 @@ import io.getstream.core.http.OKHTTPClientAdapter; import io.getstream.core.models.Activity; import io.getstream.core.models.FeedID; +import io.getstream.core.models.FollowStats; +import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.UUID; import okhttp3.OkHttpClient; import org.junit.Test; @@ -140,6 +145,33 @@ public void unfollow() throws Exception { feed1.unfollow(feed2).join(); } + @Test + public void getFollowStats() throws Exception { + Client client = + Client.builder(apiKey, secret) + .httpClient(new OKHTTPClientAdapter(new OkHttpClient())) + .build(); + String uuid1 = UUID.randomUUID().toString().replace("-", ""); + String uuid2 = UUID.randomUUID().toString().replace("-", ""); + String feed1Id = "flat:" + uuid1; + FlatFeed feed1 = client.flatFeed("flat", uuid1); + FlatFeed feed2 = client.flatFeed("flat", uuid2); + feed1.follow(feed2).join(); + + FollowStats stats = + feed1.getFollowStats(Collections.emptyList(), Lists.newArrayList("timeline")).join(); + assertEquals(0, stats.getFollowers().getCount()); + assertEquals(feed1Id, stats.getFollowers().getFeed()); + assertEquals(0, stats.getFollowing().getCount()); + assertEquals(feed1Id, stats.getFollowing().getFeed()); + + stats = feed1.getFollowStats(Collections.emptyList(), Lists.newArrayList("flat")).join(); + assertEquals(0, stats.getFollowers().getCount()); + assertEquals(feed1Id, stats.getFollowers().getFeed()); + assertEquals(1, stats.getFollowing().getCount()); + assertEquals(feed1Id, stats.getFollowing().getFeed()); + } + @Test public void updateActivityToTargets() throws Exception { Client client =