using MongoDB.Entities; using PrivaPub.Domain.Statuses; 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.Social; 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 PostEntity = PrivaPub.Models.Post.Post; namespace PrivaPub.Federation.Inbox.Handlers { public class DeleteHandler : IActivityHandler { readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; readonly IRemoteActorService _remoteActors; readonly IDeliveryService _delivery; readonly IGroupDistributor _groups; readonly IQuoteService _quotes; public DeleteHandler(DbEntities dbEntities, ILocalActorService localActors, IRemoteActorService remoteActors, IDeliveryService delivery, IGroupDistributor groups, IQuoteService quotes) { _quotes = quotes; _groups = groups; _dbEntities = dbEntities; _localActors = localActors; _remoteActors = remoteActors; _delivery = delivery; } public string Type => "Delete"; public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token) { var delete = activity; var objectUri = Id(delete["object"]); if (!Origin.Same(objectUri, actor.ActorURI)) { Arrival.Drop("cross-origin"); return; } if (objectUri == actor.ActorURI) { Arrival.Accept("actor-delete"); Arrival.About(actor.AvatarType.ToString(), created: actor.Published); actor.DeletionAt = DateTime.UtcNow; actor.AccountState = AvatarAccountState.Deleted; await DB.Default.SaveAsync(actor, token); var followers = await _dbEntities.Followers.Match(f => f.ActorURI == actor.ActorURI).ExecuteAsync(token); foreach (var follower in followers) { await DB.Default.DeleteAsync(follower.ID); if (follower.LocalActorKind == LocalActorKind.Group) await RemoveForeignMember(follower.LocalActorId, actor.ActorURI, token); } await DB.Default.DeleteAsync(f => f.TargetActorURI == actor.ActorURI); await DB.Default.DeleteAsync(e => e.AuthorAccountId == actor.ID); await DB.Default.Update().Match(p => p.ActorURI == actor.ActorURI).Modify(p => p.AuthorGone, true).ExecuteAsync(token); return; } await RemoteDeletes.Tombstone(objectUri, token); var post = await _dbEntities.Posts.Match(p => p.ObjectURI == objectUri && p.ActorURI == actor.ActorURI).ExecuteFirstAsync(token); if (post == default) { Arrival.Accept("tombstone-only"); await _quotes.Revoke(objectUri, token); return; } Arrival.Accept("removed"); Arrival.About(post.ObjectType, post.Visibility, post.CreationDate); await RemoteDeletes.Remove(post, objectUri, token); if (!string.IsNullOrEmpty(post.GroupId) && await _localActors.FindById(LocalActorKind.Group, post.GroupId, token) is { IsCircle: false } community) await _groups.Announce(community, activity.AsObject(), post.ObjectURI, isNewPost: false, token); } } }