Commit e7d7988f authored by HankG's avatar HankG

Add UserListPostUpdater to lib w/tests and necessary infra updates

parent 38b4f16a
......@@ -53,7 +53,7 @@ namespace MySocialPortalLib.Converter
if (tweet?.Entities?.HashTagEntities?.Count > 0)
{
post.Tags.AddRange(tweet.Entities.HashTagEntities.Select(h => h.Text));
post.AddTags(tweet.Entities.HashTagEntities.Select(h => h.Text));
}
if (tweet?.Entities?.UserMentionEntities?.Count > 0)
......
using MySocialPortalLib.Service;
namespace MySocialPortalDesktop.Factory
{
public interface ISocialMediaConnectorFactory
{
ISocialMediaConnector GetConnectorByNetworkName(string name);
}
}
\ No newline at end of file
using System;
using System.Diagnostics.CodeAnalysis;
using MySocialPortalLib.Model;
using MySocialPortalLib.Service;
using MySocialPortalLib.Service.SocialMediaConnectors;
namespace MySocialPortalDesktop.Factory
{
[SuppressMessage("ReSharper", "CA1822")]
public static class SocialMediaConnectorFactory
public class SocialMediaConnectorFactory : ISocialMediaConnectorFactory
{
public static TwitterConnector GetNewTwitterConnector()
{
return new TwitterConnector(RepositoryFactory.Instance.MainPeopleRepository,
ServiceFactory.BuildNewTimelineManagementService(StandardSocialNetworkNames.Twitter));
}
public ISocialMediaConnector GetConnectorByNetworkName(string name)
{
switch (name)
{
case StandardSocialNetworkNames.Twitter:
return GetNewTwitterConnector();
default:
return null;
}
}
}
}
\ No newline at end of file
......@@ -6,18 +6,19 @@ namespace MySocialPortalLib.Repository
{
public interface IPostsRepository
{
void AddPost(Post post);
void AddOrUpdate(Post post);
void AddPosts(IEnumerable<Post> posts);
Post? GetById(string id);
Post? GetByOriginalNetworkId(string id);
Post? GetByOriginalNetworkId(string network, string id);
IEnumerable<Post> GetPosts(int maxPosts, string personId = "", string networkName = "");
IEnumerable<Post> GetPosts(DateTimeOffset newestPostTime, int maxPosts, bool inclusive, string personId = "", string networkName = "");
IEnumerable<Post> GetPosts(DateTimeOffset oldestPostTime, DateTimeOffset newestPostTime, int maxPosts, bool inclusive, string personId = "", string networkName = "");
}
}
\ No newline at end of file
......@@ -52,9 +52,9 @@ namespace MySocialPortalLib.Repository
}
public void AddPost(Post post)
public void AddOrUpdate(Post post)
{
_postsRepository.Insert(post, _postsCollectionName);
_postsRepository.Upsert(post, _postsCollectionName);
}
public void AddPosts(IEnumerable<Post> posts)
......@@ -79,7 +79,7 @@ namespace MySocialPortalLib.Repository
.FirstOrDefault();
}
public Post GetByOriginalNetworkId(string id)
public Post GetByOriginalNetworkId(string network, string id)
{
if (string.IsNullOrWhiteSpace(id))
{
......@@ -87,7 +87,7 @@ namespace MySocialPortalLib.Repository
}
return _postsRepository.Query<Post>(_postsCollectionName)
.Where(p => p.OriginalLinkUrlOrId == id)
.Where(p => p.OriginalLinkUrlOrId == id && p.OriginalSocialMediaSystem == network)
.FirstOrDefault();
}
......
......@@ -14,5 +14,6 @@ namespace MySocialPortalLib.Service
IEnumerable<Post> GetOlderUserTimeline(Person person, int maxPosts);
bool UserOnSocialNetwork(Person person);
}
}
\ No newline at end of file
......@@ -76,6 +76,7 @@ namespace MySocialPortalLib.Service.SocialMediaConnectors
var newInterval = TimelineManager.GetNextSamplingInterval(twitterId, EarliestTweetValue, LatestTweetValue);
return PullUserTweets(twitterId, newInterval, maxPosts);
}
public IEnumerable<Post> GetOlderUserTimeline(Person person, int maxPosts)
{
var twitterId = "";
......
using System;
using System.Threading.Tasks;
using MySocialPortalDesktop.Factory;
using MySocialPortalLib.Repository;
namespace MySocialPortalLib.Util
{
public class UserListPostUpdater
{
public ISocialMediaConnectorFactory ConnectorFactory { get; }
public int MaxPosts { get; }
public IPersonsRepository PersonsRepository { get; }
public IPostsRepository PostsRepository { get; }
public INamedListRepository UsersLists { get; }
public UserListPostUpdater(ISocialMediaConnectorFactory connectorFactory,
IPostsRepository postsRepository, IPersonsRepository personsRepository,
INamedListRepository usersLists,
int maxPosts)
{
ConnectorFactory = connectorFactory;
PersonsRepository = personsRepository;
PostsRepository = postsRepository;
UsersLists = usersLists;
MaxPosts = maxPosts;
}
public async Task<int> Update(string userListName)
{
var accountsUpdated = 0;
var idsToProcess = UsersLists.GetAllIdsForList(userListName);
if (idsToProcess == null || idsToProcess.Count == 0)
{
return accountsUpdated;
}
foreach (var id in idsToProcess)
{
var person = PersonsRepository.FindById(id);
if (person == null)
{
continue;
}
foreach (var sma in person.SocialMediaAccounts.Values)
{
var connector = ConnectorFactory.GetConnectorByNetworkName(sma.SocialMediaSystemName);
if (connector == null)
{
continue;
}
var posts = connector.GetNewerUserTimeline(person, MaxPosts);
foreach (var post in posts)
{
var oldPost = PostsRepository.GetByOriginalNetworkId(post.OriginalSocialMediaSystem,
post.OriginalLinkUrlOrId);
if (oldPost == null)
{
PostsRepository.AddOrUpdate(post);
}
else
{
oldPost.Merge(post);
PostsRepository.AddOrUpdate(oldPost);
}
}
}
accountsUpdated++;
}
return accountsUpdated;
}
}
}
\ No newline at end of file
......@@ -30,10 +30,24 @@ namespace MySocialPortalLibTest.Service
{
using var postDb = GetTempDb();
Assert.Equal(0, postDb.Count());
postDb.AddPost(new Post{Title = "Test Post1"});
postDb.AddOrUpdate(new Post{Title = "Test Post1"});
Assert.Equal(1, postDb.Count());
}
[Fact]
public void TestUpdate()
{
using var postDb = GetTempDb();
Assert.Equal(0, postDb.Count());
var post1 = new Post {Title = "Test Post1"};
var post2 = new Post {Id = post1.Id, Title = "Test Title 2"};
postDb.AddOrUpdate(post1);
postDb.AddOrUpdate(post2);
Assert.Equal(1, postDb.Count());
var pulledPost = postDb.GetById(post2.Id);
Assert.Equal(post2.Title, pulledPost.Title);
}
[Fact]
public void TestAddMultipleAndCount()
{
......@@ -121,7 +135,7 @@ namespace MySocialPortalLibTest.Service
{
UserId = userId
};
postDb.AddPost(post);
postDb.AddOrUpdate(post);
var postResults = postDb.GetPosts(personId: userId);
Assert.Equal(1, postResults.Count());
Assert.Equal(post, postResults.First());
......@@ -143,21 +157,21 @@ namespace MySocialPortalLibTest.Service
UserId = userId,
OriginalSocialMediaSystem = StandardSocialNetworkNames.Twitter
};
postDb.AddPost(post1);
postDb.AddOrUpdate(post1);
var post2 = new Post
{
UserId = userId,
OriginalSocialMediaSystem = StandardSocialNetworkNames.Diaspora
};
postDb.AddPost(post2);
postDb.AddOrUpdate(post2);
var post3 = new Post
{
UserId = Guid.NewGuid().ToString(),
OriginalSocialMediaSystem = StandardSocialNetworkNames.Diaspora
};
postDb.AddPost(post3);
postDb.AddOrUpdate(post3);
var postResults = postDb.GetPosts(personId: userId, networkName: StandardSocialNetworkNames.Diaspora);
Assert.Equal(1, postResults.Count());
Assert.Equal(post2, postResults.First());
......@@ -169,6 +183,42 @@ namespace MySocialPortalLibTest.Service
Assert.False(postResults.Any());
}
[Fact]
public void TestGetByOriginalNetworkId()
{
using var postDb = GetTempDb();
var postCount = 10;
var postLimit = 3;
var posts = GeneratePosts(postCount);
postDb.AddPosts(posts);
var networkIdCollision = "123456";
var otherNetworkName = "OtherNetwork";
var post1 = new Post
{
OriginalSocialMediaSystem = StandardSocialNetworkNames.Twitter,
OriginalLinkUrlOrId = networkIdCollision
};
postDb.AddOrUpdate(post1);
var post2 = new Post
{
OriginalSocialMediaSystem = StandardSocialNetworkNames.Diaspora,
OriginalLinkUrlOrId = "DA5794C2-DD24-4B71-803A-AA5E06EAFA91"
};
postDb.AddOrUpdate(post2);
var post3 = new Post
{
OriginalSocialMediaSystem = otherNetworkName,
OriginalLinkUrlOrId = networkIdCollision
};
postDb.AddOrUpdate(post3);
Assert.Equal(post1, postDb.GetByOriginalNetworkId(StandardSocialNetworkNames.Twitter, networkIdCollision));
Assert.Equal(post2, postDb.GetByOriginalNetworkId(StandardSocialNetworkNames.Diaspora, post2.OriginalLinkUrlOrId));
Assert.Equal(post3, postDb.GetByOriginalNetworkId(otherNetworkName, networkIdCollision));
Assert.Null(postDb.GetByOriginalNetworkId(StandardSocialNetworkNames.Diaspora, networkIdCollision));
}
[Fact]
public void TestPagingFlow()
{
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using LiteDB;
using MySocialPortalDesktop.Factory;
using MySocialPortalLib.Model;
using MySocialPortalLib.Repository;
using MySocialPortalLib.Service;
using MySocialPortalLib.Util;
using Xunit;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace MySocialPortalLibTest.Util
{
public class TestUserListPostUpdater
{
private const string UserListName1 = "userlist1";
[Fact]
public void TestUpdating()
{
var updater = GetUpdater();
Populate(updater);
updater.Update(UserListName1);
var posts = updater.PostsRepository.GetPosts(100000).ToList();
Assert.Equal(40, posts.Count);
(updater.PostsRepository as PostsLiteDbRepository)?.Dispose();
(updater.PersonsRepository as PersonsLiteDbRepository)?.Dispose();
}
private UserListPostUpdater GetUpdater()
{
var updater = new UserListPostUpdater(new SocialMediaConnectorFactoryStub(),
GetTempPostDb(), GetTempPersonDb(),
GetNamedListDb(), 10);
return updater;
}
private PostsLiteDbRepository GetTempPostDb()
{
return new PostsLiteDbRepository(new FileStream(Path.GetTempFileName() + "posts.db", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None, 4096,
FileOptions.RandomAccess));
}
private PersonsLiteDbRepository GetTempPersonDb()
{
return new PersonsLiteDbRepository(new FileStream(Path.GetTempFileName() + "persons.db", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None, 4096,
FileOptions.RandomAccess ));
}
private NamedListLiteDbRepository GetNamedListDb()
{
var fileStream = new FileStream(Path.GetTempFileName() + "lists.db", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None, 4096,
FileOptions.RandomAccess | FileOptions.DeleteOnClose);
var repo = new LiteRepository(fileStream);
var listRepo = new NamedListLiteDbRepository(repo);
return listRepo;
}
private void Populate(UserListPostUpdater updater)
{
var person1 = new Person
{
Name = "Person1"
};
person1.SocialMediaAccounts[StandardSocialNetworkNames.Diaspora] = new SocialMediaAccountData
{
Id = "1234",
ProfileId = "UserProfile1234",
SocialMediaSystemName = StandardSocialNetworkNames.Diaspora
};
person1.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[0]] = new SocialMediaAccountData
{
Id = "1234",
ProfileId = "UserProfile1234",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[0]
};
person1.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[1]] = new SocialMediaAccountData
{
Id = "1234",
ProfileId = "UserProfile1234",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[1]
};
updater.PersonsRepository.AddPerson(person1);
updater.UsersLists.Add(person1.Id, UserListName1);
var person2 = new Person
{
Name = "Person2"
};
person2.SocialMediaAccounts[StandardSocialNetworkNames.Diaspora] = new SocialMediaAccountData
{
Id = "2",
ProfileId = "UserProfile2",
SocialMediaSystemName = StandardSocialNetworkNames.Diaspora
};
person2.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[0]] = new SocialMediaAccountData
{
Id = "2",
ProfileId = "UserProfile2",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[0]
};
person2.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[1]] = new SocialMediaAccountData
{
Id = "2",
ProfileId = "UserProfile2",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[1]
};
updater.PersonsRepository.AddPerson(person2);
updater.UsersLists.Add(person2.Id, "OtherUserList");
var person3 = new Person
{
Name = "Person3"
};
person3.SocialMediaAccounts[StandardSocialNetworkNames.Diaspora] = new SocialMediaAccountData
{
Id = "3",
ProfileId = "UserProfile3",
SocialMediaSystemName = StandardSocialNetworkNames.Diaspora
};
updater.PersonsRepository.AddPerson(person3);
updater.UsersLists.Add(person3.Id, UserListName1);
var person4 = new Person
{
Name = "Person4"
};
person4.SocialMediaAccounts[StandardSocialNetworkNames.Diaspora] = new SocialMediaAccountData
{
Id = "4",
ProfileId = "UserProfile4",
SocialMediaSystemName = StandardSocialNetworkNames.Diaspora
};
person4.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[0]] = new SocialMediaAccountData
{
Id = "4",
ProfileId = "UserProfil4",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[0]
};
person4.SocialMediaAccounts[SocialMediaConnectorFactoryStub.SocialMediaNames[1]] = new SocialMediaAccountData
{
Id = "4",
ProfileId = "UserProfile4",
SocialMediaSystemName = SocialMediaConnectorFactoryStub.SocialMediaNames[0]
};
updater.PersonsRepository.AddPerson(person4);
updater.UsersLists.Add(person4.Id, UserListName1);
}
class SocialMediaConnectorFactoryStub : ISocialMediaConnectorFactory
{
public static readonly List<string> SocialMediaNames = new List<string> {"SocialNetwork1", "SocialNetwork2"};
public ISocialMediaConnector GetConnectorByNetworkName(string name)
{
if (SocialMediaNames.Contains(name))
{
return new SocialMediaConnectorStub(name);
}
return null;
}
}
class SocialMediaConnectorStub : ISocialMediaConnector
{
public string NetworkName { get; set; }
public SocialMediaConnectorStub(string networkName)
{
NetworkName = networkName;
}
public IEnumerable<Post> GetNewerHomeTimeline(int maxPosts)
{
throw new System.NotImplementedException();
}
public IEnumerable<Post> GetOlderHomeTimeline(int maxPosts)
{
throw new System.NotImplementedException();
}
public IEnumerable<Post> GetNewerUserTimeline(Person person, int maxPosts)
{
var newPosts = new List<Post>(maxPosts);
for (var i = 0; i < maxPosts; i++)
{
var post = new Post
{
Body = $"New Post at {DateTimeOffset.Now} for {person.Name}",
UserId = person.Id,
OriginalSocialMediaSystem = NetworkName,
OriginalLinkUrlOrId = Guid.NewGuid().ToString()
};
newPosts.Add(post);
}
return newPosts;
}
public IEnumerable<Post> GetOlderUserTimeline(Person person, int maxPosts)
{
throw new System.NotImplementedException();
}
public bool UserOnSocialNetwork(Person person)
{
throw new System.NotImplementedException();
}
}
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment