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:
thepraandClaude Opus 5.5 committed 2026-10-17 05:41:10 +02:00
1 parent 4c88980374
commit c572471b88
30 files changed
+2604 -67

No files matched your search

+19
View File
@@ -1,6 +1,7 @@
using System.Net;
using decePubClient.Extensions;
using decePubClient.Helpers;
using decePubClient.Models;
using PrivaPub.ClientModels;
@@ -59,6 +60,24 @@ namespace decePubClient.Services
public Task<WebResult> Remove(string personaId, string groupId, string actorUri, CancellationToken cancellationToken = default) =>
Membership(APIs.ClientApi.POST_RemoveGroupMember, personaId, groupId, actorUri, cancellationToken);
/// <summary>
/// Deletes a group the persona owns, the login's password given: its members and followers are told, its name stays
/// taken. PrivaPub answers a wrong password, or a persona that isn't the owner, with 403.
/// </summary>
public async Task<WebResult> Delete(string personaId, string groupId, string password, CancellationToken cancellationToken = default)
{
using var response = await httpService.Post(APIs.ClientApi.POST_DeleteGroup,
new DeleteGroupForm { AvatarId = personaId, GroupId = groupId, Password = password }, cancellationToken: cancellationToken);
if (response.IsSuccessStatusCode)
return new WebResult();
// the owner is the only one offered it, so PrivaPub's own 403 is the password's
if (response.StatusCode is HttpStatusCode.Forbidden && !response.Content.Headers.Contains(SUtility.FailureHeader))
return new WebResult().Invalidate(localizer["Wrong password."], (int)HttpStatusCode.Forbidden);
return await response.Content.ReadWebResult(response.StatusCode, localizer, cancellationToken);
}
/// <summary>Who is in a group the persona runs, and who asks to join; empty on failure.</summary>
public async Task<List<ViewGroupMember>> Members(string personaId, string groupId, CancellationToken cancellationToken = default)
{