using MongoDB.Entities; using PrivaPub.Federation.Actors; using PrivaPub.Federation.Objects; using PrivaPub.Federation.Outbox; using PrivaPub.Federation.Rendering; using PrivaPub.Models.Federation; using PrivaPub.Models.Group; using PrivaPub.Models.Post; using PrivaPub.Models.User; using PrivaPub.StaticServices; using System.Text.Json.Nodes; using static PrivaPub.Federation.Inbox.ForeignMembers; using static PrivaPub.Federation.Objects.ActivityJson; using DmPostEntity = PrivaPub.Models.Post.DmPost; using PostEntity = PrivaPub.Models.Post.Post; namespace PrivaPub.Federation.Inbox.Handlers { public class FollowHandler : IActivityHandler { readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; readonly IRemoteActorService _remoteActors; readonly IDeliveryService _delivery; public FollowHandler(DbEntities dbEntities, ILocalActorService localActors, IRemoteActorService remoteActors, IDeliveryService delivery) { _dbEntities = dbEntities; _localActors = localActors; _remoteActors = remoteActors; _delivery = delivery; } public string Type => "Follow"; public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token) { var follow = activity; var follower = actor; var target = await _localActors.FindByUri(Id(follow["object"]), token); if (target is not { IsFederated: true } || target.Kind == LocalActorKind.Application) return; var existing = await _dbEntities.Followers .Match(f => f.LocalActorId == target.Id && f.LocalActorKind == target.Kind && f.ActorURI == follower.ActorURI) .ExecuteFirstAsync(token); var record = existing ?? new Follower { LocalActorId = target.Id, LocalActorKind = target.Kind, ActorURI = follower.ActorURI }; record.InboxURL = follower.InboxURL; record.SharedInboxURL = follower.SharedInboxURL; record.FollowActivityURI = Id(follow); record.IsAccepted = existing?.IsAccepted == true || !target.ManuallyApprovesFollowers; await DB.Default.SaveAsync(record, token); if (!record.IsAccepted) return; if (target.Kind == LocalActorKind.Group) await AddForeignMember(target.Id, follower.ActorURI, token); var accept = ActivityPubRenderer.Accept(target, follow, $"accept-{record.ID}-{DateTime.UtcNow.Ticks}"); await _delivery.Enqueue(target, new[] { follower.InboxURL }, accept, token); return; } } }