86 lines
3.0 KiB
C#
86 lines
3.0 KiB
C#
using MongoDB.Entities;
|
|||
|
|
|
||
|
|
using PrivaPub.Domain.Social;
|
||
|
|
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
|
||
|
|
{
|
||
|
|
// Lemmy 1.0's warning: a community's moderator tells one of our personas, about one of its posts there, why (Warn{to:
|
||
|
|
// [persona], object: post, summary: reason, audience: community}), sent to the persona's inbox alone. It becomes the
|
||
|
|
// persona's moderation_warning notification, once the sender is shown to moderate that community and the post is the
|
||
|
|
// persona's own, in it.
|
||
|
|
public class WarnHandler : IActivityHandler
|
||
|
|
{
|
||
|
|
const int MaxReason = 1000;
|
||
|
|
|
||
|
|
readonly DbEntities _dbEntities;
|
||
|
|
readonly ILocalActorService _localActors;
|
||
|
|
readonly IRemoteActorService _remoteActors;
|
||
|
|
|
||
|
|
public WarnHandler(DbEntities dbEntities, ILocalActorService localActors, IRemoteActorService remoteActors)
|
||
|
|
{
|
||
|
|
_dbEntities = dbEntities;
|
||
|
|
_localActors = localActors;
|
||
|
|
_remoteActors = remoteActors;
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Type => "Warn";
|
||
|
|
|
||
|
|
public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token)
|
||
|
|
{
|
||
|
|
LocalActor persona = default;
|
||
|
|
foreach (var uri in Recipients(activity["to"]))
|
||
|
|
if (await _localActors.FindByUri(uri, token) is { Kind: LocalActorKind.Person } found)
|
||
|
|
{
|
||
|
|
persona = found;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (persona == default)
|
||
|
|
{
|
||
|
|
Arrival.Drop("not-ours");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
var communityUri = Id(activity["audience"]);
|
||
|
|
var community = communityUri == default ? default : await _remoteActors.GetActor(communityUri, refresh: false, token);
|
||
|
|
if (community is not { AvatarType: AvatarType.Group })
|
||
|
|
{
|
||
|
|
Arrival.Drop("unknown-community");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
var objectUri = Id(activity["object"]);
|
||
|
|
var post = objectUri == default
|
||
|
|
? default
|
||
|
|
: await _dbEntities.Posts.Match(p => p.ObjectURI == objectUri && p.GroupUserId == persona.Id && !p.IsFederatedCopy).ExecuteFirstAsync(token);
|
||
|
|
if (post == default || await Communities.Of(post, _dbEntities, token) != community.ActorURI)
|
||
|
|
{
|
||
|
|
Arrival.Drop("unknown-object");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Arrival.About(visibility: post.Visibility, created: post.CreationDate, local: persona);
|
||
|
|
if (!await Communities.Moderates(community, actor.ActorURI, _remoteActors, token))
|
||
|
|
{
|
||
|
|
Arrival.Drop("not-moderator");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
var reason = Value(activity, "summary") ?? Value(activity, "content");
|
||
|
|
await Notifications.Add(persona.Id, NotificationType.ModerationWarning, community.ID, community.ActorURI, post.ID, token,
|
||
|
|
text: string.IsNullOrWhiteSpace(reason) ? default : reason.Trim().Length <= MaxReason ? reason.Trim() : reason.Trim()[..MaxReason]);
|
||
|
|
Arrival.Accept("warned");
|
||
|
|
}
|
||
|
|
|
||
|
|
static IEnumerable<string> Recipients(JsonNode node) => node switch
|
||
|
|
{
|
||
|
|
JsonArray array => array.Select(Id).Where(id => id != default),
|
||
|
|
JsonNode single when Id(single) is { } id => new[] { id },
|
||
|
|
_ => Enumerable.Empty<string>()
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|