Build / Build (push) Successful in 8m37s
- A Warn from a community's moderator about a persona's own post there becomes that persona's moderation_warning
notification (Mastodon's AccountWarning, with the reason and the post), believed from the community's own server or
from an account the community's moderators collection lists. Remote communities keep that collection's address
(attributedTo) as ForeignAvatar.ModeratorsURL; it is read only when a warning needs it.
- A Resolve{Flag} for one of our reports (`/grunts/flag-<report id>`) is kept as the report's remote resolution when it
comes from the server holding what was reported, or the community it was reported to; our own moderators'
resolution is never replaced. The moderators' report list shows both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
52 lines
1.9 KiB
C#
52 lines
1.9 KiB
C#
using MongoDB.Driver;
|
|
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Models.Social;
|
|
|
|
namespace PrivaPub.Domain.Social
|
|
{
|
|
public static class Notifications
|
|
{
|
|
public static async Task Add(string avatarId, NotificationType type, string fromAccountId, string fromActorUri, string postId,
|
|
CancellationToken token, string emoji = default, string emojiUrl = default, string text = default)
|
|
{
|
|
if (string.IsNullOrEmpty(avatarId) || avatarId == fromAccountId && type != NotificationType.Poll)
|
|
return;
|
|
if ((await Relationships.Hidden.AuthorsHiddenFrom(avatarId, new[] { fromActorUri }, forNotifications: true, token)).Count > 0)
|
|
return;
|
|
var action = await NotificationPolicies.Judge(avatarId, type, fromAccountId, fromActorUri, postId, token);
|
|
if (action == NotificationAction.Drop)
|
|
return;
|
|
try
|
|
{
|
|
var notification = new Notification
|
|
{
|
|
AvatarId = avatarId,
|
|
Type = type,
|
|
FromAccountId = fromAccountId,
|
|
FromActorURI = fromActorUri,
|
|
PostId = postId,
|
|
Emoji = emoji,
|
|
EmojiURL = emojiUrl,
|
|
Text = text,
|
|
DedupeKey = emoji == default ? $"{type}|{avatarId}|{fromActorUri}|{postId}" : $"{type}|{avatarId}|{fromActorUri}|{postId}|{emoji}",
|
|
Filtered = action == NotificationAction.Filter
|
|
};
|
|
await DB.Default.SaveAsync(notification, token);
|
|
// filtered: in its account's request, told to no stream
|
|
if (notification.Filtered)
|
|
{
|
|
await NotificationPolicies.Requested(notification, token);
|
|
return;
|
|
}
|
|
var told = new Timelines.Streams.Event("notification", notification.ID);
|
|
Timelines.Streams.ToPersona(avatarId, new Timelines.Streams.Key(Timelines.Streams.User), told);
|
|
Timelines.Streams.ToPersona(avatarId, new Timelines.Streams.Key(Timelines.Streams.UserNotification), told);
|
|
}
|
|
catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|