mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 23:18:56 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RadicadeServer.Admin;
|
||||
using RadicadeServer.Radicade.Discord;
|
||||
using RadicadeServer.DB;
|
||||
using RadicadeServer.Extensions;
|
||||
using RadicadeServer.RecNet.Enums.Moderation;
|
||||
using RadicadeServer.RecNet.Moderation;
|
||||
using RadicadeServer.Discord.Webhooks;
|
||||
|
||||
namespace RadicadeServer.API.Moderation;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class ContentReportAPI : Controller
|
||||
{
|
||||
private readonly RecDBContext db;
|
||||
|
||||
public ContentReportAPI(RecDBContext dbContext) {
|
||||
db = dbContext;
|
||||
}
|
||||
|
||||
[HttpPost("api/inventions/v1/report"), Authorize]
|
||||
[HttpPost("api/inventions/v2/report"), Authorize]
|
||||
public Task<IActionResult> ReportInvention() => HandleReport("Invention",
|
||||
new[] { "InventionId", "inventionId", "Id", "id", "TargetId", "targetId", "ReporteeId", "reporteeId" },
|
||||
async targetId =>
|
||||
{
|
||||
var invention = await db.Inventions.AsNoTracking().FirstOrDefaultAsync(x => x.InventionId == targetId);
|
||||
return invention == null ? null : (OwnerId: invention.CreatorPlayerId, TargetName: invention.Name);
|
||||
});
|
||||
|
||||
[HttpPost("api/rooms/v1/report"), Authorize]
|
||||
[HttpPost("api/rooms/v2/report"), Authorize]
|
||||
public Task<IActionResult> ReportRoom() => HandleReport("Room",
|
||||
new[] { "RoomId", "roomId", "Id", "id", "TargetId", "targetId", "ReporteeId", "reporteeId" },
|
||||
async targetId =>
|
||||
{
|
||||
var room = await db.Rooms.AsNoTracking().FirstOrDefaultAsync(x => x.RoomId == targetId);
|
||||
return room == null ? null : (OwnerId: room.CreatorAccountId, TargetName: room.Name);
|
||||
});
|
||||
|
||||
[HttpPost("api/clubs/v1/report"), Authorize]
|
||||
[HttpPost("api/clubs/v2/report"), Authorize]
|
||||
[HttpPost("api/clubreporting/v1/report"), Authorize]
|
||||
public Task<IActionResult> ReportClub() => HandleReport("Club",
|
||||
new[] { "ClubId", "clubId", "Id", "id", "TargetId", "targetId", "ReporteeId", "reporteeId" },
|
||||
_ => Task.FromResult<(long OwnerId, string TargetName)?>(null));
|
||||
|
||||
[HttpPost("api/board/v1/report"), Authorize]
|
||||
[HttpPost("api/board/v2/report"), Authorize]
|
||||
[HttpPost("api/communityboard/v1/report"), Authorize]
|
||||
[HttpPost("api/communityboard/v2/report"), Authorize]
|
||||
public Task<IActionResult> ReportBoard() => HandleReport("Board",
|
||||
new[] { "BoardId", "boardId", "PostId", "postId", "CommentId", "commentId", "Id", "id", "TargetId", "targetId" },
|
||||
_ => Task.FromResult<(long OwnerId, string TargetName)?>(null));
|
||||
|
||||
[HttpPost("api/playerevents/v2/report"), Authorize]
|
||||
[HttpPost("api/events/v1/report"), Authorize]
|
||||
[HttpPost("api/events/v2/report"), Authorize]
|
||||
public Task<IActionResult> ReportEvent() => HandleReport("Event",
|
||||
new[] { "EventId", "eventId", "PlayerEventId", "playerEventId", "Id", "id", "TargetId", "targetId", "ReporteeId", "reporteeId" },
|
||||
async targetId =>
|
||||
{
|
||||
var ev = await db.PlayerEvents.AsNoTracking().FirstOrDefaultAsync(x => x.PlayerEventId == targetId);
|
||||
return ev == null ? null : (OwnerId: ev.CreatorPlayerId, TargetName: ev.Name);
|
||||
});
|
||||
|
||||
private async Task<IActionResult> HandleReport(
|
||||
string reportType,
|
||||
string[] idFieldNames,
|
||||
Func<long, Task<(long OwnerId, string TargetName)?>> resolveTarget)
|
||||
{
|
||||
var reporterId = User.GetUserId();
|
||||
if (reporterId == null) return Unauthorized();
|
||||
|
||||
var fields = await ReadFieldsAsync();
|
||||
|
||||
var targetId = GetLong(fields, idFieldNames);
|
||||
|
||||
long reportedId = 0;
|
||||
string targetName = "";
|
||||
if (targetId.HasValue)
|
||||
{
|
||||
var resolved = await resolveTarget(targetId.Value);
|
||||
if (resolved.HasValue)
|
||||
{
|
||||
reportedId = resolved.Value.OwnerId;
|
||||
targetName = resolved.Value.TargetName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
targetName = $"{reportType} {targetId.Value}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return await SubmitReport(reportType, targetId, targetName, reportedId, reporterId.Value, fields);
|
||||
}
|
||||
|
||||
[HttpPost("api/customAvatarItems/v1/{customAvatarItemId:guid}/report"), Authorize]
|
||||
public async Task<IActionResult> ReportCustomAvatarItem(Guid customAvatarItemId)
|
||||
{
|
||||
var reporterId = User.GetUserId();
|
||||
if (reporterId == null) return Unauthorized();
|
||||
|
||||
var fields = await ReadFieldsAsync();
|
||||
|
||||
var item = await db.CustomAvatarItems.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.CustomAvatarItemId == customAvatarItemId);
|
||||
|
||||
return await SubmitReport(
|
||||
"CustomAvatarItem",
|
||||
null,
|
||||
item?.Name ?? $"Custom Avatar Item {customAvatarItemId}",
|
||||
item?.CreatorAccountId ?? 0,
|
||||
reporterId.Value,
|
||||
fields);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> SubmitReport(
|
||||
string reportType,
|
||||
long? targetId,
|
||||
string targetName,
|
||||
long reportedId,
|
||||
long reporterId,
|
||||
Dictionary<string, string> fields)
|
||||
{
|
||||
var reason = GetField(fields, "Reason", "reason", "ReportReason", "reportReason") ?? "";
|
||||
var details = GetField(fields, "Details", "details", "Description", "description", "Message", "message", "Text", "text") ?? "";
|
||||
var category = ParseCategory(fields);
|
||||
var roomId = GetLong(fields, "RoomId", "roomId") ?? 0;
|
||||
|
||||
if (reportedId > 0 && reportedId != reporterId)
|
||||
{
|
||||
var reputation = await db.Reputations.FirstOrDefaultAsync(x => x.AccountId == reportedId);
|
||||
if (reputation == null)
|
||||
{
|
||||
reputation = new Reputation { AccountId = reportedId };
|
||||
await db.Reputations.AddAsync(reputation);
|
||||
}
|
||||
reputation.ReportCount += 1;
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
AdminPanelAPI.AddModerationReport(reporterId, reportedId, reason, details, category, roomId,
|
||||
reportType, targetId, targetName);
|
||||
|
||||
ReportDiscord.SendAsync(WebhookConfig.ReportsUrl, $"🚩 {reportType} Report",
|
||||
new DiscordPayload
|
||||
{
|
||||
Title = $"{reportType} Report",
|
||||
ThumbnailUrl = WebhookImages.ForReport(reportType) ?? "",
|
||||
Color = 0xF0B232,
|
||||
Fields = new List<DiscordField>
|
||||
{
|
||||
new() { Name = "Report Type", Value = reportType, Inline = true },
|
||||
new() { Name = "Reporter", Value = reporterId.ToString(), Inline = true },
|
||||
new() { Name = "Reported Player", Value = reportedId > 0 ? reportedId.ToString() : "Unknown", Inline = true },
|
||||
new() { Name = "Target", Value = targetId.HasValue ? $"{targetName} ({targetId})" : targetName, Inline = true },
|
||||
new() { Name = "Category", Value = category.ToString(), Inline = true },
|
||||
new() { Name = "Room", Value = roomId.ToString(), Inline = true },
|
||||
new() { Name = "Reason", Value = reason, Inline = false },
|
||||
new() { Name = "Details", Value = details, Inline = false }
|
||||
},
|
||||
TimestampUtc = DateTime.UtcNow.ToString("O")
|
||||
});
|
||||
|
||||
return Ok(new OkResponse { Success = true });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task<Dictionary<string, string>> ReadFieldsAsync()
|
||||
{
|
||||
var fields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var kv in Request.Query)
|
||||
fields[kv.Key] = kv.Value.ToString();
|
||||
|
||||
if (Request.HasFormContentType)
|
||||
{
|
||||
var form = await Request.ReadFormAsync();
|
||||
foreach (var kv in form)
|
||||
fields[kv.Key] = kv.Value.ToString();
|
||||
return fields;
|
||||
}
|
||||
|
||||
if (Request.ContentLength is not > 0) return fields;
|
||||
|
||||
try
|
||||
{
|
||||
using var reader = new StreamReader(Request.Body);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
if (string.IsNullOrWhiteSpace(body)) return fields;
|
||||
|
||||
var trimmed = body.TrimStart();
|
||||
if (trimmed.StartsWith("{", StringComparison.Ordinal))
|
||||
{
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
if (doc.RootElement.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
foreach (var prop in doc.RootElement.EnumerateObject())
|
||||
{
|
||||
fields[prop.Name] = prop.Value.ValueKind == JsonValueKind.String
|
||||
? prop.Value.GetString() ?? ""
|
||||
: prop.Value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (trimmed.Contains('='))
|
||||
{
|
||||
|
||||
foreach (var pair in body.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var eq = pair.IndexOf('=');
|
||||
if (eq < 0)
|
||||
{
|
||||
fields[Uri.UnescapeDataString(pair)] = "";
|
||||
continue;
|
||||
}
|
||||
var key = Uri.UnescapeDataString(pair.Substring(0, eq));
|
||||
var value = Uri.UnescapeDataString(pair.Substring(eq + 1));
|
||||
fields[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static string? GetField(Dictionary<string, string> fields, params string[] names)
|
||||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
if (fields.TryGetValue(name, out var value) && !string.IsNullOrWhiteSpace(value))
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static long? GetLong(Dictionary<string, string> fields, params string[] names)
|
||||
{
|
||||
var raw = GetField(fields, names);
|
||||
if (raw == null) return null;
|
||||
if (long.TryParse(raw, out var value)) return value;
|
||||
|
||||
|
||||
var digits = new string(raw.Where(char.IsDigit).ToArray());
|
||||
return long.TryParse(digits, out value) ? value : null;
|
||||
}
|
||||
|
||||
private static ReportCategory ParseCategory(Dictionary<string, string> fields)
|
||||
{
|
||||
var raw = GetField(fields, "ReportCategory", "reportCategory", "Category", "category", "Reason", "reason", "ReportReason", "reportReason");
|
||||
if (raw == null) return ReportCategory.Misc;
|
||||
|
||||
if (int.TryParse(raw, out var intValue) && Enum.IsDefined(typeof(ReportCategory), intValue))
|
||||
return (ReportCategory)intValue;
|
||||
|
||||
if (Enum.TryParse<ReportCategory>(raw, ignoreCase: true, out var parsed))
|
||||
return parsed;
|
||||
|
||||
return ReportCategory.Misc;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user