2026-10-01 11:25:05 +02:00
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.Extensions.Localization;
|
|
|
|
|
|
|
|
|
|
using MongoDB.Entities;
|
|
|
|
|
|
|
|
|
|
using PrivaPub.ClientModels;
|
|
|
|
|
using PrivaPub.ClientModels.Admin;
|
2026-10-17 04:02:47 +02:00
|
|
|
using PrivaPub.Domain.Moderation;
|
|
|
|
|
using PrivaPub.Extensions;
|
2026-10-01 11:25:05 +02:00
|
|
|
using PrivaPub.Federation.Moderation;
|
2026-10-17 04:02:47 +02:00
|
|
|
using PrivaPub.Models;
|
2026-10-01 11:25:05 +02:00
|
|
|
using PrivaPub.Models.Federation;
|
|
|
|
|
using PrivaPub.Resources;
|
|
|
|
|
|
|
|
|
|
namespace PrivaPub.Controllers.ClientToServer
|
|
|
|
|
{
|
|
|
|
|
[ApiController,
|
|
|
|
|
Route("clientapi/admin/domainblocks"),
|
|
|
|
|
Authorize(Policy = Policies.IsAdmin)]
|
|
|
|
|
public class DomainBlockController : ControllerBase
|
|
|
|
|
{
|
|
|
|
|
readonly IDomainBlocks _domainBlocks;
|
|
|
|
|
readonly IStringLocalizer _localizer;
|
2026-10-07 10:54:33 +02:00
|
|
|
readonly Domain.Media.IMediaProxy _proxy;
|
2026-10-17 04:02:47 +02:00
|
|
|
readonly IModerationLog _log;
|
2026-10-01 11:25:05 +02:00
|
|
|
|
2026-10-17 04:02:47 +02:00
|
|
|
public DomainBlockController(IDomainBlocks domainBlocks, IStringLocalizer<GenericRes> localizer, Domain.Media.IMediaProxy proxy, IModerationLog log)
|
2026-10-01 11:25:05 +02:00
|
|
|
{
|
|
|
|
|
_domainBlocks = domainBlocks;
|
|
|
|
|
_localizer = localizer;
|
2026-10-07 10:54:33 +02:00
|
|
|
_proxy = proxy;
|
2026-10-17 04:02:47 +02:00
|
|
|
_log = log;
|
2026-10-01 11:25:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet, Route("/clientapi/admin/domainblocks/list")]
|
|
|
|
|
public async Task<IActionResult> List(CancellationToken token) =>
|
|
|
|
|
Ok((await DB.Default.Find<DomainBlock>().Sort(b => b.Domain, Order.Ascending).ExecuteAsync(token)).Select(ToView).ToList());
|
|
|
|
|
|
|
|
|
|
[HttpPost, Route("/clientapi/admin/domainblocks/insert")]
|
|
|
|
|
public async Task<IActionResult> Insert(DomainBlockForm form, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
var domain = DomainBlocks.Normalise(form.Domain);
|
|
|
|
|
if (!ModelState.IsValid || Uri.CheckHostName(domain) != UriHostNameType.Dns)
|
|
|
|
|
return BadRequest(new WebResult().Invalidate(_localizer["Invalid model."]));
|
|
|
|
|
|
|
|
|
|
var block = await DB.Default.UpdateAndGet<DomainBlock>()
|
|
|
|
|
.Match(b => b.Domain == domain)
|
|
|
|
|
.Modify(b => b.Domain, domain)
|
|
|
|
|
.Modify(b => b.Severity, form.Suspend ? DomainBlockSeverity.Suspend : DomainBlockSeverity.Silence)
|
|
|
|
|
.Modify(b => b.RejectMedia, form.RejectMedia)
|
|
|
|
|
.Modify(b => b.PublicComment, form.PublicComment)
|
|
|
|
|
.Modify(b => b.PrivateComment, form.PrivateComment)
|
2026-10-17 04:02:47 +02:00
|
|
|
.Modify(b => b.Published, form.Published)
|
|
|
|
|
.Modify(b => b.Obfuscate, form.Obfuscate)
|
2026-10-01 11:25:05 +02:00
|
|
|
.Modify(b => b.SetOnInsert(x => x.CreatedAt, DateTime.UtcNow))
|
|
|
|
|
.Option(o => o.IsUpsert = true)
|
|
|
|
|
.ExecuteAsync(token);
|
|
|
|
|
await _domainBlocks.Reload(token);
|
2026-10-07 10:54:33 +02:00
|
|
|
// what the media proxy holds of it goes with the block
|
|
|
|
|
if (block.Severity == DomainBlockSeverity.Suspend || block.RejectMedia)
|
|
|
|
|
_proxy.Purge(domain);
|
2026-10-17 04:02:47 +02:00
|
|
|
await _log.Write(User.GetUserId(), AdminActions.DomainBlockInsert, AdminTargets.Domain, domain, domain,
|
|
|
|
|
note: string.Join(", ", new[] { block.Severity.ToString().ToLowerInvariant(), block.RejectMedia ? "media rejected" : default,
|
|
|
|
|
block.Published ? (block.Obfuscate ? "published, obfuscated" : "published") : default }.Where(n => n != default)), token: token);
|
2026-10-01 11:25:05 +02:00
|
|
|
return Ok(ToView(block));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost, Route("/clientapi/admin/domainblocks/delete")]
|
|
|
|
|
public async Task<IActionResult> Delete([FromQuery] string domain, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
domain = DomainBlocks.Normalise(domain);
|
2026-10-17 04:02:47 +02:00
|
|
|
var deleted = await DB.Default.DeleteAsync<DomainBlock>(b => b.Domain == domain);
|
2026-10-01 11:25:05 +02:00
|
|
|
await _domainBlocks.Reload(token);
|
2026-10-17 04:02:47 +02:00
|
|
|
if (deleted.DeletedCount > 0)
|
|
|
|
|
await _log.Write(User.GetUserId(), AdminActions.DomainBlockDelete, AdminTargets.Domain, domain, domain, token: token);
|
2026-10-01 11:25:05 +02:00
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ViewDomainBlock ToView(DomainBlock block) => new()
|
|
|
|
|
{
|
|
|
|
|
Id = block.ID,
|
|
|
|
|
Domain = block.Domain,
|
|
|
|
|
Severity = block.Severity.ToString(),
|
|
|
|
|
RejectMedia = block.RejectMedia,
|
|
|
|
|
PublicComment = block.PublicComment,
|
|
|
|
|
PrivateComment = block.PrivateComment,
|
2026-10-17 04:02:47 +02:00
|
|
|
Published = block.Published,
|
|
|
|
|
Obfuscate = block.Obfuscate,
|
2026-10-01 11:25:05 +02:00
|
|
|
CreatedAt = block.CreatedAt
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|