mirror of
https://github.com/NicolasConstant/BirdsiteLive
synced 2025-06-05 21:49:16 +02:00
added migration logic
This commit is contained in:
@@ -4,19 +4,30 @@ using BirdsiteLive.Twitter;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.ActivityPub;
|
||||||
|
using BirdsiteLive.ActivityPub.Models;
|
||||||
|
using BirdsiteLive.DAL.Contracts;
|
||||||
|
using BirdsiteLive.ActivityPub.Converters;
|
||||||
|
using BirdsiteLive.Common.Settings;
|
||||||
|
|
||||||
namespace BirdsiteLive.Domain
|
namespace BirdsiteLive.Domain
|
||||||
{
|
{
|
||||||
public class MigrationService
|
public class MigrationService
|
||||||
{
|
{
|
||||||
|
private readonly InstanceSettings _instanceSettings;
|
||||||
private readonly ITwitterTweetsService _twitterTweetsService;
|
private readonly ITwitterTweetsService _twitterTweetsService;
|
||||||
private readonly IActivityPubService _activityPubService;
|
private readonly IActivityPubService _activityPubService;
|
||||||
|
private readonly ITwitterUserDal _twitterUserDal;
|
||||||
|
private readonly IFollowersDal _followersDal;
|
||||||
|
|
||||||
#region Ctor
|
#region Ctor
|
||||||
public MigrationService(ITwitterTweetsService twitterTweetsService, IActivityPubService activityPubService)
|
public MigrationService(ITwitterTweetsService twitterTweetsService, IActivityPubService activityPubService, ITwitterUserDal twitterUserDal, IFollowersDal followersDal, InstanceSettings instanceSettings)
|
||||||
{
|
{
|
||||||
_twitterTweetsService = twitterTweetsService;
|
_twitterTweetsService = twitterTweetsService;
|
||||||
_activityPubService = activityPubService;
|
_activityPubService = activityPubService;
|
||||||
|
_twitterUserDal = twitterUserDal;
|
||||||
|
_followersDal = followersDal;
|
||||||
|
_instanceSettings = instanceSettings;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -33,8 +44,14 @@ namespace BirdsiteLive.Domain
|
|||||||
var castedTweetId = ExtractedTweetId(tweetId);
|
var castedTweetId = ExtractedTweetId(tweetId);
|
||||||
var tweet = _twitterTweetsService.GetTweet(castedTweetId);
|
var tweet = _twitterTweetsService.GetTweet(castedTweetId);
|
||||||
|
|
||||||
if (tweet == null) throw new Exception("Tweet not found");
|
if (tweet == null)
|
||||||
if (!tweet.MessageContent.Contains(code)) throw new Exception("Tweet don't have migration code");
|
throw new Exception("Tweet not found");
|
||||||
|
|
||||||
|
if (tweet.CreatorName.Trim().ToLowerInvariant() != acct.Trim().ToLowerInvariant())
|
||||||
|
throw new Exception($"Tweet not published by @{acct}");
|
||||||
|
|
||||||
|
if (!tweet.MessageContent.Contains(code))
|
||||||
|
throw new Exception("Tweet don't have migration code");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -52,25 +69,81 @@ namespace BirdsiteLive.Domain
|
|||||||
throw new ArgumentException("Unvalid Tweet ID");
|
throw new ArgumentException("Unvalid Tweet ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ValidateFediverseAcctAsync(string fediverseAcct)
|
public async Task<ValidatedFediverseUser> ValidateFediverseAcctAsync(string fediverseAcct)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(fediverseAcct))
|
if (string.IsNullOrWhiteSpace(fediverseAcct))
|
||||||
throw new ArgumentException("Please provide Fediverse account");
|
throw new ArgumentException("Please provide Fediverse account");
|
||||||
|
|
||||||
if( !fediverseAcct.Contains('@') || fediverseAcct.Trim('@').Split('@').Length != 2)
|
if( !fediverseAcct.Contains('@') || !fediverseAcct.StartsWith("@") || fediverseAcct.Trim('@').Split('@').Length != 2)
|
||||||
throw new ArgumentException("Please provide valid Fediverse handle");
|
throw new ArgumentException("Please provide valid Fediverse handle");
|
||||||
|
|
||||||
var objectId = await _activityPubService.GetUserIdAsync(fediverseAcct);
|
var objectId = await _activityPubService.GetUserIdAsync(fediverseAcct);
|
||||||
var user = await _activityPubService.GetUser(objectId);
|
var user = await _activityPubService.GetUser(objectId);
|
||||||
|
|
||||||
if(user != null) return true;
|
var result = new ValidatedFediverseUser
|
||||||
|
{
|
||||||
|
FediverseAcct = fediverseAcct,
|
||||||
|
ObjectId = objectId,
|
||||||
|
User = user,
|
||||||
|
IsValid = user != null
|
||||||
|
};
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MigrateAccountAsync(string acct, string tweetId, string fediverseAcct, bool triggerRemoteMigration)
|
public async Task MigrateAccountAsync(ValidatedFediverseUser validatedUser, string acct)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Migration not implemented");
|
// Apply moved to
|
||||||
|
var twitterAccount = await _twitterUserDal.GetTwitterUserAsync(acct);
|
||||||
|
twitterAccount.MovedTo = validatedUser.ObjectId;
|
||||||
|
twitterAccount.MovedToAcct = validatedUser.FediverseAcct;
|
||||||
|
await _twitterUserDal.UpdateTwitterUserAsync(twitterAccount);
|
||||||
|
|
||||||
|
// Notify Followers
|
||||||
|
var t = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var followers = await _followersDal.GetFollowersAsync(twitterAccount.Id);
|
||||||
|
foreach (var follower in followers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var noteId = Guid.NewGuid().ToString();
|
||||||
|
var actorUrl = UrlFactory.GetActorUrl(_instanceSettings.Domain, acct);
|
||||||
|
var noteUrl = UrlFactory.GetNoteUrl(_instanceSettings.Domain, acct, noteId);
|
||||||
|
|
||||||
|
var to = validatedUser.ObjectId;
|
||||||
|
var cc = new string[0];
|
||||||
|
|
||||||
|
var note = new Note
|
||||||
|
{
|
||||||
|
id = noteId,
|
||||||
|
|
||||||
|
published = DateTime.UtcNow.ToString("s") + "Z",
|
||||||
|
url = noteUrl,
|
||||||
|
attributedTo = actorUrl,
|
||||||
|
|
||||||
|
to = new[] { to },
|
||||||
|
cc = cc,
|
||||||
|
|
||||||
|
content = $@"<p>[MIRROR SERVICE NOTIFICATION]<br/>
|
||||||
|
This bot has been disabled by it's original owner.<br/>
|
||||||
|
It has been redirected to {validatedUser.FediverseAcct}.
|
||||||
|
</p>"
|
||||||
|
};
|
||||||
|
|
||||||
|
await _activityPubService.PostNewNoteActivity(note, acct, Guid.NewGuid().ToString(), follower.Host, follower.InboxRoute);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task TriggerRemoteMigrationAsync(string id, string tweetid, string handle)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] GetHash(string inputString)
|
private byte[] GetHash(string inputString)
|
||||||
@@ -88,4 +161,12 @@ namespace BirdsiteLive.Domain
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ValidatedFediverseUser
|
||||||
|
{
|
||||||
|
public string FediverseAcct { get; set; }
|
||||||
|
public string ObjectId { get; set; }
|
||||||
|
public Actor User { get; set; }
|
||||||
|
public bool IsValid { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
@@ -28,7 +28,8 @@ namespace BirdsiteLive.Twitter.Extractors
|
|||||||
IsReply = tweet.InReplyToUserId != null,
|
IsReply = tweet.InReplyToUserId != null,
|
||||||
IsThread = tweet.InReplyToUserId != null && tweet.InReplyToUserId == tweet.CreatedBy.Id,
|
IsThread = tweet.InReplyToUserId != null && tweet.InReplyToUserId == tweet.CreatedBy.Id,
|
||||||
IsRetweet = tweet.IsRetweet || tweet.QuotedStatusId != null,
|
IsRetweet = tweet.IsRetweet || tweet.QuotedStatusId != null,
|
||||||
RetweetUrl = ExtractRetweetUrl(tweet)
|
RetweetUrl = ExtractRetweetUrl(tweet),
|
||||||
|
CreatorName = tweet.CreatedBy.Name
|
||||||
};
|
};
|
||||||
|
|
||||||
return extractedTweet;
|
return extractedTweet;
|
||||||
|
@@ -15,5 +15,6 @@ namespace BirdsiteLive.Twitter.Models
|
|||||||
public bool IsThread { get; set; }
|
public bool IsThread { get; set; }
|
||||||
public bool IsRetweet { get; set; }
|
public bool IsRetweet { get; set; }
|
||||||
public string RetweetUrl { get; set; }
|
public string RetweetUrl { get; set; }
|
||||||
|
public string CreatorName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -51,25 +51,27 @@ namespace BirdsiteLive.Controllers
|
|||||||
FediverseAccount = handle
|
FediverseAccount = handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ValidatedFediverseUser fediverseUserValidation = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var isAcctValid = await _migrationService.ValidateFediverseAcctAsync(handle);
|
fediverseUserValidation = await _migrationService.ValidateFediverseAcctAsync(handle);
|
||||||
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
|
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
|
||||||
|
|
||||||
data.IsAcctValid = isAcctValid;
|
data.IsAcctValid = fediverseUserValidation.IsValid;
|
||||||
data.IsTweetValid = isTweetValid;
|
data.IsTweetValid = isTweetValid;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
data.ErrorMessage = e.Message;
|
data.ErrorMessage = e.Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.IsAcctValid && data.IsTweetValid && fediverseUserValidation != null)
|
||||||
if (data.IsAcctValid && data.IsTweetValid)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _migrationService.MigrateAccountAsync(id, tweetid, handle, true);
|
await _migrationService.MigrateAccountAsync(fediverseUserValidation, id);
|
||||||
|
await _migrationService.TriggerRemoteMigrationAsync(id, tweetid, handle);
|
||||||
data.MigrationSuccess = true;
|
data.MigrationSuccess = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -86,12 +88,12 @@ namespace BirdsiteLive.Controllers
|
|||||||
[Route("/migration/{id}/{tweetid}/{handle}")]
|
[Route("/migration/{id}/{tweetid}/{handle}")]
|
||||||
public async Task<IActionResult> RemoteMigrate(string id, string tweetid, string handle)
|
public async Task<IActionResult> RemoteMigrate(string id, string tweetid, string handle)
|
||||||
{
|
{
|
||||||
var isAcctValid = await _migrationService.ValidateFediverseAcctAsync(handle);
|
var fediverseUserValidation = await _migrationService.ValidateFediverseAcctAsync(handle);
|
||||||
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
|
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
|
||||||
|
|
||||||
if (isAcctValid && isTweetValid)
|
if (fediverseUserValidation.IsValid && isTweetValid)
|
||||||
{
|
{
|
||||||
await _migrationService.MigrateAccountAsync(id, tweetid, handle, false);
|
await _migrationService.MigrateAccountAsync(fediverseUserValidation, id);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user