diff --git a/src/IStreamFeed.cs b/src/IStreamFeed.cs index 1fc0cd9..3dcf972 100644 --- a/src/IStreamFeed.cs +++ b/src/IStreamFeed.cs @@ -28,6 +28,8 @@ public interface IStreamFeed /// https://getstream.io/activity-feeds/docs/dotnet-csharp/feeds_101/?language=csharp Task AddActivitiesAsync(IEnumerable activities); + Task BatchUpdateActivityToTargetsAsync(List reqs); + /// Add a new activity to the feed. /// https://getstream.io/activity-feeds/docs/dotnet-csharp/feeds_101/?language=csharp Task AddActivityAsync(Activity activity); diff --git a/src/Models/UpdateToTargets.cs b/src/Models/UpdateToTargets.cs new file mode 100644 index 0000000..850a283 --- /dev/null +++ b/src/Models/UpdateToTargets.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Stream.Models +{ + public class UpdateToTargetsRequest + { + [JsonProperty("foreign_id")] + public string ForeignID { get; set; } + + [JsonProperty("time")] + public string Time { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("new_targets")] + public List NewTargets { get; set; } + + [JsonProperty("added_targets")] + public List Adds { get; set; } + + [JsonProperty("removed_targets")] + public List RemovedTargets { get; set; } + } +} diff --git a/src/StreamFeed.cs b/src/StreamFeed.cs index e2693f2..2c804b5 100644 --- a/src/StreamFeed.cs +++ b/src/StreamFeed.cs @@ -127,6 +127,24 @@ public async Task> GetActivitiesAsync(int offset = throw StreamException.FromResponse(response); } + public async Task BatchUpdateActivityToTargetsAsync(List reqs) + { + var endpoint = $"feed_targets/{_feedSlug}/{_userId}/activity_to_targets/"; + + var request = _client.BuildAppRequest(endpoint, HttpMethod.Post); + request.SetJsonBody(StreamJsonConverter.SerializeObject(reqs)); + var response = await _client.MakeRequestAsync(request); + if (response.StatusCode != HttpStatusCode.Created) + { + throw new HttpRequestException($"Request failed with status code {response.StatusCode}"); + } + + if (response.StatusCode == HttpStatusCode.Created) + return StreamJsonConverter.DeserializeObject(response.Content); + + throw StreamException.FromResponse(response); + } + public async Task UpdateActivityToTargetsAsync(string id, IEnumerable adds = null, IEnumerable newTargets = null, @@ -136,6 +154,8 @@ public async Task UpdateActivityToTargetsAsync(string i newTargets?.ForEach(FeedIdValidator.ThrowIfFeedIdIsInvalid); removed?.ForEach(FeedIdValidator.ThrowIfFeedIdIsInvalid); + + var payload = new { id = id, diff --git a/tests/ActivityTests/UpdateActivityTests.cs b/tests/ActivityTests/UpdateActivityTests.cs index 1671e6c..ff3239c 100644 --- a/tests/ActivityTests/UpdateActivityTests.cs +++ b/tests/ActivityTests/UpdateActivityTests.cs @@ -164,6 +164,96 @@ public async Task TestUpdateToTargets() Assert.AreEqual(2, updatedAct.To.ToList().FindAll(t => newOnes.Contains(t)).Count); } + [Test] + public async Task TestBatchUpdateToTargets() + { + var fidTime = new ForeignIdTime(Guid.NewGuid().ToString(), DateTime.UtcNow); + + var targets = new List() + { + "flat:" + Guid.NewGuid().ToString(), + "user:" + Guid.NewGuid().ToString(), + }; + + var act = new Activity("upd", "test", "1") + { + ForeignId = fidTime.ForeignId, + Time = fidTime.Time, + To = targets, + }; + + var insertedAct = await this.UserFeed.AddActivityAsync(act); + Assert.AreEqual(2, insertedAct.To.Count); + + // add 1 + var add = "user:" + Guid.NewGuid().ToString(); + var updateReqs = new List + { + new UpdateToTargetsRequest + { + Id = insertedAct.Id, + Adds = new List { add }, + } + }; + var updateResp = await this.UserFeed.BatchUpdateActivityToTargetsAsync(updateReqs); + Assert.AreEqual(insertedAct.Id, updateResp.Activity.Id); + Assert.AreEqual(1, updateResp.Added.Count); + Assert.AreEqual(add, updateResp.Added[0]); + Assert.AreEqual(3, updateResp.Activity.To.Count); + Assert.IsNotNull(updateResp.Activity.To.ToList().Find(t => t == add)); + + var updatedAct = (await this.UserFeed.GetActivitiesAsync(0, 1, FeedFilter.Where().IdLessThanEqual(insertedAct.Id))).Results.FirstOrDefault(); + Assert.NotNull(updatedAct); + Assert.AreEqual(3, updatedAct.To.Count); + Assert.IsNotNull(updatedAct.To.ToList().Find(t => t == add)); + + // remove 1 + var remove = targets[0]; + updateReqs = new List + { + new UpdateToTargetsRequest + { + Id = insertedAct.Id, + RemovedTargets = new List { remove }, + } + }; + updateResp = await this.UserFeed.BatchUpdateActivityToTargetsAsync(updateReqs); + Assert.AreEqual(insertedAct.Id, updateResp.Activity.Id); + Assert.AreEqual(1, updateResp.Removed.Count); + Assert.AreEqual(remove, updateResp.Removed[0]); + Assert.AreEqual(2, updateResp.Activity.To.Count); + Assert.IsNull(updateResp.Activity.To.ToList().Find(t => t == remove)); + + updatedAct = (await this.UserFeed.GetActivitiesAsync(0, 1, FeedFilter.Where().IdLessThanEqual(insertedAct.Id))).Results.FirstOrDefault(); + Assert.NotNull(updatedAct); + Assert.AreEqual(2, updatedAct.To.Count); + Assert.IsNull(updatedAct.To.ToList().Find(t => t == remove)); + + // new ones + var newOnes = new List() + { + "flat:" + Guid.NewGuid().ToString(), + "user:" + Guid.NewGuid().ToString(), + }; + updateReqs = new List + { + new UpdateToTargetsRequest + { + Id = insertedAct.Id, + NewTargets = newOnes, + } + }; + updateResp = await this.UserFeed.BatchUpdateActivityToTargetsAsync(updateReqs); + Assert.AreEqual(insertedAct.Id, updateResp.Activity.Id); + Assert.AreEqual(2, updateResp.Activity.To.Count); + Assert.AreEqual(2, updateResp.Added.Count); + Assert.AreEqual(2, updateResp.Added.ToList().FindAll(t => newOnes.Contains(t)).Count); + updatedAct = (await this.UserFeed.GetActivitiesAsync(0, 1, FeedFilter.Where().IdLessThanEqual(insertedAct.Id))).Results.FirstOrDefault(); + Assert.NotNull(updatedAct); + Assert.AreEqual(2, updatedAct.To.Count); + Assert.AreEqual(2, updatedAct.To.ToList().FindAll(t => newOnes.Contains(t)).Count); + } + [Test] public async Task TestActivityPartialUpdateByForeignIDTime() { diff --git a/tests/ClientTests.cs b/tests/ClientTests.cs index 855fde2..90ed6f1 100644 --- a/tests/ClientTests.cs +++ b/tests/ClientTests.cs @@ -115,7 +115,24 @@ public void TestToken() Assert.AreEqual(true, (bool)result["testing"]); Assert.False(result.ContainsKey("missing")); } + + [Test] + public void TestModerationToken() + { + var result = DecodeJwt(Client.CreateUserToken("user")); + Assert.AreEqual("user", (string)result["user_id"]); + + var extra = new Dictionary() + { + { "client", "dotnet" }, + { "required_moderation_template", "mod_template_1" }, + }; + result = DecodeJwt(Client.CreateUserToken("user2", extra)); + Assert.AreEqual("mod_template_1", (string)result["required_moderation_template"]); + Assert.False(result.ContainsKey("missing")); + } + private Dictionary DecodeJwt(string token) { var segment = token.Split('.')[1];