From e504537fa892c53622712f691ceeb83eb422aae6 Mon Sep 17 00:00:00 2001 From: peterdeme Date: Mon, 25 Apr 2022 15:34:14 +0200 Subject: [PATCH 1/2] feat(stats): add followstats --- src/main/java/io/getstream/client/Client.java | 6 +++ src/main/java/io/getstream/client/Feed.java | 22 +++++++++-- src/main/java/io/getstream/core/Stream.java | 29 +++++++++++++++ .../io/getstream/core/models/FollowStats.java | 37 +++++++++++++++++++ .../java/io/getstream/core/utils/Routes.java | 5 +++ .../getstream/core/utils/Serialization.java | 10 +++++ .../java/io/getstream/client/FeedTest.java | 26 +++++++++++++ 7 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/getstream/core/models/FollowStats.java 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..11af92b7 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,6 +9,8 @@ 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 okhttp3.OkHttpClient; @@ -140,6 +144,28 @@ 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 feed1Id = "flat:1"; + FlatFeed feed1 = client.flatFeed("flat", "1"); + FlatFeed feed2 = client.flatFeed("flat", "2"); + feed1.follow(feed2).join(); + + FollowStats stats = + feed1.getFollowStats(Collections.emptyList(), Lists.newArrayList("timeline")).join(); + assertEquals(0, stats.getFollowers().getCount()); + assertEquals(feed1Id, stats.getFollowers().getFeed()); + + stats = feed1.getFollowStats(Collections.emptyList(), Lists.newArrayList("user")).join(); + assertEquals(0, stats.getFollowers().getCount()); + assertEquals(feed1Id, stats.getFollowers().getFeed()); + assertEquals(feed1Id, stats.getFollowing().getFeed()); + } + @Test public void updateActivityToTargets() throws Exception { Client client = From d3e9b9cb81f35d8e1de6b4efadfff182f84db847 Mon Sep 17 00:00:00 2001 From: peterdeme Date: Tue, 26 Apr 2022 11:41:45 +0200 Subject: [PATCH 2/2] fix: pr comment fixes --- src/test/java/io/getstream/client/FeedTest.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/test/java/io/getstream/client/FeedTest.java b/src/test/java/io/getstream/client/FeedTest.java index 11af92b7..6bc07e8b 100644 --- a/src/test/java/io/getstream/client/FeedTest.java +++ b/src/test/java/io/getstream/client/FeedTest.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.UUID; import okhttp3.OkHttpClient; import org.junit.Test; @@ -150,19 +151,24 @@ public void getFollowStats() throws Exception { Client.builder(apiKey, secret) .httpClient(new OKHTTPClientAdapter(new OkHttpClient())) .build(); - String feed1Id = "flat:1"; - FlatFeed feed1 = client.flatFeed("flat", "1"); - FlatFeed feed2 = client.flatFeed("flat", "2"); + 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("user")).join(); + 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()); }