Build / Build (push) Successful in 1m5s
Administration's Pleroma placeholders give way to real sections: Instance (title, descriptions, contact, thumbnail, privacy policy, terms, the weekly activity), Rules, Announcements, Relays, Media limits and the Moderation log, next to Reports, blocked servers (now published or obfuscated), statistics and backups; moderators see Reports and the log. Every save sends the whole settings form built from the latest read, since PrivaPub replaces what it carries. /about shows the server's documents to anyone. The report dialog picks the rules a violation breaks, and reports show them. Announcements show above the feed tabs, dismissed and reacted to, live from the user stream. Login names the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
165 lines
5.0 KiB
Plaintext
165 lines
5.0 KiB
Plaintext
@inherits LocalizableComponentBase
|
|
|
|
@* The reports moderators handle (/clientapi/moderator/reports): from someone here (never said who) or from another
|
|
server, about an account and some of its posts, a violation with the server's rules it names (their texts as PrivaPub
|
|
keeps them, a removed rule's too); resolved here. *@
|
|
<div class="flex flex-col gap-3 w-full" data-reports>
|
|
<DToggle LabelText="@Localizer["Show the resolved ones"]" Value="resolved" ValueChanged="ShowResolved" ValueExpression="() => resolved" />
|
|
|
|
@if (IsLoading)
|
|
{
|
|
<p class="flex w-full items-center justify-center gap-2">
|
|
<DLoading Variant="DLoadingVariant.Dots" LabelText="@Localizer["loading"]" />
|
|
@Localizer["loading"]
|
|
</p>
|
|
}
|
|
else if (reports.Count == 0)
|
|
{
|
|
<p class="text-sm opacity-70">@(resolved ? Localizer["No resolved report."] : Localizer["No open report."])</p>
|
|
}
|
|
|
|
@foreach (var report in reports)
|
|
{
|
|
<article class="flex flex-col gap-2 p-3 rounded-xl neo-raised neo-xs" data-report-id="@report.ID">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<DBadge Size="DSize.Sm" Variant="DBadgeVariant.Soft" Color="DColor.Warning">@CategoryName(report.Category)</DBadge>
|
|
@if (report.Forwarded)
|
|
{
|
|
<DBadge Size="DSize.Sm" Variant="DBadgeVariant.Soft">@Localizer["Forwarded"]</DBadge>
|
|
}
|
|
<span class="text-xs opacity-70" title="@report.CreatedAt.ToLocalTime().ToString(SUtility.dateTimeFormat)">
|
|
@report.CreatedAt.GetPassedTime(Localizer)
|
|
</span>
|
|
<span class="flex-1"></span>
|
|
@if (!report.IsResolved)
|
|
{
|
|
<DButton Size="DSize.Sm" Color="DColor.Success" Disabled="@(IsDefaultDisabled || busy.Contains(report.ID))" OnClick="() => Resolve(report)"
|
|
data-report-resolve>
|
|
<i class="ion-md-checkmark"></i><span>@Localizer["Resolve"]</span>
|
|
</DButton>
|
|
}
|
|
else if (report.ResolvedAt is { } resolvedAt)
|
|
{
|
|
<span class="text-xs opacity-70">@Localizer["Resolved {0}", resolvedAt.GetPassedTime(Localizer)]</span>
|
|
}
|
|
</div>
|
|
<p class="text-sm">
|
|
<b>@Localizer["About"]</b>
|
|
@if (report.TargetAccountId is { Length: > 0 } targetId)
|
|
{
|
|
<a class="link link-hover break-all" href="@($"account/{Uri.EscapeDataString(targetId)}")">@report.TargetActorURI</a>
|
|
}
|
|
else
|
|
{
|
|
<span class="break-all">@report.TargetActorURI</span>
|
|
}
|
|
</p>
|
|
<p class="text-sm">
|
|
<b>@Localizer["From"]</b>
|
|
<span class="break-all">@(report.Reporter == "local" ? Localizer["someone here"] : report.Reporter)</span>
|
|
</p>
|
|
@if (report.RuleIds.Count > 0)
|
|
{
|
|
<div class="flex flex-col gap-1 text-sm" data-report-rules>
|
|
<b>@Localizer["Rules it names"]</b>
|
|
<ol class="list-decimal ps-5">
|
|
@foreach (var (ruleId, text) in RulesOf(report))
|
|
{
|
|
<li class="break-words" data-report-rule-id="@ruleId">
|
|
@if (text is { Length: > 0 })
|
|
{
|
|
@text
|
|
}
|
|
else
|
|
{
|
|
<span class="opacity-70">@Localizer["A rule no longer kept"]</span>
|
|
}
|
|
</li>
|
|
}
|
|
</ol>
|
|
</div>
|
|
}
|
|
@if (report.Comment is { Length: > 0 } comment)
|
|
{
|
|
<p class="text-sm whitespace-pre-line rounded-lg neo-inset neo-2xs p-2">@comment</p>
|
|
}
|
|
@if (report.PostIds.Count > 0 || report.ObjectURIs.Count > 0)
|
|
{
|
|
<div class="flex flex-wrap gap-2 text-xs">
|
|
@foreach (var postId in report.PostIds)
|
|
{
|
|
<a class="link" href="@($"expand/{Uri.EscapeDataString(postId)}")">@Localizer["Post {0}", postId]</a>
|
|
}
|
|
@* a report from another server names posts by their ids there when we hold none of them *@
|
|
@if (report.PostIds.Count == 0)
|
|
{
|
|
@foreach (var uri in report.ObjectURIs)
|
|
{
|
|
<span class="break-all opacity-70">@uri</span>
|
|
}
|
|
}
|
|
</div>
|
|
}
|
|
</article>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
[Inject] AdminService AdminService { get; set; }
|
|
|
|
List<ViewReport> reports = [];
|
|
bool resolved;
|
|
HashSet<string> busy = [];
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
if (CascadingState.IsOffline)
|
|
{
|
|
WhenOnline(LoadData);
|
|
StartOnlinePolling();
|
|
IsLoading = false;
|
|
return;
|
|
}
|
|
|
|
await LoadData();
|
|
IsLoading = false;
|
|
}
|
|
|
|
async Task LoadData() => reports = await AdminService.Reports(resolved);
|
|
|
|
async Task ShowResolved(bool value)
|
|
{
|
|
resolved = value;
|
|
IsLoading = true;
|
|
await LoadData();
|
|
IsLoading = false;
|
|
}
|
|
|
|
// each rule the report names with its text, in the report's order (an empty text: the server no longer has it)
|
|
static IEnumerable<(string Id, string Text)> RulesOf(ViewReport report) =>
|
|
report.RuleIds.Select((id, i) => (id, i < report.Rules.Count ? report.Rules[i] : null));
|
|
|
|
string CategoryName(string category) => category switch
|
|
{
|
|
"spam" => Localizer["Spam"],
|
|
"legal" => Localizer["Illegal"],
|
|
"violation" => Localizer["Breaks the rules"],
|
|
_ => Localizer["Other"]
|
|
};
|
|
|
|
async Task Resolve(ViewReport report)
|
|
{
|
|
busy.Add(report.ID);
|
|
var result = await AdminService.Resolve(report.ID);
|
|
busy.Remove(report.ID);
|
|
if (result.IsInvalid)
|
|
{
|
|
Toast.AddResponseError(result);
|
|
return;
|
|
}
|
|
|
|
reports.Remove(report);
|
|
Toast.AddResponseSuccess(Localizer["Report resolved."]);
|
|
}
|
|
}
|