diff --git a/src/BirdsiteLive.Domain/BusinessUseCases/ProcessUnfollowUser.cs b/src/BirdsiteLive.Domain/BusinessUseCases/ProcessUnfollowUser.cs
index 4d5483a..a8a53b4 100644
--- a/src/BirdsiteLive.Domain/BusinessUseCases/ProcessUnfollowUser.cs
+++ b/src/BirdsiteLive.Domain/BusinessUseCases/ProcessUnfollowUser.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Linq;
+using System.Threading.Tasks;
using BirdsiteLive.DAL.Contracts;
namespace BirdsiteLive.Domain.BusinessUseCases
@@ -38,8 +39,16 @@ namespace BirdsiteLive.Domain.BusinessUseCases
if (follower.FollowingsSyncStatus.ContainsKey(twitterUserId))
follower.FollowingsSyncStatus.Remove(twitterUserId);
- // Save Follower
- await _followerDal.UpdateFollowerAsync(follower);
+ // Save or delete Follower
+ if (follower.Followings.Any())
+ await _followerDal.UpdateFollowerAsync(follower);
+ else
+ await _followerDal.DeleteFollowerAsync(followerUsername, followerDomain);
+
+ // Check if TwitterUser has still followers
+ var followers = await _followerDal.GetFollowersAsync(twitterUser.Id);
+ if (!followers.Any())
+ await _twitterUserDal.DeleteTwitterUserAsync(twitterUsername);
}
}
}
\ No newline at end of file
diff --git a/src/BirdsiteLive.Domain/UserService.cs b/src/BirdsiteLive.Domain/UserService.cs
index 221ff4f..42feb39 100644
--- a/src/BirdsiteLive.Domain/UserService.cs
+++ b/src/BirdsiteLive.Domain/UserService.cs
@@ -137,7 +137,7 @@ namespace BirdsiteLive.Domain
if (!sigValidation.SignatureIsValidated) return false;
// Save Follow in DB
- var followerUserName = sigValidation.User.name.ToLowerInvariant();
+ var followerUserName = sigValidation.User.preferredUsername.ToLowerInvariant();
var followerHost = sigValidation.User.url.Replace("https://", string.Empty).Split('/').First();
//var followerInbox = sigValidation.User.inbox;
var twitterUser = activity.apObject.apObject.Split('/').Last().Replace("@", string.Empty);
diff --git a/src/BirdsiteLive/BirdsiteLive.csproj b/src/BirdsiteLive/BirdsiteLive.csproj
index 774c4ce..82bb9ee 100644
--- a/src/BirdsiteLive/BirdsiteLive.csproj
+++ b/src/BirdsiteLive/BirdsiteLive.csproj
@@ -4,7 +4,7 @@
netcoreapp3.1
d21486de-a812-47eb-a419-05682bb68856
Linux
- 0.2.0
+ 0.3.0
diff --git a/src/Tests/BirdsiteLive.Domain.Tests/BirdsiteLive.Domain.Tests.csproj b/src/Tests/BirdsiteLive.Domain.Tests/BirdsiteLive.Domain.Tests.csproj
index 8762be8..72a94c9 100644
--- a/src/Tests/BirdsiteLive.Domain.Tests/BirdsiteLive.Domain.Tests.csproj
+++ b/src/Tests/BirdsiteLive.Domain.Tests/BirdsiteLive.Domain.Tests.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessFollowUserTests.cs b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessFollowUserTests.cs
new file mode 100644
index 0000000..d5d735e
--- /dev/null
+++ b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessFollowUserTests.cs
@@ -0,0 +1,149 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using BirdsiteLive.DAL.Contracts;
+using BirdsiteLive.DAL.Models;
+using BirdsiteLive.Domain.BusinessUseCases;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Org.BouncyCastle.Crypto.Prng;
+
+namespace BirdsiteLive.Domain.Tests.BusinessUseCases
+{
+ [TestClass]
+ public class ProcessFollowUserTests
+ {
+ [TestMethod]
+ public async Task ExecuteAsync_UserDontExists_TwitterDontExists_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+ var followerInbox = "/user/testest";
+ var inbox = "/inbox";
+
+ var follower = new Follower
+ {
+ Id = 1,
+ Acct = username,
+ Host = domain,
+ SharedInboxRoute = followerInbox,
+ InboxRoute = inbox,
+ Followings = new List(),
+ FollowingsSyncStatus = new Dictionary()
+ };
+
+ var twitterUser = new SyncTwitterUser
+ {
+ Id = 2,
+ Acct = twitterName,
+ LastTweetPostedId = -1,
+ LastTweetSynchronizedForAllFollowersId = -1
+ };
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .SetupSequence(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync((Follower)null)
+ .ReturnsAsync(follower);
+
+ followersDalMock
+ .Setup(x => x.CreateFollowerAsync(
+ It.Is(y => y == username),
+ It.Is(y => y == domain),
+ It.Is(y => y == followerInbox),
+ It.Is(y => y == inbox),
+ null,
+ null))
+ .Returns(Task.CompletedTask);
+
+ followersDalMock
+ .Setup(x => x.UpdateFollowerAsync(
+ It.Is(y => y.Followings.Contains(twitterUser.Id)
+ && y.FollowingsSyncStatus[twitterUser.Id] == -1)
+ ))
+ .Returns(Task.CompletedTask);
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ twitterUserDalMock
+ .SetupSequence(x => x.GetTwitterUserAsync(twitterName))
+ .ReturnsAsync((SyncTwitterUser)null)
+ .ReturnsAsync(twitterUser);
+
+ twitterUserDalMock
+ .Setup(x => x.CreateTwitterUserAsync(
+ It.Is(y => y == twitterName),
+ It.Is(y => y == -1)))
+ .Returns(Task.CompletedTask);
+ #endregion
+
+ var action = new ProcessFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName, followerInbox, inbox);
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+
+ [TestMethod]
+ public async Task ExecuteAsync_UserExists_TwitterExists_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+ var followerInbox = "/user/testest";
+ var inbox = "/inbox";
+
+ var follower = new Follower
+ {
+ Id = 1,
+ Acct = username,
+ Host = domain,
+ SharedInboxRoute = followerInbox,
+ InboxRoute = inbox,
+ Followings = new List(),
+ FollowingsSyncStatus = new Dictionary()
+ };
+
+ var twitterUser = new SyncTwitterUser
+ {
+ Id = 2,
+ Acct = twitterName,
+ LastTweetPostedId = -1,
+ LastTweetSynchronizedForAllFollowersId = -1
+ };
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .Setup(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync(follower);
+
+ followersDalMock
+ .Setup(x => x.UpdateFollowerAsync(
+ It.Is(y => y.Followings.Contains(twitterUser.Id)
+ && y.FollowingsSyncStatus[twitterUser.Id] == -1)
+ ))
+ .Returns(Task.CompletedTask);
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ twitterUserDalMock
+ .Setup(x => x.GetTwitterUserAsync(twitterName))
+ .ReturnsAsync(twitterUser);
+ #endregion
+
+ var action = new ProcessFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName, followerInbox, inbox);
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessUnfollowUserTests.cs b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessUnfollowUserTests.cs
new file mode 100644
index 0000000..9bd83e3
--- /dev/null
+++ b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessUnfollowUserTests.cs
@@ -0,0 +1,210 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using BirdsiteLive.DAL.Contracts;
+using BirdsiteLive.DAL.Models;
+using BirdsiteLive.Domain.BusinessUseCases;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+
+namespace BirdsiteLive.Domain.Tests.BusinessUseCases
+{
+ [TestClass]
+ public class ProcessUnfollowUserTests
+ {
+ [TestMethod]
+ public async Task ExecuteAsync_NoFollowerFound_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .Setup(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync((Follower) null);
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ #endregion
+
+ var action = new ProcessUndoFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName );
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+
+ [TestMethod]
+ public async Task ExecuteAsync_NoTwitterUserFound_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+
+ var follower = new Follower
+ {
+ Id = 1,
+ Acct = username,
+ Host = domain,
+ Followings = new List(),
+ FollowingsSyncStatus = new Dictionary()
+ };
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .Setup(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync(follower);
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ twitterUserDalMock
+ .Setup(x => x.GetTwitterUserAsync(twitterName))
+ .ReturnsAsync((SyncTwitterUser)null);
+ #endregion
+
+ var action = new ProcessUndoFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName);
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+
+ [TestMethod]
+ public async Task ExecuteAsync_MultiFollows_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+
+ var follower = new Follower
+ {
+ Id = 1,
+ Acct = username,
+ Host = domain,
+ Followings = new List { 2, 3 },
+ FollowingsSyncStatus = new Dictionary { { 2, 460 }, { 3, 563} }
+ };
+
+ var twitterUser = new SyncTwitterUser
+ {
+ Id = 2,
+ Acct = twitterName,
+ LastTweetPostedId = 460,
+ LastTweetSynchronizedForAllFollowersId = 460
+ };
+
+ var followerList = new List
+ {
+ new Follower(),
+ new Follower()
+ };
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .Setup(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync(follower);
+
+ followersDalMock
+ .Setup(x => x.UpdateFollowerAsync(
+ It.Is(y => !y.Followings.Contains(twitterUser.Id)
+ && !y.FollowingsSyncStatus.ContainsKey(twitterUser.Id))
+ ))
+ .Returns(Task.CompletedTask);
+
+ followersDalMock
+ .Setup(x => x.GetFollowersAsync(twitterUser.Id))
+ .ReturnsAsync(followerList.ToArray());
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ twitterUserDalMock
+ .Setup(x => x.GetTwitterUserAsync(twitterName))
+ .ReturnsAsync(twitterUser);
+ #endregion
+
+ var action = new ProcessUndoFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName);
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+
+ [TestMethod]
+ public async Task ExecuteAsync_CleanUp_Test()
+ {
+ #region Stubs
+ var username = "testest";
+ var domain = "m.s";
+ var twitterName = "handle";
+
+ var follower = new Follower
+ {
+ Id = 1,
+ Acct = username,
+ Host = domain,
+ Followings = new List { 2 },
+ FollowingsSyncStatus = new Dictionary { { 2, 460 } }
+ };
+
+ var twitterUser = new SyncTwitterUser
+ {
+ Id = 2,
+ Acct = twitterName,
+ LastTweetPostedId = 460,
+ LastTweetSynchronizedForAllFollowersId = 460
+ };
+
+ var followerList = new List();
+ #endregion
+
+ #region Mocks
+ var followersDalMock = new Mock(MockBehavior.Strict);
+ followersDalMock
+ .Setup(x => x.GetFollowerAsync(username, domain))
+ .ReturnsAsync(follower);
+
+ followersDalMock
+ .Setup(x => x.DeleteFollowerAsync(
+ It.Is(y => y == username),
+ It.Is(y => y == domain)
+ ))
+ .Returns(Task.CompletedTask);
+
+ followersDalMock
+ .Setup(x => x.GetFollowersAsync(twitterUser.Id))
+ .ReturnsAsync(followerList.ToArray());
+
+ var twitterUserDalMock = new Mock(MockBehavior.Strict);
+ twitterUserDalMock
+ .Setup(x => x.GetTwitterUserAsync(twitterName))
+ .ReturnsAsync(twitterUser);
+
+ twitterUserDalMock
+ .Setup(x => x.DeleteTwitterUserAsync(
+ It.Is(y => y == twitterName)
+ ))
+ .Returns(Task.CompletedTask);
+ #endregion
+
+ var action = new ProcessUndoFollowUser(followersDalMock.Object, twitterUserDalMock.Object);
+ await action.ExecuteAsync(username, domain, twitterName);
+
+ #region Validations
+ followersDalMock.VerifyAll();
+ twitterUserDalMock.VerifyAll();
+ #endregion
+ }
+ }
+}
\ No newline at end of file