added reply filtering

This commit is contained in:
Nicolas Constant 2021-01-22 18:31:30 -05:00
parent fee7810d8a
commit 40d6f69446
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
10 changed files with 600 additions and 17 deletions

View File

@ -10,4 +10,5 @@ You can configure some of BirdsiteLIVE's settings via environment variables (tho
## Instance customization ## Instance customization
* `Instance:Name` (default: BirdsiteLIVE) the name of the instance * `Instance:Name` (default: BirdsiteLIVE) the name of the instance
* `Instance:ResolveMentionsInProfiles` (default: true) to enable or disable mentions parsing in profile's description. Resolving it will consume more User's API calls since newly discovered account can also contain references to others accounts as well. On a big instance it is recommended to disable it. * `Instance:ResolveMentionsInProfiles` (default: true) to enable or disable mentions parsing in profile's description. Resolving it will consume more User's API calls since newly discovered account can also contain references to others accounts as well. On a big instance it is recommended to disable it.
* `Instance:PublishReplies` (default: false) to enable or disable replies publishing.

View File

@ -6,5 +6,6 @@
public string Domain { get; set; } public string Domain { get; set; }
public string AdminEmail { get; set; } public string AdminEmail { get; set; }
public bool ResolveMentionsInProfiles { get; set; } public bool ResolveMentionsInProfiles { get; set; }
public bool PublishReplies { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Contracts;
using BirdsiteLive.DAL.Models; using BirdsiteLive.DAL.Models;
using BirdsiteLive.Domain; using BirdsiteLive.Domain;
@ -21,15 +22,17 @@ namespace BirdsiteLive.Pipeline.Processors.SubTasks
private readonly IActivityPubService _activityPubService; private readonly IActivityPubService _activityPubService;
private readonly IStatusService _statusService; private readonly IStatusService _statusService;
private readonly IFollowersDal _followersDal; private readonly IFollowersDal _followersDal;
private readonly InstanceSettings _settings;
private readonly ILogger<SendTweetsToInboxTask> _logger; private readonly ILogger<SendTweetsToInboxTask> _logger;
#region Ctor #region Ctor
public SendTweetsToInboxTask(IActivityPubService activityPubService, IStatusService statusService, IFollowersDal followersDal, ILogger<SendTweetsToInboxTask> logger) public SendTweetsToInboxTask(IActivityPubService activityPubService, IStatusService statusService, IFollowersDal followersDal, InstanceSettings settings, ILogger<SendTweetsToInboxTask> logger)
{ {
_activityPubService = activityPubService; _activityPubService = activityPubService;
_statusService = statusService; _statusService = statusService;
_followersDal = followersDal; _followersDal = followersDal;
_settings = settings;
_logger = logger; _logger = logger;
} }
#endregion #endregion
@ -52,8 +55,13 @@ namespace BirdsiteLive.Pipeline.Processors.SubTasks
{ {
try try
{ {
var note = _statusService.GetStatus(user.Acct, tweet); if (!tweet.IsReply ||
await _activityPubService.PostNewNoteActivity(note, user.Acct, tweet.Id.ToString(), follower.Host, inbox); tweet.IsReply && tweet.IsThread ||
_settings.PublishReplies)
{
var note = _statusService.GetStatus(user.Acct, tweet);
await _activityPubService.PostNewNoteActivity(note, user.Acct, tweet.Id.ToString(), follower.Host, inbox);
}
} }
catch (ArgumentException e) catch (ArgumentException e)
{ {

View File

@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Contracts;
using BirdsiteLive.DAL.Models; using BirdsiteLive.DAL.Models;
using BirdsiteLive.Domain; using BirdsiteLive.Domain;
@ -20,14 +21,16 @@ namespace BirdsiteLive.Pipeline.Processors.SubTasks
private readonly IStatusService _statusService; private readonly IStatusService _statusService;
private readonly IActivityPubService _activityPubService; private readonly IActivityPubService _activityPubService;
private readonly IFollowersDal _followersDal; private readonly IFollowersDal _followersDal;
private readonly InstanceSettings _settings;
private readonly ILogger<SendTweetsToSharedInboxTask> _logger; private readonly ILogger<SendTweetsToSharedInboxTask> _logger;
#region Ctor #region Ctor
public SendTweetsToSharedInboxTask(IActivityPubService activityPubService, IStatusService statusService, IFollowersDal followersDal, ILogger<SendTweetsToSharedInboxTask> logger) public SendTweetsToSharedInboxTask(IActivityPubService activityPubService, IStatusService statusService, IFollowersDal followersDal, InstanceSettings settings, ILogger<SendTweetsToSharedInboxTask> logger)
{ {
_activityPubService = activityPubService; _activityPubService = activityPubService;
_statusService = statusService; _statusService = statusService;
_followersDal = followersDal; _followersDal = followersDal;
_settings = settings;
_logger = logger; _logger = logger;
} }
#endregion #endregion
@ -52,8 +55,13 @@ namespace BirdsiteLive.Pipeline.Processors.SubTasks
{ {
try try
{ {
var note = _statusService.GetStatus(user.Acct, tweet); if (!tweet.IsReply ||
await _activityPubService.PostNewNoteActivity(note, user.Acct, tweet.Id.ToString(), host, inbox); tweet.IsReply && tweet.IsThread ||
_settings.PublishReplies)
{
var note = _statusService.GetStatus(user.Acct, tweet);
await _activityPubService.PostNewNoteActivity(note, user.Acct, tweet.Id.ToString(), host, inbox);
}
} }
catch (ArgumentException e) catch (ArgumentException e)
{ {
@ -66,7 +74,7 @@ namespace BirdsiteLive.Pipeline.Processors.SubTasks
throw; throw;
} }
} }
syncStatus = tweet.Id; syncStatus = tweet.Id;
} }
} }

View File

@ -24,7 +24,9 @@ namespace BirdsiteLive.Twitter.Extractors
InReplyToAccount = tweet.InReplyToScreenName, InReplyToAccount = tweet.InReplyToScreenName,
MessageContent = ExtractMessage(tweet), MessageContent = ExtractMessage(tweet),
Media = ExtractMedia(tweet.Media), Media = ExtractMedia(tweet.Media),
CreatedAt = tweet.CreatedAt.ToUniversalTime() CreatedAt = tweet.CreatedAt.ToUniversalTime(),
IsReply = tweet.InReplyToUserId != null,
IsThread = tweet.InReplyToUserId != null && tweet.InReplyToUserId == tweet.CreatedBy.Id
}; };
return extractedTweet; return extractedTweet;
} }

