using MongoDB.Entities; using PrivaPub.Domain.Statuses; using PrivaPub.Federation.Actors; using PrivaPub.Models.Social; using PrivaPub.Models.User; using PrivaPub.StaticServices; using System.Text.Json.Nodes; using static PrivaPub.Federation.Objects.ActivityJson; namespace PrivaPub.Federation.Inbox.Handlers { public class AcceptHandler : IActivityHandler { readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; readonly IQuoteService _quotes; public AcceptHandler(DbEntities dbEntities, ILocalActorService localActors, IQuoteService quotes) { _dbEntities = dbEntities; _localActors = localActors; _quotes = quotes; } public virtual string Type => "Accept"; public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token) { if (await _quotes.Answered(activity, actor, accepted: Type == "Accept", token)) { Arrival.Accept("quote-answer"); return; } var following = await FindFollowing(activity["object"], actor, _dbEntities, _localActors, token); if (following == default) { Arrival.Drop("unknown-object"); return; } Arrival.About("Follow"); Arrival.Accept("follow-answer"); await Apply(following, token); } protected virtual Task Apply(Following following, CancellationToken token) => DB.Default.Update().MatchID(following.ID).Modify(f => f.State, FollowState.Accepted).ExecuteAsync(token); public static async Task FindFollowing(JsonNode follow, ForeignAvatar target, DbEntities dbEntities, ILocalActorService localActors, CancellationToken token) { if (follow is JsonObject && Value(follow, "type") is { } type && type != "Follow") return default; var followId = Id(follow); var byId = followId == default ? default : await dbEntities.Followings.Match(f => f.FollowActivityURI == followId && f.TargetActorURI == target.ActorURI).ExecuteFirstAsync(token); if (byId != default || follow is not JsonObject) return byId; var follower = await localActors.FindByUri(Id(follow["actor"]), token); return follower == default ? default : await dbEntities.Followings.Match(f => f.AvatarId == follower.Id && f.TargetActorURI == target.ActorURI).ExecuteFirstAsync(token); } } public class RejectHandler : AcceptHandler { public RejectHandler(DbEntities dbEntities, ILocalActorService localActors, IQuoteService quotes) : base(dbEntities, localActors, quotes) { } public override string Type => "Reject"; protected override Task Apply(Following following, CancellationToken token) => DB.Default.DeleteAsync(following.ID); } }