diff --git a/src/BirdsiteLive.ActivityPub/ApDeserializer.cs b/src/BirdsiteLive.ActivityPub/ApDeserializer.cs index 17dadbe..169bbe6 100644 --- a/src/BirdsiteLive.ActivityPub/ApDeserializer.cs +++ b/src/BirdsiteLive.ActivityPub/ApDeserializer.cs @@ -1,4 +1,5 @@ using System; +using BirdsiteLive.ActivityPub.Models; using Newtonsoft.Json; namespace BirdsiteLive.ActivityPub @@ -19,6 +20,8 @@ namespace BirdsiteLive.ActivityPub if(a.apObject.type == "Follow") return JsonConvert.DeserializeObject(json); break; + case "Delete": + return JsonConvert.DeserializeObject(json); case "Accept": var accept = JsonConvert.DeserializeObject(json); //var acceptType = JsonConvert.DeserializeObject(accept.apObject); diff --git a/src/BirdsiteLive.ActivityPub/Models/ActivityDelete.cs b/src/BirdsiteLive.ActivityPub/Models/ActivityDelete.cs new file mode 100644 index 0000000..deb7e7f --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/ActivityDelete.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace BirdsiteLive.ActivityPub.Models +{ + public class ActivityDelete : Activity + { + [JsonProperty("object")] + public object apObject { get; set; } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/BusinessUseCases/ProcessDeleteUser.cs b/src/BirdsiteLive.Domain/BusinessUseCases/ProcessDeleteUser.cs new file mode 100644 index 0000000..a35b6c8 --- /dev/null +++ b/src/BirdsiteLive.Domain/BusinessUseCases/ProcessDeleteUser.cs @@ -0,0 +1,51 @@ +using System.Linq; +using System.Threading.Tasks; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Models; + +namespace BirdsiteLive.Domain.BusinessUseCases +{ + public interface IProcessDeleteUser + { + Task ExecuteAsync(Follower follower); + Task ExecuteAsync(string followerUsername, string followerDomain); + } + + public class ProcessDeleteUser : IProcessDeleteUser + { + private readonly IFollowersDal _followersDal; + private readonly ITwitterUserDal _twitterUserDal; + + #region Ctor + public ProcessDeleteUser(IFollowersDal followersDal, ITwitterUserDal twitterUserDal) + { + _followersDal = followersDal; + _twitterUserDal = twitterUserDal; + } + #endregion + + public async Task ExecuteAsync(string followerUsername, string followerDomain) + { + // Get Follower and Twitter Users + var follower = await _followersDal.GetFollowerAsync(followerUsername, followerDomain); + if (follower == null) return; + + await ExecuteAsync(follower); + } + + public async Task ExecuteAsync(Follower follower) + { + // Remove twitter users if no more followers + var followings = follower.Followings; + foreach (var following in followings) + { + var followers = await _followersDal.GetFollowersAsync(following); + if (followers.Length == 1 && followers.First().Id == follower.Id) + await _twitterUserDal.DeleteTwitterUserAsync(following); + } + + // Remove follower from DB + await _followersDal.DeleteFollowerAsync(follower.Id); + } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/Tools/SigValidationResultExtractor.cs b/src/BirdsiteLive.Domain/Tools/SigValidationResultExtractor.cs new file mode 100644 index 0000000..1d6890a --- /dev/null +++ b/src/BirdsiteLive.Domain/Tools/SigValidationResultExtractor.cs @@ -0,0 +1,22 @@ +using System.Linq; + +namespace BirdsiteLive.Domain.Tools +{ + public class SigValidationResultExtractor + { + public static string GetUserName(SignatureValidationResult result) + { + return result.User.preferredUsername.ToLowerInvariant().Trim(); + } + + public static string GetHost(SignatureValidationResult result) + { + return result.User.url.Replace("https://", string.Empty).Split('/').First(); + } + + public static string GetSharedInbox(SignatureValidationResult result) + { + return result.User?.endpoints?.sharedInbox; + } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/UserService.cs b/src/BirdsiteLive.Domain/UserService.cs index 24c8287..a080180 100644 --- a/src/BirdsiteLive.Domain/UserService.cs +++ b/src/BirdsiteLive.Domain/UserService.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using BirdsiteLive.ActivityPub; using BirdsiteLive.ActivityPub.Converters; +using BirdsiteLive.ActivityPub.Models; using BirdsiteLive.Common.Regexes; using BirdsiteLive.Common.Settings; using BirdsiteLive.Cryptography; @@ -28,10 +29,12 @@ namespace BirdsiteLive.Domain Task UndoFollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityUndoFollow activity, string body); Task SendRejectFollowAsync(ActivityFollow activity, string followerHost); + Task DeleteRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityDelete activity, string body); } public class UserService : IUserService { + private readonly IProcessDeleteUser _processDeleteUser; private readonly IProcessFollowUser _processFollowUser; private readonly IProcessUndoFollowUser _processUndoFollowUser; @@ -46,7 +49,7 @@ namespace BirdsiteLive.Domain private readonly IModerationRepository _moderationRepository; #region Ctor - public UserService(InstanceSettings instanceSettings, ICryptoService cryptoService, IActivityPubService activityPubService, IProcessFollowUser processFollowUser, IProcessUndoFollowUser processUndoFollowUser, IStatusExtractor statusExtractor, IExtractionStatisticsHandler statisticsHandler, ITwitterUserService twitterUserService, IModerationRepository moderationRepository) + public UserService(InstanceSettings instanceSettings, ICryptoService cryptoService, IActivityPubService activityPubService, IProcessFollowUser processFollowUser, IProcessUndoFollowUser processUndoFollowUser, IStatusExtractor statusExtractor, IExtractionStatisticsHandler statisticsHandler, ITwitterUserService twitterUserService, IModerationRepository moderationRepository, IProcessDeleteUser processDeleteUser) { _instanceSettings = instanceSettings; _cryptoService = cryptoService; @@ -57,6 +60,7 @@ namespace BirdsiteLive.Domain _statisticsHandler = statisticsHandler; _twitterUserService = twitterUserService; _moderationRepository = moderationRepository; + _processDeleteUser = processDeleteUser; } #endregion @@ -126,10 +130,10 @@ namespace BirdsiteLive.Domain if (!sigValidation.SignatureIsValidated) return false; // Prepare data - var followerUserName = sigValidation.User.preferredUsername.ToLowerInvariant().Trim(); - var followerHost = sigValidation.User.url.Replace("https://", string.Empty).Split('/').First(); + var followerUserName = SigValidationResultExtractor.GetUserName(sigValidation); + var followerHost = SigValidationResultExtractor.GetHost(sigValidation); var followerInbox = sigValidation.User.inbox; - var followerSharedInbox = sigValidation.User?.endpoints?.sharedInbox; + var followerSharedInbox = SigValidationResultExtractor.GetSharedInbox(sigValidation); var twitterUser = activity.apObject.Split('/').Last().Replace("@", string.Empty).ToLowerInvariant().Trim(); // Make sure to only keep routes @@ -213,7 +217,7 @@ namespace BirdsiteLive.Domain return result == HttpStatusCode.Accepted || result == HttpStatusCode.OK; //TODO: revamp this for better error handling } - + private string OnlyKeepRoute(string inbox, string host) { if (string.IsNullOrWhiteSpace(inbox)) @@ -258,6 +262,22 @@ namespace BirdsiteLive.Domain return result == HttpStatusCode.Accepted || result == HttpStatusCode.OK; //TODO: revamp this for better error handling } + public async Task DeleteRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, + ActivityDelete activity, string body) + { + // Validate + var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders, body); + if (!sigValidation.SignatureIsValidated) return false; + + // Remove user and followings + var followerUserName = SigValidationResultExtractor.GetUserName(sigValidation); + var followerHost = SigValidationResultExtractor.GetHost(sigValidation); + + await _processDeleteUser.ExecuteAsync(followerUserName, followerHost); + + return true; + } + private async Task ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary requestHeaders, string body) { //Check Date Validity diff --git a/src/BirdsiteLive.Moderation/Actions/RemoveFollowerAction.cs b/src/BirdsiteLive.Moderation/Actions/RemoveFollowerAction.cs index 8ab3132..4721154 100644 --- a/src/BirdsiteLive.Moderation/Actions/RemoveFollowerAction.cs +++ b/src/BirdsiteLive.Moderation/Actions/RemoveFollowerAction.cs @@ -1,12 +1,6 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using BirdsiteLive.ActivityPub; -using BirdsiteLive.ActivityPub.Converters; -using BirdsiteLive.Common.Settings; -using BirdsiteLive.DAL.Contracts; +using System.Threading.Tasks; using BirdsiteLive.DAL.Models; -using BirdsiteLive.Domain; +using BirdsiteLive.Domain.BusinessUseCases; namespace BirdsiteLive.Moderation.Actions { @@ -17,16 +11,14 @@ namespace BirdsiteLive.Moderation.Actions public class RemoveFollowerAction : IRemoveFollowerAction { - private readonly IFollowersDal _followersDal; - private readonly ITwitterUserDal _twitterUserDal; private readonly IRejectAllFollowingsAction _rejectAllFollowingsAction; + private readonly IProcessDeleteUser _processDeleteUser; #region Ctor - public RemoveFollowerAction(IFollowersDal followersDal, ITwitterUserDal twitterUserDal, IRejectAllFollowingsAction rejectAllFollowingsAction) + public RemoveFollowerAction(IRejectAllFollowingsAction rejectAllFollowingsAction, IProcessDeleteUser processDeleteUser) { - _followersDal = followersDal; - _twitterUserDal = twitterUserDal; _rejectAllFollowingsAction = rejectAllFollowingsAction; + _processDeleteUser = processDeleteUser; } #endregion @@ -36,16 +28,7 @@ namespace BirdsiteLive.Moderation.Actions await _rejectAllFollowingsAction.ProcessAsync(follower); // Remove twitter users if no more followers - var followings = follower.Followings; - foreach (var following in followings) - { - var followers = await _followersDal.GetFollowersAsync(following); - if (followers.Length == 1 && followers.First().Id == follower.Id) - await _twitterUserDal.DeleteTwitterUserAsync(following); - } - - // Remove follower from DB - await _followersDal.DeleteFollowerAsync(follower.Id); + await _processDeleteUser.ExecuteAsync(follower); } } } \ No newline at end of file diff --git a/src/BirdsiteLive/BirdsiteLive.csproj b/src/BirdsiteLive/BirdsiteLive.csproj index a30e4e0..d4e7466 100644 --- a/src/BirdsiteLive/BirdsiteLive.csproj +++ b/src/BirdsiteLive/BirdsiteLive.csproj @@ -4,7 +4,7 @@ netcoreapp3.1 d21486de-a812-47eb-a419-05682bb68856 Linux - 0.19.1 + 0.20.0 diff --git a/src/BirdsiteLive/Controllers/InboxController.cs b/src/BirdsiteLive/Controllers/InboxController.cs index db055cf..f55e22b 100644 --- a/src/BirdsiteLive/Controllers/InboxController.cs +++ b/src/BirdsiteLive/Controllers/InboxController.cs @@ -3,6 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using BirdsiteLive.ActivityPub; +using BirdsiteLive.ActivityPub.Models; +using BirdsiteLive.Domain; +using BirdsiteLive.Tools; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -13,11 +17,13 @@ namespace BirdsiteLive.Controllers public class InboxController : ControllerBase { private readonly ILogger _logger; + private readonly IUserService _userService; #region Ctor - public InboxController(ILogger logger) + public InboxController(ILogger logger, IUserService userService) { _logger = logger; + _userService = userService; } #endregion @@ -33,6 +39,19 @@ namespace BirdsiteLive.Controllers _logger.LogTrace("Inbox: {Body}", body); //System.IO.File.WriteAllText($@"C:\apdebug\inbox\{Guid.NewGuid()}.json", body); + var activity = ApDeserializer.ProcessActivity(body); + var signature = r.Headers["Signature"].First(); + + switch (activity?.type) + { + case "Delete": + { + var succeeded = await _userService.DeleteRequestedAsync(signature, r.Method, r.Path, + r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityDelete, body); + if (succeeded) return Accepted(); + else return Unauthorized(); + } + } } return Accepted(); diff --git a/src/BirdsiteLive/Controllers/UsersController.cs b/src/BirdsiteLive/Controllers/UsersController.cs index 0d5f77b..73be8b0 100644 --- a/src/BirdsiteLive/Controllers/UsersController.cs +++ b/src/BirdsiteLive/Controllers/UsersController.cs @@ -13,6 +13,7 @@ using BirdsiteLive.Common.Regexes; using BirdsiteLive.Common.Settings; using BirdsiteLive.Domain; using BirdsiteLive.Models; +using BirdsiteLive.Tools; using BirdsiteLive.Twitter; using BirdsiteLive.Twitter.Models; using Microsoft.AspNetCore.Http; @@ -142,7 +143,6 @@ namespace BirdsiteLive.Controllers //System.IO.File.WriteAllText($@"C:\apdebug\{Guid.NewGuid()}.json", body); var activity = ApDeserializer.ProcessActivity(body); - // Do something var signature = r.Headers["Signature"].First(); switch (activity?.type) @@ -150,7 +150,7 @@ namespace BirdsiteLive.Controllers case "Follow": { var succeeded = await _userService.FollowRequestedAsync(signature, r.Method, r.Path, - r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityFollow, body); + r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityFollow, body); if (succeeded) return Accepted(); else return Unauthorized(); } @@ -158,11 +158,18 @@ namespace BirdsiteLive.Controllers if (activity is ActivityUndoFollow) { var succeeded = await _userService.UndoFollowRequestedAsync(signature, r.Method, r.Path, - r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityUndoFollow, body); + r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityUndoFollow, body); if (succeeded) return Accepted(); else return Unauthorized(); } return Accepted(); + case "Delete": + { + var succeeded = await _userService.DeleteRequestedAsync(signature, r.Method, r.Path, + r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityDelete, body); + if (succeeded) return Accepted(); + else return Unauthorized(); + } default: return Accepted(); } @@ -184,9 +191,6 @@ namespace BirdsiteLive.Controllers return Content(jsonApUser, "application/activity+json; charset=utf-8"); } - private Dictionary RequestHeaders(IHeaderDictionary header) - { - return header.ToDictionary, string, string>(h => h.Key.ToLowerInvariant(), h => h.Value); - } + } } \ No newline at end of file diff --git a/src/BirdsiteLive/Tools/HeaderHandler.cs b/src/BirdsiteLive/Tools/HeaderHandler.cs new file mode 100644 index 0000000..74ecf29 --- /dev/null +++ b/src/BirdsiteLive/Tools/HeaderHandler.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace BirdsiteLive.Tools +{ + public class HeaderHandler + { + public static Dictionary RequestHeaders(IHeaderDictionary header) + { + return header.ToDictionary, string, string>(h => h.Key.ToLowerInvariant(), h => h.Value); + } + } +} \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs index 3c85113..3d64e90 100644 --- a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs +++ b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using BirdsiteLive.ActivityPub.Models; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; namespace BirdsiteLive.ActivityPub.Tests @@ -48,6 +49,20 @@ namespace BirdsiteLive.ActivityPub.Tests Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject); } + [TestMethod] + public void DeleteDeserializationTest() + { + var json = + "{\"@context\": \"https://www.w3.org/ns/activitystreams\", \"id\": \"https://mastodon.technology/users/deleteduser#delete\", \"type\": \"Delete\", \"actor\": \"https://mastodon.technology/users/deleteduser\", \"to\": [\"https://www.w3.org/ns/activitystreams#Public\"],\"object\": \"https://mastodon.technology/users/deleteduser\",\"signature\": {\"type\": \"RsaSignature2017\",\"creator\": \"https://mastodon.technology/users/deleteduser#main-key\",\"created\": \"2020-11-19T22:43:01Z\",\"signatureValue\": \"peksQao4v5N+sMZgHXZ6xZnGaZrd0s+LqZimu63cnp7O5NBJM6gY9AAu/vKUgrh4C50r66f9OQdHg5yChQhc4ViE+yLR/3/e59YQimelmXJPpcC99Nt0YLU/iTRLsBehY3cDdC6+ogJKgpkToQvB6tG2KrPdrkreYh4Il4eXLKMfiQhgdKluOvenLnl2erPWfE02hIu/jpuljyxSuvJunMdU4yQVSZHTtk/I8q3jjzIzhgyb7ICWU5Hkx0H/47Q24ztsvOgiTWNgO+v6l9vA7qIhztENiRPhzGP5RCCzUKRAe6bcSu1Wfa3NKWqB9BeJ7s+2y2bD7ubPbiEE1MQV7Q==\"}}"; + + var data = ApDeserializer.ProcessActivity(json) as ActivityDelete; + + Assert.AreEqual("https://mastodon.technology/users/deleteduser#delete", data.id); + Assert.AreEqual("Delete", data.type); + Assert.AreEqual("https://mastodon.technology/users/deleteduser", data.actor); + Assert.AreEqual("https://mastodon.technology/users/deleteduser", data.apObject); + } + //[TestMethod] //public void NoteDeserializationTest() //{ diff --git a/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessDeleteUserTests.cs b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessDeleteUserTests.cs new file mode 100644 index 0000000..85900da --- /dev/null +++ b/src/Tests/BirdsiteLive.Domain.Tests/BusinessUseCases/ProcessDeleteUserTests.cs @@ -0,0 +1,97 @@ +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 ProcessDeleteUserTests + { + [TestMethod] + public async Task ExecuteAsync_NoMoreFollowings() + { + #region Stubs + var follower = new Follower + { + Id = 12, + Followings = new List { 1 } + }; + #endregion + + #region Mocks + var followersDalMock = new Mock(MockBehavior.Strict); + followersDalMock + .Setup(x => x.GetFollowersAsync( + It.Is(y => y == 1))) + .ReturnsAsync(new[] { follower }); + + followersDalMock + .Setup(x => x.DeleteFollowerAsync( + It.Is(y => y == 12))) + .Returns(Task.CompletedTask); + + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.DeleteTwitterUserAsync( + It.Is(y => y == 1))) + .Returns(Task.CompletedTask); + #endregion + + var action = new ProcessDeleteUser(followersDalMock.Object, twitterUserDalMock.Object); + await action.ExecuteAsync(follower); + + #region Validations + followersDalMock.VerifyAll(); + twitterUserDalMock.VerifyAll(); + #endregion + } + + [TestMethod] + public async Task ExecuteAsync_HaveFollowings() + { + #region Stubs + var follower = new Follower + { + Id = 12, + Followings = new List { 1 } + }; + + var followers = new List + { + follower, + new Follower + { + Id = 11 + } + }; + #endregion + + #region Mocks + var followersDalMock = new Mock(MockBehavior.Strict); + followersDalMock + .Setup(x => x.GetFollowersAsync( + It.Is(y => y == 1))) + .ReturnsAsync(followers.ToArray()); + + followersDalMock + .Setup(x => x.DeleteFollowerAsync( + It.Is(y => y == 12))) + .Returns(Task.CompletedTask); + + var twitterUserDalMock = new Mock(MockBehavior.Strict); + #endregion + + var action = new ProcessDeleteUser(followersDalMock.Object, twitterUserDalMock.Object); + await action.ExecuteAsync(follower); + + #region Validations + followersDalMock.VerifyAll(); + twitterUserDalMock.VerifyAll(); + #endregion + } + } +} \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.Moderation.Tests/Actions/RemoveFollowerActionTests.cs b/src/Tests/BirdsiteLive.Moderation.Tests/Actions/RemoveFollowerActionTests.cs index 3b83739..34f40b2 100644 --- a/src/Tests/BirdsiteLive.Moderation.Tests/Actions/RemoveFollowerActionTests.cs +++ b/src/Tests/BirdsiteLive.Moderation.Tests/Actions/RemoveFollowerActionTests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Models; +using BirdsiteLive.Domain.BusinessUseCases; using BirdsiteLive.Moderation.Actions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -29,31 +30,19 @@ namespace BirdsiteLive.Moderation.Tests.Actions It.Is(y => y.Id == follower.Id))) .Returns(Task.CompletedTask); - var followersDalMock = new Mock(MockBehavior.Strict); - followersDalMock - .Setup(x => x.GetFollowersAsync( - It.Is(y => y == 1))) - .ReturnsAsync(new[] {follower}); - - followersDalMock - .Setup(x => x.DeleteFollowerAsync( - It.Is(y => y == 12))) - .Returns(Task.CompletedTask); - - var twitterUserDalMock = new Mock(MockBehavior.Strict); - twitterUserDalMock - .Setup(x => x.DeleteTwitterUserAsync( - It.Is(y => y == 1))) + var processDeleteUserMock = new Mock(MockBehavior.Strict); + processDeleteUserMock + .Setup(x => x.ExecuteAsync( + It.Is(y => y.Id == follower.Id))) .Returns(Task.CompletedTask); #endregion - var action = new RemoveFollowerAction(followersDalMock.Object, twitterUserDalMock.Object, rejectAllFollowingsActionMock.Object); + var action = new RemoveFollowerAction(rejectAllFollowingsActionMock.Object, processDeleteUserMock.Object); await action.ProcessAsync(follower); #region Validations - followersDalMock.VerifyAll(); - twitterUserDalMock.VerifyAll(); rejectAllFollowingsActionMock.VerifyAll(); + processDeleteUserMock.VerifyAll(); #endregion } @@ -66,15 +55,6 @@ namespace BirdsiteLive.Moderation.Tests.Actions Id = 12, Followings = new List { 1 } }; - - var followers = new List - { - follower, - new Follower - { - Id = 11 - } - }; #endregion #region Mocks @@ -84,27 +64,19 @@ namespace BirdsiteLive.Moderation.Tests.Actions It.Is(y => y.Id == follower.Id))) .Returns(Task.CompletedTask); - var followersDalMock = new Mock(MockBehavior.Strict); - followersDalMock - .Setup(x => x.GetFollowersAsync( - It.Is(y => y == 1))) - .ReturnsAsync(followers.ToArray()); - - followersDalMock - .Setup(x => x.DeleteFollowerAsync( - It.Is(y => y == 12))) + var processDeleteUserMock = new Mock(MockBehavior.Strict); + processDeleteUserMock + .Setup(x => x.ExecuteAsync( + It.Is(y => y.Id == follower.Id))) .Returns(Task.CompletedTask); - - var twitterUserDalMock = new Mock(MockBehavior.Strict); #endregion - var action = new RemoveFollowerAction(followersDalMock.Object, twitterUserDalMock.Object, rejectAllFollowingsActionMock.Object); + var action = new RemoveFollowerAction(rejectAllFollowingsActionMock.Object, processDeleteUserMock.Object); await action.ProcessAsync(follower); #region Validations - followersDalMock.VerifyAll(); - twitterUserDalMock.VerifyAll(); rejectAllFollowingsActionMock.VerifyAll(); + processDeleteUserMock.VerifyAll(); #endregion } }