View File

@ -11,5 +11,7 @@ namespace BirdsiteLive.Twitter.Models
public ExtractedMedia[] Media { get; set; } public ExtractedMedia[] Media { get; set; }
public DateTime CreatedAt { get; set; } public DateTime CreatedAt { get; set; }
public string InReplyToAccount { get; set; } public string InReplyToAccount { get; set; }
public bool IsReply { get; set; }
public bool IsThread { get; set; }
} }
} }

View File

@ -40,7 +40,7 @@ namespace BirdsiteLive.Twitter
var tweet = Tweet.GetTweet(statusId); var tweet = Tweet.GetTweet(statusId);
_statisticsHandler.CalledTweetApi(); _statisticsHandler.CalledTweetApi();
if (tweet == null) return null; //TODO: test this if (tweet == null) return null; //TODO: test this
return _tweetExtractor.Extract(tweet); return _tweetExtractor.Extract(tweet);
} }
public ExtractedTweet[] GetTimeline(string username, int nberTweets, long fromTweetId = -1) public ExtractedTweet[] GetTimeline(string username, int nberTweets, long fromTweetId = -1)

View File

@ -13,7 +13,8 @@
"Name": "BirdsiteLIVE", "Name": "BirdsiteLIVE",
"Domain": "domain.name", "Domain": "domain.name",
"AdminEmail": "me@domain.name", "AdminEmail": "me@domain.name",
"ResolveMentionsInProfiles": true "ResolveMentionsInProfiles": true,
"PublishReplies": false
}, },
"Db": { "Db": {
"Type": "postgres", "Type": "postgres",

View File

@ -4,6 +4,7 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using BirdsiteLive.ActivityPub.Models; using BirdsiteLive.ActivityPub.Models;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Contracts;
using BirdsiteLive.DAL.Models; using BirdsiteLive.DAL.Models;
using BirdsiteLive.Domain; using BirdsiteLive.Domain;
@ -54,6 +55,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
InboxRoute = inbox, InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } } FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -83,7 +89,239 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion #endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser);
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_Reply_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = false
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/user/inbox";
var follower = new Follower
{
Id = 1,
Host = host,
InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
};
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser);
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_ReplyThread_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = true
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/user/inbox";
var follower = new Follower
{
Id = 1,
Host = host,
InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
};
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
activityPubService
.Setup(x => x.PostNewNoteActivity(
It.Is<Note>(y => y.id == noteId),
It.Is<string>(y => y == twitterHandle),
It.Is<string>(y => y == tweetId.ToString()),
It.Is<string>(y => y == host),
It.Is<string>(y => y == inbox)))
.Returns(Task.CompletedTask);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
statusServiceMock
.Setup(x => x.GetStatus(
It.Is<string>(y => y == twitterHandle),
It.Is<ExtractedTweet>(y => y.Id == tweetId)))
.Returns(note);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser);
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_PublishReply_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = false
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/user/inbox";
var follower = new Follower
{
Id = 1,
Host = host,
InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
};
var settings = new InstanceSettings
{
PublishReplies = true
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
activityPubService
.Setup(x => x.PostNewNoteActivity(
It.Is<Note>(y => y.id == noteId),
It.Is<string>(y => y == twitterHandle),
It.Is<string>(y => y == tweetId.ToString()),
It.Is<string>(y => y == host),
It.Is<string>(y => y == inbox)))
.Returns(Task.CompletedTask);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
statusServiceMock
.Setup(x => x.GetStatus(
It.Is<string>(y => y == twitterHandle),
It.Is<ExtractedTweet>(y => y.Id == tweetId)))
.Returns(note);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser); await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser);
#region Validations #region Validations
@ -126,6 +364,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
InboxRoute = inbox, InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 10 } } FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 10 } }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -161,7 +404,7 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion #endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser); await task.ExecuteAsync(tweets.ToArray(), follower, twitterUser);
#region Validations #region Validations
@ -205,6 +448,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
InboxRoute = inbox, InboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 10 } } FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 10 } }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -247,7 +495,7 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToInboxTask>>();
#endregion #endregion
var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
try try
{ {

View File

@ -5,6 +5,7 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using BirdsiteLive.ActivityPub.Models; using BirdsiteLive.ActivityPub.Models;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Contracts;
using BirdsiteLive.DAL.Models; using BirdsiteLive.DAL.Models;
using BirdsiteLive.Domain; using BirdsiteLive.Domain;
@ -72,6 +73,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 7 } } FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 7 } }
} }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -105,7 +111,303 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion #endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray());
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_Reply_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = false
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/inbox";
var followers = new List<Follower>
{
new Follower
{
Id = 1,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
},
new Follower
{
Id = 2,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 8 } }
},
new Follower
{
Id = 3,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 7 } }
}
};
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
foreach (var follower in followers)
{
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
}
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray());
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_ReplyThread_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = true
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/inbox";
var followers = new List<Follower>
{
new Follower
{
Id = 1,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
},
new Follower
{
Id = 2,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 8 } }
},
new Follower
{
Id = 3,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 7 } }
}
};
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
activityPubService
.Setup(x => x.PostNewNoteActivity(
It.Is<Note>(y => y.id == noteId),
It.Is<string>(y => y == twitterHandle),
It.Is<string>(y => y == tweetId.ToString()),
It.Is<string>(y => y == host),
It.Is<string>(y => y == inbox)))
.Returns(Task.CompletedTask);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
statusServiceMock
.Setup(x => x.GetStatus(
It.Is<string>(y => y == twitterHandle),
It.Is<ExtractedTweet>(y => y.Id == tweetId)))
.Returns(note);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
foreach (var follower in followers)
{
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
}
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray());
#region Validations
activityPubService.VerifyAll();
statusServiceMock.VerifyAll();
followersDalMock.VerifyAll();
#endregion
}
[TestMethod]
public async Task ExecuteAsync_SingleTweet_PublishReply_Test()
{
#region Stubs
var tweetId = 10;
var tweets = new List<ExtractedTweet>
{
new ExtractedTweet
{
Id = tweetId,
IsReply = true,
IsThread = false
}
};
var noteId = "noteId";
var note = new Note()
{
id = noteId
};
var twitterHandle = "Test";
var twitterUserId = 7;
var twitterUser = new SyncTwitterUser
{
Id = twitterUserId,
Acct = twitterHandle
};
var host = "domain.ext";
var inbox = "/inbox";
var followers = new List<Follower>
{
new Follower
{
Id = 1,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 9 } }
},
new Follower
{
Id = 2,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 8 } }
},
new Follower
{
Id = 3,
Host = host,
SharedInboxRoute = inbox,
FollowingsSyncStatus = new Dictionary<int, long> { { twitterUserId, 7 } }
}
};
var settings = new InstanceSettings
{
PublishReplies = true
};
#endregion
#region Mocks
var activityPubService = new Mock<IActivityPubService>(MockBehavior.Strict);
activityPubService
.Setup(x => x.PostNewNoteActivity(
It.Is<Note>(y => y.id == noteId),
It.Is<string>(y => y == twitterHandle),
It.Is<string>(y => y == tweetId.ToString()),
It.Is<string>(y => y == host),
It.Is<string>(y => y == inbox)))
.Returns(Task.CompletedTask);
var statusServiceMock = new Mock<IStatusService>(MockBehavior.Strict);
statusServiceMock
.Setup(x => x.GetStatus(
It.Is<string>(y => y == twitterHandle),
It.Is<ExtractedTweet>(y => y.Id == tweetId)))
.Returns(note);
var followersDalMock = new Mock<IFollowersDal>(MockBehavior.Strict);
foreach (var follower in followers)
{
followersDalMock
.Setup(x => x.UpdateFollowerAsync(
It.Is<Follower>(y => y.Id == follower.Id && y.FollowingsSyncStatus[twitterUserId] == tweetId)))
.Returns(Task.CompletedTask);
}
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray()); await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray());
#region Validations #region Validations
@ -165,6 +467,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
FollowingsSyncStatus = new Dictionary<int, long> {{twitterUserId, 7}} FollowingsSyncStatus = new Dictionary<int, long> {{twitterUserId, 7}}
} }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -204,7 +511,7 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion #endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray()); await task.ExecuteAsync(tweets.ToArray(), twitterUser, host, followers.ToArray());
#region Validations #region Validations
@ -265,6 +572,11 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
FollowingsSyncStatus = new Dictionary<int, long> {{twitterUserId, 7}} FollowingsSyncStatus = new Dictionary<int, long> {{twitterUserId, 7}}
} }
}; };
var settings = new InstanceSettings
{
PublishReplies = false
};
#endregion #endregion
#region Mocks #region Mocks
@ -311,7 +623,7 @@ namespace BirdsiteLive.Pipeline.Tests.Processors.SubTasks
var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>(); var loggerMock = new Mock<ILogger<SendTweetsToSharedInboxTask>>();
#endregion #endregion
var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, loggerMock.Object); var task = new SendTweetsToSharedInboxTask(activityPubService.Object, statusServiceMock.Object, followersDalMock.Object, settings, loggerMock.Object);
try try
{ {