R5 the server's own settings: instance, rules, announcements, relays, media limits, the staff's log
Build / Build (push) Successful in 1m3s

A singleton ServerSettings (title, descriptions, contact, thumbnail, privacy policy, terms, rules, relays, media
overrides, PublishActivity), cached by InstanceSettings and read by the instance API, NodeInfo, the instance actor, the
web pages and the mailer; its defaults are the old literals, so nothing changes until an administrator edits.
/clientapi/admin/settings (and /thumbnail), /announcements, /relays for administrators; /clientapi/moderator/log, the
staff's log (AdminAction, written by domain blocks, backups, settings and the CLI; no IP, never a root paired with its
personas). The Mastodon API's rules, extended description, privacy policy, terms of service, domain blocks (Published,
Obfuscate), announcements (dismiss, reactions, streaming) and activity (only when published). Reports carry rule ids.
Media overrides clamped to hard caps. Relays named by the settings reconcile next to the configured ones.

Verified: interop.sh instance accounts relay with mastodon, relay, aoderelay and mailpit, 119 passed.

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 04:02:47 +02:00
1 parent f67e2ae35e
commit 70d1ffe9a2
46 files changed
+2223 -107

No files matched your search

@@ -8,6 +8,7 @@ using MongoDB.Entities;
using PrivaPub.ClientModels;
using PrivaPub.ClientModels.Admin;
using PrivaPub.Domain.Moderation;
using PrivaPub.Extensions;
using PrivaPub.Infrastructure.Backup;
using PrivaPub.Models.User;
@@ -24,7 +25,7 @@ namespace PrivaPub.Controllers.ClientToServer
Route("clientapi/admin/backups"),
Authorize(Policy = Policies.IsAdmin)]
public class BackupController(Backups backups, TransferStore transfers, IPasswordHasher hasher, IStringLocalizer<GenericRes> localizer,
ILogger<BackupController> logger) : ControllerBase
ILogger<BackupController> logger, IModerationLog log) : ControllerBase
{
[HttpGet, Route("")]
public async Task<IActionResult> List(CancellationToken token)
@@ -64,6 +65,7 @@ namespace PrivaPub.Controllers.ClientToServer
return Forbid();
if (await MaintenanceLock.Current(token) is { } held)
return Conflict(new WebResult().Invalidate(localizer["A {0} is running.", held.What]));
await log.Write(admin.ID, Models.AdminActions.BackupCreate, Models.AdminTargets.Backup, default, "manual", token: token);
_ = Task.Run(async () =>
{
try
@@ -85,11 +87,15 @@ namespace PrivaPub.Controllers.ClientToServer
[HttpDelete, Route("{id}")]
public async Task<IActionResult> Delete(string id, CancellationToken token)
{
if (await Administrator(token) == default)
var admin = await Administrator(token);
if (admin == default)
return Forbid();
if (RestoreMarker.Read(backups.Root) is { } waiting && (waiting.Backup == id || waiting.PreRestore == id))
return Conflict(new WebResult().Invalidate(localizer["A restore waits for this backup."]));
return backups.Delete(id) ? Ok() : NotFound();
if (!backups.Delete(id))
return NotFound();
await log.Write(admin.ID, Models.AdminActions.BackupDelete, Models.AdminTargets.Backup, id, id, token: token);
return Ok();
}
// a link to download it with, for the password
@@ -211,6 +217,7 @@ namespace PrivaPub.Controllers.ClientToServer
if (refused != default)
return UnprocessableEntity(new WebResult().Invalidate(refused));
logger.LogWarning("{Admin} asked to restore {Backup}", admin.UserName, id);
await log.Write(admin.ID, Models.AdminActions.BackupRestore, Models.AdminTargets.Backup, id, id, token: token);
return Accepted();
}