diff --git a/Iceshrimp.Backend/Controllers/Pleroma/AdminController.cs b/Iceshrimp.Backend/Controllers/Pleroma/AdminController.cs new file mode 100644 index 00000000..5374bc71 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/AdminController.cs @@ -0,0 +1,106 @@ +using System.Net; +using System.Net.Mime; +using Iceshrimp.Backend.Controllers.Mastodon.Attributes; +using Iceshrimp.Backend.Controllers.Pleroma.Schemas; +using Iceshrimp.Backend.Controllers.Shared.Attributes; +using Iceshrimp.Backend.Controllers.Web.Renderers; +using Iceshrimp.Backend.Core.Database; +using Iceshrimp.Backend.Core.Extensions; +using Iceshrimp.Backend.Core.Middleware; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; +using Microsoft.EntityFrameworkCore; +using NoteRenderer = Iceshrimp.Backend.Controllers.Mastodon.Renderers.NoteRenderer; +using UserRenderer = Iceshrimp.Backend.Controllers.Mastodon.Renderers.UserRenderer; + +namespace Iceshrimp.Backend.Controllers.Pleroma; + +[MastodonApiController] +[Authenticate] +[EnableCors("mastodon")] +[EnableRateLimiting("sliding")] +[Produces(MediaTypeNames.Application.Json)] +public class AdminController( + DatabaseContext db, + ReportRenderer reportRenderer, + NoteRenderer noteRenderer, + UserRenderer userRenderer +) : ControllerBase +{ + [HttpGet("/api/v1/pleroma/admin/reports")] + [Authenticate("admin:read:reports")] + [ProducesResults(HttpStatusCode.OK)] + public async Task GetReports() + { + var user = HttpContext.GetUserOrFail(); + var reports = await db.Reports + .IncludeCommonProperties() + .ToListAsync(); + + var rendered = await reportRenderer.RenderManyAsync(reports); + + var reportsList = new List(); + foreach (var r in rendered) + { + var reActor = await db.Users + .IncludeCommonProperties() + .Where(p => p.Id == r.Reporter.Id) + .RenderAllForMastodonAsync(userRenderer, user); + + var reTarget = await db.Users + .IncludeCommonProperties() + .Where(p => p.Id == r.TargetUser.Id) + .RenderAllForMastodonAsync(userRenderer, user); + + foreach (var n in r.Notes) + { + var note = await db.Notes + .IncludeCommonProperties() + .Where(p => p.Id == n.Id) + .RenderAllForMastodonAsync(noteRenderer, user); + + reportsList.Add(new Reports() + { + Account = reTarget.FirstOrDefault()!, + Actor = reActor.FirstOrDefault()!, + Id = r.Id, + CreatedAt = r.CreatedAt, + State = r.Resolved ? "resolved" : "open", + Content = r.Comment, + Statuses = note, + Notes = [] // unsupported + }); + } + + } + + var resps = new ReportsQuery() + { + Total = reportsList.Count, + Reports = reportsList + }; + + return resps; + } + + [HttpPatch("/api/v1/pleroma/admin/reports")] + [Authenticate("admin:read:reports")] + [ProducesResults(HttpStatusCode.OK)] + [ProducesErrors(HttpStatusCode.NotFound)] + // ReSharper disable once AsyncVoidMethod + public async Task? SetReportState(ReportsQuery query) + { + foreach (var list in query.Reports) + { + var report = await db.Reports.Where(p => p.Id == list.Id).FirstOrDefaultAsync() + ?? throw GracefulException.NotFound("Report not found"); + + report.Resolved = list.State is "resolved" or "closed"; + + await db.SaveChangesAsync(); + } + + return query; + } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaInstanceEntity.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaInstanceEntity.cs new file mode 100644 index 00000000..97b6d254 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaInstanceEntity.cs @@ -0,0 +1,9 @@ +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +public class AkkomaInstanceEntity +{ + [J("name")] public required string Name { get; set; } + [J("nodeinfo")] public required AkkomaNodeInfoEntity NodeInfo { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoEntity.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoEntity.cs new file mode 100644 index 00000000..d712dab5 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoEntity.cs @@ -0,0 +1,8 @@ +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +public class AkkomaNodeInfoEntity +{ + [J("software")] public required AkkomaNodeInfoSoftwareEntity Software { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoSoftwareEntity.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoSoftwareEntity.cs new file mode 100644 index 00000000..ccccbe5d --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaNodeInfoSoftwareEntity.cs @@ -0,0 +1,9 @@ +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +public class AkkomaNodeInfoSoftwareEntity +{ + [J("name")] public required string? Name { get; set; } + [J("version")] public required string? Version { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaUserExtensions.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaUserExtensions.cs new file mode 100644 index 00000000..d2cd6891 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/AkkomaUserExtensions.cs @@ -0,0 +1,10 @@ +using Microsoft.EntityFrameworkCore; +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +[Keyless] +public class AkkomaUserExtensions +{ + [J("instance")] public required AkkomaInstanceEntity Instance { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaOauthTokenEntity.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaOauthTokenEntity.cs new file mode 100644 index 00000000..59861b07 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaOauthTokenEntity.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices.JavaScript; +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +public class PleromaOauthTokenEntity +{ + [J("id")] public required string Id { get; set; } + [J("valid_until")] public required DateTime ValidUntil { get; set; } + [J("app_name")] public required string? AppName { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaUserExtensions.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaUserExtensions.cs new file mode 100644 index 00000000..3f817d51 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/Entities/PleromaUserExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas.Entities; + +[Keyless] +public class PleromaUserExtensions +{ + [J("is_admin")] public required bool IsAdmin { get; set; } + [J("is_moderator")] public required bool IsModerator { get; set; } + [J("favicon")] public required string Favicon { get; set; } +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Pleroma/Schemas/ReportsResponse.cs b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/ReportsResponse.cs new file mode 100644 index 00000000..3ac9538c --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Pleroma/Schemas/ReportsResponse.cs @@ -0,0 +1,22 @@ +using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Pleroma.Schemas; + +public class ReportsQuery +{ + [J("total")] public int Total { get; set; } + [J("reports")] public required List Reports { get; set; } +} + +public class Reports +{ + [J("account")] public AccountEntity? Account { get; set; } + [J("actor")] public AccountEntity? Actor { get; set; } + [J("id")] public required string Id { get; set; } + [J("created_at")] public DateTime? CreatedAt { get; set; } + [J("state")] public required string State { get; set; } + [J("content")] public string? Content { get; set; } + [J("statuses")] public IEnumerable? Statuses { get; set; } + [J("notes")] public string[]? Notes { get; set; } +} \ No newline at end of file