Skip to content

Commit 516fc3d

Browse files
authored
[FEEDS-268] unfollowMany (#162)
* chore: unfollowMany * chore: unfollowMany * chore: unfollowMany * chore: unfollowMany * chore: fix old unrelated FlagActivity test
1 parent 40b502a commit 516fc3d

File tree

5 files changed

+192
-0
lines changed

5 files changed

+192
-0
lines changed

src/BatchOperations.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,28 @@ public async Task<ResponseBase> FollowManyAsync(IEnumerable<Follow> follows, int
5656
throw StreamException.FromResponse(response);
5757
}
5858

59+
public async Task<ResponseBase> UnfollowManyAsync(IEnumerable<UnfollowRelation> unfollows)
60+
{
61+
var request = _client.BuildAppRequest("unfollow_many/", HttpMethod.Post);
62+
63+
// Create a new anonymous object array with the properties expected by the API
64+
var unfollowRequests = unfollows.Select(f => new
65+
{
66+
source = f.Source,
67+
target = f.Target,
68+
keep_history = f.KeepHistory
69+
});
70+
71+
request.SetJsonBody(StreamJsonConverter.SerializeObject(unfollowRequests));
72+
73+
var response = await _client.MakeRequestAsync(request);
74+
75+
if (response.StatusCode == HttpStatusCode.Created || response.StatusCode == HttpStatusCode.OK)
76+
return StreamJsonConverter.DeserializeObject<ResponseBase>(response.Content);
77+
78+
throw StreamException.FromResponse(response);
79+
}
80+
5981
public async Task<GenericGetResponse<Activity>> GetActivitiesByIdAsync(IEnumerable<string> ids)
6082
=> await GetActivitiesAsync(ids, null);
6183

src/IBatchOperations.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ public interface IBatchOperations
2121
/// <summary>Follow muiltiple feeds.</summary>
2222
/// <remarks>https://getstream.io/activity-feeds/docs/dotnet-csharp/add_many_activities/?language=csharp</remarks>
2323
Task<ResponseBase> FollowManyAsync(IEnumerable<Follow> follows, int activityCopyLimit = 100);
24+
25+
/// <summary>Unfollow multiple feeds in a single request using UnfollowRelation objects.</summary>
26+
/// <remarks>https://getstream.io/activity-feeds/docs/dotnet-csharp/add_many_activities/?language=csharp</remarks>
27+
Task<ResponseBase> UnfollowManyAsync(IEnumerable<UnfollowRelation> unfollows);
2428

2529
/// <summary>Get multiple activities by activity ids.</summary>
2630
/// <remarks>https://getstream.io/activity-feeds/docs/dotnet-csharp/add_many_activities/?language=csharp</remarks>

src/Models/UnfollowRelation.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
namespace Stream.Models
2+
{
3+
/// <summary>
4+
/// Represents a relationship to unfollow in batch operations
5+
/// </summary>
6+
public class UnfollowRelation
7+
{
8+
/// <summary>
9+
/// Source feed id
10+
/// </summary>
11+
public string Source { get; set; }
12+
13+
/// <summary>
14+
/// Target feed id
15+
/// </summary>
16+
public string Target { get; set; }
17+
18+
/// <summary>
19+
/// Whether to keep activities from the unfollowed feed
20+
/// </summary>
21+
public bool KeepHistory { get; set; }
22+
23+
/// <summary>
24+
/// Creates a new instance of the UnfollowRelation class
25+
/// </summary>
26+
/// <param name="source">Source feed id</param>
27+
/// <param name="target">Target feed id</param>
28+
/// <param name="keepHistory">Whether to keep activities from the unfollowed feed</param>
29+
public UnfollowRelation(string source, string target, bool keepHistory = false)
30+
{
31+
Source = source;
32+
Target = target;
33+
KeepHistory = keepHistory;
34+
}
35+
36+
/// <summary>
37+
/// Creates a new instance of the UnfollowRelation class
38+
/// </summary>
39+
/// <param name="source">Source feed</param>
40+
/// <param name="target">Target feed</param>
41+
/// <param name="keepHistory">Whether to keep activities from the unfollowed feed</param>
42+
public UnfollowRelation(IStreamFeed source, IStreamFeed target, bool keepHistory = false)
43+
{
44+
Source = source.FeedId;
45+
Target = target.FeedId;
46+
KeepHistory = keepHistory;
47+
}
48+
}
49+
}

tests/BatchTests.cs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,28 @@ namespace StreamNetTests
1010
[TestFixture]
1111
public class BatchTests : TestBase
1212
{
13+
[Test]
14+
public void TestUnfollowManyArgumentValidation()
15+
{
16+
// Should work with empty array
17+
Assert.DoesNotThrowAsync(async () =>
18+
{
19+
await Client.Batch.UnfollowManyAsync(new UnfollowRelation[] { });
20+
});
21+
22+
// Should work with valid unfollow relation objects
23+
Assert.DoesNotThrowAsync(async () =>
24+
{
25+
await Client.Batch.UnfollowManyAsync(new[] { new UnfollowRelation("user:1", "user:2", false) });
26+
});
27+
28+
// Should work with keepHistory true
29+
Assert.DoesNotThrowAsync(async () =>
30+
{
31+
await Client.Batch.UnfollowManyAsync(new[] { new UnfollowRelation("user:1", "user:2", true) });
32+
});
33+
}
34+
1335
[Test]
1436
public void TestGetEnrichedActivitiesArgumentValidation()
1537
{
@@ -305,5 +327,93 @@ public async Task TestBatchActivityForeignIdTime()
305327

306328
Assert.AreEqual(1, result.Results.Count);
307329
}
330+
331+
[Test]
332+
public async Task TestBatchUnfollowManyKeepHistoryFalse()
333+
{
334+
// First set up follows and add activities
335+
await Client.Batch.FollowManyAsync(new[]
336+
{
337+
new Follow(UserFeed, FlatFeed),
338+
new Follow(UserFeed2, FlatFeed),
339+
});
340+
341+
var newActivity = new Activity("1", "test", "1");
342+
var response = await this.FlatFeed.AddActivityAsync(newActivity);
343+
344+
// Verify follows are working
345+
var activities1 = (await this.UserFeed.GetActivitiesAsync(0, 1)).Results;
346+
var activities2 = (await this.UserFeed2.GetActivitiesAsync(0, 1)).Results;
347+
348+
Assert.IsNotNull(activities1);
349+
Assert.AreEqual(1, activities1.Count());
350+
Assert.AreEqual(response.Id, activities1.First().Id);
351+
352+
Assert.IsNotNull(activities2);
353+
Assert.AreEqual(1, activities2.Count());
354+
Assert.AreEqual(response.Id, activities2.First().Id);
355+
356+
// Use UnfollowMany with keepHistory=false
357+
await Client.Batch.UnfollowManyAsync(new[]
358+
{
359+
new UnfollowRelation(UserFeed, FlatFeed, false),
360+
new UnfollowRelation(UserFeed2, FlatFeed, false),
361+
});
362+
363+
// Verify activities are removed
364+
activities1 = (await this.UserFeed.GetActivitiesAsync(0, 1)).Results;
365+
activities2 = (await this.UserFeed2.GetActivitiesAsync(0, 1)).Results;
366+
367+
Assert.IsNotNull(activities1);
368+
Assert.AreEqual(0, activities1.Count());
369+
370+
Assert.IsNotNull(activities2);
371+
Assert.AreEqual(0, activities2.Count());
372+
}
373+
374+
[Test]
375+
public async Task TestBatchUnfollowManyKeepHistoryTrue()
376+
{
377+
// First set up follows and add activities
378+
await Client.Batch.FollowManyAsync(new[]
379+
{
380+
new Follow(UserFeed, FlatFeed),
381+
new Follow(UserFeed2, FlatFeed),
382+
});
383+
384+
var newActivity = new Activity("1", "test", "1");
385+
var response = await this.FlatFeed.AddActivityAsync(newActivity);
386+
387+
// Verify follows are working
388+
var activities1 = (await this.UserFeed.GetActivitiesAsync(0, 1)).Results;
389+
var activities2 = (await this.UserFeed2.GetActivitiesAsync(0, 1)).Results;
390+
391+
Assert.IsNotNull(activities1);
392+
Assert.AreEqual(1, activities1.Count());
393+
Assert.AreEqual(response.Id, activities1.First().Id);
394+
395+
Assert.IsNotNull(activities2);
396+
Assert.AreEqual(1, activities2.Count());
397+
Assert.AreEqual(response.Id, activities2.First().Id);
398+
399+
// Use UnfollowMany with keepHistory=true
400+
await Client.Batch.UnfollowManyAsync(new[]
401+
{
402+
new UnfollowRelation(UserFeed, FlatFeed, true),
403+
new UnfollowRelation(UserFeed2, FlatFeed, true),
404+
});
405+
406+
// Verify activities are retained
407+
activities1 = (await this.UserFeed.GetActivitiesAsync(0, 1)).Results;
408+
activities2 = (await this.UserFeed2.GetActivitiesAsync(0, 1)).Results;
409+
410+
Assert.IsNotNull(activities1);
411+
Assert.AreEqual(1, activities1.Count());
412+
Assert.AreEqual(response.Id, activities1.First().Id);
413+
414+
Assert.IsNotNull(activities2);
415+
Assert.AreEqual(1, activities2.Count());
416+
Assert.AreEqual(response.Id, activities2.First().Id);
417+
}
308418
}
309419
}

tests/ModerationTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ public async Task TestFlagActivity()
9898
newActivity.SetData<string>("stringint", "42");
9999
newActivity.SetData<string>("stringdouble", "42.2");
100100
newActivity.SetData<string>("stringcomplex", "{ \"test1\": 1, \"test2\": \"testing\" }");
101+
102+
// Set moderation data with origin_feed
103+
var moderationData = new Dictionary<string, object>
104+
{
105+
{ "origin_feed", this.UserFeed.FeedId }
106+
};
107+
newActivity.SetData("moderation", moderationData);
101108

102109
var response = await this.UserFeed.AddActivityAsync(newActivity);
103110
Assert.IsNotNull(response);

0 commit comments

Comments
 (0)