// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . using System.Net; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace Foxnouns.Backend.Controllers.Moderation; [Route("/api/v2/moderation")] [Authorize("user.moderation")] [Limit(RequireModerator = true)] public class ModActionsController( DatabaseContext db, ModerationService moderationService, ModerationRendererService moderationRenderer ) : ApiControllerBase { [HttpPost("warnings/{id}")] public async Task WarnUserAsync(Snowflake id, [FromBody] WarnUserRequest req) { User user = await db.ResolveUserAsync(id); if (user.Deleted) { throw new ApiError( "This user is already deleted.", HttpStatusCode.BadRequest, ErrorCode.InvalidWarningTarget ); } if (user.Id == CurrentUser!.Id) { throw new ApiError( "You can't warn yourself.", HttpStatusCode.BadRequest, ErrorCode.InvalidWarningTarget ); } Member? member = null; if (req.MemberId != null) { member = await db.Members.FirstOrDefaultAsync(m => m.Id == req.MemberId && m.UserId == user.Id ); if (member == null) throw new ApiError.NotFound("No member with that ID found."); } Report? report = null; if (req.ReportId != null) { report = await db.Reports.FindAsync(req.ReportId); if (report is not { Status: ReportStatus.Open }) { throw new ApiError.NotFound( "No report with that ID found, or it's already closed." ); } } AuditLogEntry entry = await moderationService.ExecuteWarningAsync( CurrentUser, user, member, report, req.Reason, req.ClearFields ); return Ok(moderationRenderer.RenderAuditLogEntry(entry)); } [HttpPost("suspensions/{id}")] public async Task SuspendUserAsync( Snowflake id, [FromBody] SuspendUserRequest req ) { User user = await db.ResolveUserAsync(id); if (user.Deleted) { throw new ApiError( "This user is already deleted.", HttpStatusCode.BadRequest, ErrorCode.InvalidWarningTarget ); } if (user.Id == CurrentUser!.Id) { throw new ApiError( "You can't warn yourself.", HttpStatusCode.BadRequest, ErrorCode.InvalidWarningTarget ); } Report? report = null; if (req.ReportId != null) { report = await db.Reports.FindAsync(req.ReportId); if (report is not { Status: ReportStatus.Open }) { throw new ApiError.NotFound( "No report with that ID found, or it's already closed." ); } } AuditLogEntry entry = await moderationService.ExecuteSuspensionAsync( CurrentUser, user, report, req.Reason, req.ClearProfile ); return Ok(moderationRenderer.RenderAuditLogEntry(entry)); } }