mirror of
https://github.com/NicolasConstant/BirdsiteLive
synced 2025-06-05 21:49:16 +02:00
Merge pull request #139 from NicolasConstant/topic_better-progression-handling
remove users if not followed
This commit is contained in:
@@ -3,6 +3,8 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BirdsiteLive.DAL.Contracts;
|
using BirdsiteLive.DAL.Contracts;
|
||||||
|
using BirdsiteLive.DAL.Models;
|
||||||
|
using BirdsiteLive.Moderation.Actions;
|
||||||
using BirdsiteLive.Pipeline.Contracts;
|
using BirdsiteLive.Pipeline.Contracts;
|
||||||
using BirdsiteLive.Pipeline.Models;
|
using BirdsiteLive.Pipeline.Models;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -13,12 +15,14 @@ namespace BirdsiteLive.Pipeline.Processors
|
|||||||
{
|
{
|
||||||
private readonly ITwitterUserDal _twitterUserDal;
|
private readonly ITwitterUserDal _twitterUserDal;
|
||||||
private readonly ILogger<SaveProgressionProcessor> _logger;
|
private readonly ILogger<SaveProgressionProcessor> _logger;
|
||||||
|
private readonly IRemoveTwitterAccountAction _removeTwitterAccountAction;
|
||||||
|
|
||||||
#region Ctor
|
#region Ctor
|
||||||
public SaveProgressionProcessor(ITwitterUserDal twitterUserDal, ILogger<SaveProgressionProcessor> logger)
|
public SaveProgressionProcessor(ITwitterUserDal twitterUserDal, ILogger<SaveProgressionProcessor> logger, IRemoveTwitterAccountAction removeTwitterAccountAction)
|
||||||
{
|
{
|
||||||
_twitterUserDal = twitterUserDal;
|
_twitterUserDal = twitterUserDal;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_removeTwitterAccountAction = removeTwitterAccountAction;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -28,24 +32,19 @@ namespace BirdsiteLive.Pipeline.Processors
|
|||||||
{
|
{
|
||||||
if (userWithTweetsToSync.Tweets.Length == 0)
|
if (userWithTweetsToSync.Tweets.Length == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No tweets synchronized");
|
_logger.LogInformation("No tweets synchronized");
|
||||||
|
await UpdateUserSyncDateAsync(userWithTweetsToSync.User);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(userWithTweetsToSync.Followers.Length == 0)
|
if(userWithTweetsToSync.Followers.Length == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No Followers found for {User}", userWithTweetsToSync.User.Acct);
|
_logger.LogInformation("No Followers found for {User}", userWithTweetsToSync.User.Acct);
|
||||||
|
await _removeTwitterAccountAction.ProcessAsync(userWithTweetsToSync.User);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = userWithTweetsToSync.User.Id;
|
var userId = userWithTweetsToSync.User.Id;
|
||||||
var followingSyncStatuses = userWithTweetsToSync.Followers.Select(x => x.FollowingsSyncStatus[userId]).ToList();
|
var followingSyncStatuses = userWithTweetsToSync.Followers.Select(x => x.FollowingsSyncStatus[userId]).ToList();
|
||||||
|
|
||||||
if (followingSyncStatuses.Count == 0)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("No Followers sync found for {User}, Id: {UserId}", userWithTweetsToSync.User.Acct, userId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastPostedTweet = userWithTweetsToSync.Tweets.Select(x => x.Id).Max();
|
var lastPostedTweet = userWithTweetsToSync.Tweets.Select(x => x.Id).Max();
|
||||||
var minimumSync = followingSyncStatuses.Min();
|
var minimumSync = followingSyncStatuses.Min();
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
@@ -57,5 +56,11 @@ namespace BirdsiteLive.Pipeline.Processors
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UpdateUserSyncDateAsync(SyncTwitterUser user)
|
||||||
|
{
|
||||||
|
user.LastSync = DateTime.UtcNow;
|
||||||
|
await _twitterUserDal.UpdateTwitterUserAsync(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,16 +1,16 @@
|
|||||||
using System;
|
using BirdsiteLive.DAL.Contracts;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using BirdsiteLive.DAL.Contracts;
|
|
||||||
using BirdsiteLive.DAL.Models;
|
using BirdsiteLive.DAL.Models;
|
||||||
|
using BirdsiteLive.Moderation.Actions;
|
||||||
using BirdsiteLive.Pipeline.Models;
|
using BirdsiteLive.Pipeline.Models;
|
||||||
using BirdsiteLive.Pipeline.Processors;
|
using BirdsiteLive.Pipeline.Processors;
|
||||||
using BirdsiteLive.Twitter.Models;
|
using BirdsiteLive.Twitter.Models;
|
||||||
using Castle.DynamicProxy.Contributors;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace BirdsiteLive.Pipeline.Tests.Processors
|
namespace BirdsiteLive.Pipeline.Tests.Processors
|
||||||
{
|
{
|
||||||
@@ -69,14 +69,84 @@ namespace BirdsiteLive.Pipeline.Tests.Processors
|
|||||||
It.IsAny<DateTime>()
|
It.IsAny<DateTime>()
|
||||||
))
|
))
|
||||||
.Returns(Task.CompletedTask);
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object);
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
#region Validations
|
#region Validations
|
||||||
twitterUserDalMock.VerifyAll();
|
twitterUserDalMock.VerifyAll();
|
||||||
loggerMock.VerifyAll();
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(ArgumentException))]
|
||||||
|
public async Task ProcessAsync_Exception_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var user = new SyncTwitterUser
|
||||||
|
{
|
||||||
|
Id = 1
|
||||||
|
};
|
||||||
|
var tweet1 = new ExtractedTweet
|
||||||
|
{
|
||||||
|
Id = 36
|
||||||
|
};
|
||||||
|
var tweet2 = new ExtractedTweet
|
||||||
|
{
|
||||||
|
Id = 37
|
||||||
|
};
|
||||||
|
var follower1 = new Follower
|
||||||
|
{
|
||||||
|
FollowingsSyncStatus = new Dictionary<int, long>
|
||||||
|
{
|
||||||
|
{1, 37}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var usersWithTweets = new UserWithDataToSync
|
||||||
|
{
|
||||||
|
Tweets = new[]
|
||||||
|
{
|
||||||
|
tweet1,
|
||||||
|
tweet2
|
||||||
|
},
|
||||||
|
Followers = new[]
|
||||||
|
{
|
||||||
|
follower1
|
||||||
|
},
|
||||||
|
User = user
|
||||||
|
};
|
||||||
|
|
||||||
|
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var twitterUserDalMock = new Mock<ITwitterUserDal>(MockBehavior.Strict);
|
||||||
|
twitterUserDalMock
|
||||||
|
.Setup(x => x.UpdateTwitterUserAsync(
|
||||||
|
It.Is<int>(y => y == user.Id),
|
||||||
|
It.Is<long>(y => y == tweet2.Id),
|
||||||
|
It.Is<long>(y => y == tweet2.Id),
|
||||||
|
It.Is<int>(y => y == 0),
|
||||||
|
It.IsAny<DateTime>()
|
||||||
|
))
|
||||||
|
.Throws(new ArgumentException());
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
twitterUserDalMock.VerifyAll();
|
||||||
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,14 +207,17 @@ namespace BirdsiteLive.Pipeline.Tests.Processors
|
|||||||
.Returns(Task.CompletedTask);
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object);
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
#region Validations
|
#region Validations
|
||||||
twitterUserDalMock.VerifyAll();
|
twitterUserDalMock.VerifyAll();
|
||||||
loggerMock.VerifyAll();
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,15 +286,122 @@ namespace BirdsiteLive.Pipeline.Tests.Processors
|
|||||||
.Returns(Task.CompletedTask);
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object);
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
#region Validations
|
#region Validations
|
||||||
twitterUserDalMock.VerifyAll();
|
twitterUserDalMock.VerifyAll();
|
||||||
loggerMock.VerifyAll();
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ProcessAsync_NoTweets_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var user = new SyncTwitterUser
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
LastTweetPostedId = 42,
|
||||||
|
LastSync = DateTime.UtcNow.AddDays(-3)
|
||||||
|
};
|
||||||
|
var follower1 = new Follower
|
||||||
|
{
|
||||||
|
FollowingsSyncStatus = new Dictionary<int, long>
|
||||||
|
{
|
||||||
|
{1, 37}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var usersWithTweets = new UserWithDataToSync
|
||||||
|
{
|
||||||
|
Tweets = Array.Empty<ExtractedTweet>(),
|
||||||
|
Followers = new[]
|
||||||
|
{
|
||||||
|
follower1
|
||||||
|
},
|
||||||
|
User = user
|
||||||
|
};
|
||||||
|
|
||||||
|
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var twitterUserDalMock = new Mock<ITwitterUserDal>(MockBehavior.Strict);
|
||||||
|
twitterUserDalMock
|
||||||
|
.Setup(x => x.UpdateTwitterUserAsync(
|
||||||
|
It.Is<SyncTwitterUser>(y => y.LastTweetPostedId == 42
|
||||||
|
&& y.LastSync > DateTime.UtcNow.AddDays(-1))
|
||||||
|
))
|
||||||
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
twitterUserDalMock.VerifyAll();
|
||||||
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ProcessAsync_NoFollower_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var user = new SyncTwitterUser
|
||||||
|
{
|
||||||
|
Id = 1
|
||||||
|
};
|
||||||
|
var tweet1 = new ExtractedTweet
|
||||||
|
{
|
||||||
|
Id = 36
|
||||||
|
};
|
||||||
|
var tweet2 = new ExtractedTweet
|
||||||
|
{
|
||||||
|
Id = 37
|
||||||
|
};
|
||||||
|
|
||||||
|
var usersWithTweets = new UserWithDataToSync
|
||||||
|
{
|
||||||
|
Tweets = new[]
|
||||||
|
{
|
||||||
|
tweet1,
|
||||||
|
tweet2
|
||||||
|
},
|
||||||
|
Followers = Array.Empty<Follower>(),
|
||||||
|
User = user
|
||||||
|
};
|
||||||
|
|
||||||
|
var loggerMock = new Mock<ILogger<SaveProgressionProcessor>>();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var twitterUserDalMock = new Mock<ITwitterUserDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
var removeTwitterAccountActionMock = new Mock<IRemoveTwitterAccountAction>(MockBehavior.Strict);
|
||||||
|
removeTwitterAccountActionMock
|
||||||
|
.Setup(x => x.ProcessAsync(It.Is<SyncTwitterUser>(y => y.Id == user.Id)))
|
||||||
|
.Returns(Task.CompletedTask);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var processor = new SaveProgressionProcessor(twitterUserDalMock.Object, loggerMock.Object, removeTwitterAccountActionMock.Object);
|
||||||
|
await processor.ProcessAsync(usersWithTweets, CancellationToken.None);
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
twitterUserDalMock.VerifyAll();
|
||||||
|
loggerMock.VerifyAll();
|
||||||
|
removeTwitterAccountActionMock.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user