using MongoDB.Entities; using PrivaPub.Federation.Actors; using PrivaPub.Federation.Outbox; using PrivaPub.Federation.Rendering; using PrivaPub.Models.Social; using PrivaPub.Models.User; using PrivaPub.StaticServices; using System.Text.Json.Nodes; namespace PrivaPub.Domain.Relationships { public interface IReportService { Task File(LocalActor reporter, string targetAccountId, IReadOnlyList postIds, string comment, string category, bool forward, CancellationToken token); } public class ReportService : IReportService { readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; readonly IDeliveryService _delivery; public ReportService(DbEntities dbEntities, ILocalActorService localActors, IDeliveryService delivery) { _dbEntities = dbEntities; _localActors = localActors; _delivery = delivery; } public async Task File(LocalActor reporter, string targetAccountId, IReadOnlyList postIds, string comment, string category, bool forward, CancellationToken token) { var localTarget = await _dbEntities.Avatars.MatchID(targetAccountId).ExecuteFirstAsync(token); var remoteTarget = localTarget == default ? await _dbEntities.ForeignAvatars.MatchID(targetAccountId).ExecuteFirstAsync(token) : default; if (localTarget == default && remoteTarget == default) return default; var targetUri = localTarget != default ? _localActors.FromAvatar(localTarget).Uri : remoteTarget.ActorURI; var posts = postIds.Count == 0 ? new List() : await _dbEntities.Posts.Match(p => postIds.Contains(p.ID) && p.ActorURI == targetUri).ExecuteAsync(token); var report = new Report { ReporterAvatarId = reporter.Id, TargetAccountId = targetAccountId, TargetActorURI = targetUri, PostIds = posts.Select(p => p.ID).ToList(), ObjectURIs = posts.Select(p => p.ObjectURI).ToList(), Comment = comment?.Trim(), Category = category is "spam" or "legal" or "violation" ? category : "other", Forwarded = forward && remoteTarget != default }; await DB.Default.SaveAsync(report, token); if (report.Forwarded) { var instance = await _localActors.GetInstanceActor(token); var flag = new JsonObject { ["@context"] = ActivityPubRenderer.ActivityStreams, ["id"] = instance.ActivityUri($"flag-{report.ID}"), ["type"] = "Flag", ["actor"] = instance.Uri, ["content"] = report.Comment ?? string.Empty, ["object"] = new JsonArray(report.ObjectURIs.Prepend(targetUri).Select(u => (JsonNode)u).ToArray()) }; await _delivery.Enqueue(instance, new[] { remoteTarget.SharedInboxURL ?? remoteTarget.InboxURL }, flag, token); } return report; } } }