Files
SocialPub/PrivaPub/Federation/Inbox/Handlers/BlockHandler.cs
T

72 lines
3.0 KiB
C#
Raw Normal View History

using MongoDB.Driver;
using MongoDB.Entities;
using PrivaPub.Federation.Actors;
using PrivaPub.Models.Federation;
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
{
// A remote account blocks one of our personas, as Mastodon does it: the follows between them end here too (the blocker
// already ended its side, so nothing is sent back), the persona stops seeing the blocker's posts and notifications, the
// relationship says blocked_by, and nothing of the persona's is addressed to the blocker any more. Undo{Block} lifts it.
public class BlockHandler : IActivityHandler
{
readonly DbEntities _dbEntities;
readonly ILocalActorService _localActors;
public BlockHandler(DbEntities dbEntities, ILocalActorService localActors)
{
_dbEntities = dbEntities;
_localActors = localActors;
}
public string Type => "Block";
public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token)
{
var target = Id(activity["object"]) is { } uri ? await _localActors.FindByUri(uri, token) : default;
if (target is not { Kind: LocalActorKind.Person })
{
Arrival.Drop("unknown-object");
return;
}
try
{
await DB.Default.SaveAsync(new BlockedBy { AvatarId = target.Id, ActorURI = actor.ActorURI, AccountId = actor.ID, ActivityURI = Id(activity) }, token);
}
catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey)
{
Arrival.Drop("duplicate");
return;
}
Arrival.Accept("stored");
await DB.Default.DeleteAsync<Following>(f => f.AvatarId == target.Id && f.TargetActorURI == actor.ActorURI);
await DB.Default.DeleteAsync<Follower>(f => f.LocalActorId == target.Id && f.ActorURI == actor.ActorURI);
await DB.Default.DeleteAsync<TimelineEntry>(e => e.AvatarId == target.Id && e.AuthorAccountId == actor.ID);
await DB.Default.DeleteAsync<Notification>(n => n.AvatarId == target.Id && n.FromAccountId == actor.ID);
}
// Undo{Block}: the block it names by id, or else the blocker's block of the persona the inner Block names
public static async Task<bool> Undo(JsonNode inner, string innerId, ForeignAvatar actor, ILocalActorService localActors, CancellationToken token)
{
var block = innerId == default
? default
: await DB.Default.Find<BlockedBy>().Match(b => b.ActivityURI == innerId && b.ActorURI == actor.ActorURI).ExecuteFirstAsync(token);
if (block == default && inner is JsonObject && Id(inner["object"]) is { } objectUri
&& await localActors.FindByUri(objectUri, token) is { Kind: LocalActorKind.Person } persona)
block = await DB.Default.Find<BlockedBy>().Match(b => b.AvatarId == persona.Id && b.ActorURI == actor.ActorURI).ExecuteFirstAsync(token);
if (block == default)
return false;
await DB.Default.DeleteAsync<BlockedBy>(block.ID);
return true;
}
}
}