[backend/api] Add follow list import endpoint

This commit is contained in:
pancakes 2024-10-24 19:26:12 +10:00 committed by Laura Hausmann
parent 6a2ce89699
commit 62aa5f3075
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
2 changed files with 50 additions and 1 deletions

View file

@ -1,9 +1,11 @@
using System.Net;
using System.Net.Mime;
using AngleSharp.Text;
using Iceshrimp.Backend.Controllers.Shared.Attributes;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Middleware;
using Iceshrimp.Backend.Core.Services;
using Iceshrimp.Shared.Schemas.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
@ -16,7 +18,7 @@ namespace Iceshrimp.Backend.Controllers.Web;
[EnableRateLimiting("sliding")]
[Route("/api/iceshrimp/settings")]
[Produces(MediaTypeNames.Application.Json)]
public class SettingsController(DatabaseContext db) : ControllerBase
public class SettingsController(DatabaseContext db, UserService userSvc) : ControllerBase
{
[HttpGet]
[ProducesResults(HttpStatusCode.OK)]
@ -63,4 +65,25 @@ public class SettingsController(DatabaseContext db) : ControllerBase
await db.ReloadEntityAsync(settings);
return settings;
}
[HttpPost("import/following")]
[ProducesResults(HttpStatusCode.Accepted)]
public async Task<AcceptedResult> ImportFollowing(IFormFile file)
{
var user = HttpContext.GetUserOrFail();
var reader = new StreamReader(file.OpenReadStream());
var contents = await reader.ReadToEndAsync();
var fqns = contents
.Split("\n")
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select(line => line.SplitCommas().First())
.Where(fqn => fqn.Contains('@'))
.ToList();
await userSvc.ImportFollowingAsync(user, fqns);
return Accepted();
}
}

View file

@ -39,6 +39,7 @@ public class UserService(
QueueService queueSvc,
EventService eventSvc,
WebFingerService webFingerSvc,
CacheService cacheSvc,
ActivityPub.FederationControlService fedCtrlSvc
)
{
@ -945,6 +946,31 @@ public class UserService(
await db.UserListMembers.Where(p => p.UserList.User == user && p.User == followee).ExecuteDeleteAsync();
}
public async Task ImportFollowingAsync(User user, List<string> fqns)
{
foreach (var fqn in fqns.Select(fqn => fqn.Split("@")))
{
var followee = await db.Users
.IncludeCommonProperties()
.FirstOrDefaultAsync(p => fqn[0].ToLower() == p.UsernameLower &&
fqn[1] == (p.Host ?? instance.Value.AccountDomain));
if (followee == null) continue;
try
{
await FollowUserAsync(user, followee);
}
catch (Exception e)
{
logger.LogWarning("Failed to import follow {followee} for user {follower}: {error}",
followee.Id, user.Id, e);
}
}
await QueryableTimelineExtensions.ResetHeuristic(user, cacheSvc);
}
[SuppressMessage("ReSharper", "SuggestBaseTypeForParameter", Justification = "Method only makes sense for users")]
private void UpdateUserPinnedNotesInBackground(ASActor actor, User user, bool force = false)
{