R6 moderation in decePub: users and personas, accounts, report actions, deletions, suspended personas
Administration's Users & personas (administrators): logins searched and opened into their personas and groups; roles, bans, two-factor reset and deletion of a login; silence, suspension and deletion of a persona; a group deleted. Accounts (moderators): local personas and remote accounts searched or listed as moderated, silenced and suspended with a staff note and a warning. Reports resolve with an action. ActDialog asks for the note, the warning or the password and is the act's confirmation. A login deletes its own persona and the groups it owns with its password. Suspended personas can't be chosen; one refused a token mid-session moves the session to another, or to none, once. Warnings show in notifications, limited accounts on their profile, and moderators remove a post from its card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
This commit is contained in:
1 parent
4c88980374
commit
c572471b88
30 files changed
+2604
-67
No files matched your search
@@ -10,8 +10,10 @@
|
||||
hide filter leaves it out, a warn filter folds it behind the filter's title, a blur filter blurs its media; "Filter this
|
||||
post" puts it in one of them. Located posts have no Mastodon actions (PrivaPub keeps them off the Mastodon API); their
|
||||
author deletes them through /clientapi. A threadiverse post takes a downvote; the persona's own public post is given who
|
||||
may quote it, and a post quoting it can have its quote revoked; a notification is dismissed from its line. Nerd stats
|
||||
are on the time, the author and its server's history, the place or the CDN, the media and the counts. *@
|
||||
may quote it, and a post quoting it can have its quote revoked; a notification is dismissed from its line, and a
|
||||
warning from the server's staff (moderation_warning) shows what they did and what they wrote. A moderator removes
|
||||
another's post from its menu, with a note and a warning, asked first. Nerd stats are on the time, the author and its
|
||||
server's history, the place or the CDN, the media and the counts. *@
|
||||
@if (!IsFilteredOut)
|
||||
{
|
||||
<article class="flex gap-3 w-full rounded-xl neo-raised @(Highlighted ? "neo-sm" : "neo-2xs") @CssContainer"
|
||||
@@ -60,6 +62,20 @@
|
||||
</DButton>
|
||||
}
|
||||
</p>
|
||||
@if (notification.ModerationWarning is { } warning)
|
||||
{
|
||||
<div class="flex flex-col gap-1 p-2 rounded-lg neo-inset neo-2xs text-sm" data-notification-warning="@warning.Action">
|
||||
<b>@WarningActionText(warning.Action)</b>
|
||||
@if (warning.Text is { Length: > 0 } warningText)
|
||||
{
|
||||
<p class="whitespace-pre-line break-words" data-notification-warning-text>@warningText</p>
|
||||
}
|
||||
@if (warning.StatusIds.Count > 0)
|
||||
{
|
||||
<p class="text-xs opacity-70">@Localizer["It is about {0} of your posts.", warning.StatusIds.Count]</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else if (Post.BoostedBy is { } booster)
|
||||
{
|
||||
@@ -434,6 +450,14 @@
|
||||
<i aria-hidden="true" class="ion-md-remove-circle text-base text-error"></i>
|
||||
<span>@Localizer["Block"]</span>
|
||||
</DButton>
|
||||
@if (CascadingState.IsModerator && !Post.Located)
|
||||
{
|
||||
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Disabled="IsDefaultDisabled || isActing"
|
||||
OnClick="@(() => isModeratingPost = true)" data-moderate-remove-post>
|
||||
<i aria-hidden="true" class="ion-md-trash text-base text-error"></i>
|
||||
<span>@Localizer["Remove post (moderation)"]</span>
|
||||
</DButton>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -508,6 +532,14 @@
|
||||
{
|
||||
<ReportDialog Account="reported" Post="status" OnClosed="@(() => isReporting = false)" />
|
||||
}
|
||||
@if (isModeratingPost)
|
||||
{
|
||||
<ActDialog Question="@Localizer["Remove this post as a moderator?"]"
|
||||
Text="@Localizer["A post written here is deleted as its author would delete it; a copy of one from elsewhere is hidden here."]"
|
||||
ConfirmText="@Localizer["Remove the post"]" Danger="true" Act="remove-post" Staff="true" AskNote="true" AskWarning="true"
|
||||
WarningHint="@Localizer["Only a persona here is told; an account elsewhere is told nothing."]" OnConfirm="RemoveAsModerator"
|
||||
OnClosed="ModerationClosed" />
|
||||
}
|
||||
@if (showInteractedBy is { } boosts)
|
||||
{
|
||||
<InteractedByDialog StatusId="@status.Id" Boosts="boosts" OnClosed="@(() => showInteractedBy = null)" />
|
||||
@@ -544,7 +576,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Post.Notification?.Account is { } follower)
|
||||
else if (Post.Notification is { Type: not "moderation_warning", Account: { } follower })
|
||||
{
|
||||
<p class="text-sm">
|
||||
<a class="font-bold" href="@($"account/{Uri.EscapeDataString(follower.Id)}")">@follower.Name</a>
|
||||
@@ -577,6 +609,7 @@
|
||||
[Inject] TimelineService TimelineService { get; set; }
|
||||
[Inject] InstanceService InstanceService { get; set; }
|
||||
[Inject] ProvenanceService ProvenanceService { get; set; }
|
||||
[Inject] ModerationService ModerationService { get; set; }
|
||||
|
||||
[Parameter, EditorRequired] public FeedPost Post { get; set; }
|
||||
[Parameter] public EventCallback<FeedPost> OnDeleted { get; set; }
|
||||
@@ -610,6 +643,9 @@
|
||||
bool isReporting;
|
||||
bool isFilteringPost;
|
||||
bool isChoosingQuotePolicy;
|
||||
bool isModeratingPost;
|
||||
// the staff removed the post: the page takes it out once the dialog closes
|
||||
bool removedByModerator;
|
||||
// who liked it (false) or boosted it (true), when that list is open
|
||||
bool? showInteractedBy;
|
||||
List<StatusEdit> history = [];
|
||||
@@ -1123,6 +1159,26 @@
|
||||
await OnDeleted.InvokeAsync(Post);
|
||||
}
|
||||
|
||||
// a moderator takes another's post down (/clientapi/moderator/posts/remove): deleted when it was written here, hidden
|
||||
// here when it is a copy from elsewhere
|
||||
async Task<WebResult> RemoveAsModerator(ActDialog.Answer answer)
|
||||
{
|
||||
var result = await ModerationService.RemovePost(new RemovePostForm { PostId = Status.Id, Note = answer.Note, Warning = answer.Warning });
|
||||
if (result.IsInvalid)
|
||||
return result;
|
||||
|
||||
removedByModerator = true;
|
||||
Toast.AddResponseSuccess(Localizer["Post removed."]);
|
||||
return result;
|
||||
}
|
||||
|
||||
async Task ModerationClosed()
|
||||
{
|
||||
isModeratingPost = false;
|
||||
if (removedByModerator)
|
||||
await OnDeleted.InvokeAsync(Post);
|
||||
}
|
||||
|
||||
// someone's post on the persona's wall: its owner deletes it there (PrivaPub tells the wall's readers, and Smithereen
|
||||
// deletes the post)
|
||||
bool IsOnOwnWall(Status status) => !IsOwn && status.Privapub?.Wall?.Id is { } owner && owner == CascadingState.PersonaId;
|
||||
@@ -1293,9 +1349,21 @@
|
||||
"poll" => "ion-md-podium",
|
||||
"update" or "quoted_update" => "ion-md-create",
|
||||
"quote" => "ion-md-quote",
|
||||
"moderation_warning" => "ion-md-warning text-warning",
|
||||
_ => "ion-md-notifications"
|
||||
};
|
||||
|
||||
// what a warning from the server's staff says they did
|
||||
string WarningActionText(string action) => action switch
|
||||
{
|
||||
"silence" => Localizer["This persona is silenced: its posts stay out of public timelines, hashtags, trends and search."],
|
||||
"suspend" => Localizer["This persona was suspended."],
|
||||
"delete_statuses" => Localizer["A post of yours was removed."],
|
||||
"mark_statuses_as_sensitive" or "sensitive" => Localizer["Your media were marked as sensitive."],
|
||||
"disable" => Localizer["This login was disabled."],
|
||||
_ => Localizer["A warning from this server's staff."]
|
||||
};
|
||||
|
||||
string NotificationText(Notification notification)
|
||||
{
|
||||
var name = notification.Account?.Name;
|
||||
@@ -1320,6 +1388,7 @@
|
||||
"update" => Localizer["{0} edited a post", name],
|
||||
"quote" => Localizer["{0} quoted your post", name],
|
||||
"pleroma:emoji_reaction" => Localizer["{0} reacted {1}", name, notification.Emoji],
|
||||
"moderation_warning" => Localizer["This server's staff warned you"],
|
||||
_ => Localizer["{0}: {1}", name, notification.Type]
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user