diff --git a/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs b/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs index 2bd2b2d..c5472b3 100644 --- a/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs +++ b/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs @@ -229,6 +229,7 @@ public class ReportsController( .Reports.Include(r => r.Reporter) .Include(r => r.TargetUser) .Include(r => r.TargetMember) + .Include(r => r.AuditLogEntry) .FirstOrDefaultAsync(r => r.Id == id, ct); if (report == null) throw new ApiError.NotFound("No report with that ID found."); @@ -243,6 +244,9 @@ public class ReportsController( ), Member: report.TargetMember != null ? memberRenderer.RenderMember(report.TargetMember) + : null, + AuditLogEntry: report.AuditLogEntry != null + ? moderationRenderer.RenderAuditLogEntry(report.AuditLogEntry) : null ) ); diff --git a/Foxnouns.Backend/Dto/Moderation.cs b/Foxnouns.Backend/Dto/Moderation.cs index 3792e31..26fd0aa 100644 --- a/Foxnouns.Backend/Dto/Moderation.cs +++ b/Foxnouns.Backend/Dto/Moderation.cs @@ -39,7 +39,9 @@ public record ReportResponse( public record ReportDetailResponse( ReportResponse Report, UserResponse User, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] MemberResponse? Member + [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] MemberResponse? Member, + [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + AuditLogResponse? AuditLogEntry ); public record AuditLogResponse( diff --git a/Foxnouns.Frontend/src/lib/api/models/moderation.ts b/Foxnouns.Frontend/src/lib/api/models/moderation.ts index edd0865..eee9382 100644 --- a/Foxnouns.Frontend/src/lib/api/models/moderation.ts +++ b/Foxnouns.Frontend/src/lib/api/models/moderation.ts @@ -75,6 +75,7 @@ export type ReportDetails = { report: Report; user: User; member?: Member; + audit_log_entry?: AuditLogEntry; }; export type QueriedUser = { diff --git a/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte b/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte new file mode 100644 index 0000000..7f7f3b0 --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte @@ -0,0 +1,37 @@ + + +
+

+ Closed by at + {idTimestamp(entry.id).toLocaleString(DateTime.DATETIME_MED)} +

+

+ {#if entry.type === AuditLogEntryType.IgnoreReport} + Report was ignored + {:else if entry.type === AuditLogEntryType.WarnUser || entry.type === AuditLogEntryType.WarnUserAndClearProfile} + User was warned + {#if entry.cleared_fields && entry.cleared_fields.length > 0} +
Cleared fields: {entry.cleared_fields.join(", ")} + {/if} + {:else if entry.type === AuditLogEntryType.SuspendUser} + User was suspended + {/if} +

+

Reason

+

+ {#if entry.reason} + {@html renderMarkdown(entry.reason)} + {:else} + (no reason given) + {/if} +

+
diff --git a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts index a9a2d44..214049a 100644 --- a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts @@ -7,7 +7,12 @@ export const load = async ({ params, fetch, cookies }) => { fetch, cookies, }); - return { report: resp.report, user: resp.user, member: resp.member }; + return { + report: resp.report, + user: resp.user, + member: resp.member, + auditLogEntry: resp.audit_log_entry, + }; }; export const actions = createModactions(); diff --git a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte index 17bff1d..2e953d5 100644 --- a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte +++ b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte @@ -2,6 +2,7 @@ import type { Member } from "$api/models/member"; import type { User } from "$api/models/user"; import ActionForm from "$components/admin/ActionForm.svelte"; + import ClosedReportAuditLog from "$components/admin/ClosedReportAuditLog.svelte"; import PartialProfileCard from "$components/admin/PartialProfileCard.svelte"; import ProfileHeader from "$components/profile/ProfileHeader.svelte"; import MemberCard from "$components/profile/user/MemberCard.svelte"; @@ -10,13 +11,21 @@ type Props = { data: PageData; form: ActionData }; let { data, form }: Props = $props(); - let { report, user, member } = $derived(data); + let { report, user, auditLogEntry } = $derived(data); Report on @{user.username} • pronouns.cc +{#if report.status === "CLOSED"} +
+ This report has already been handled. See audit log entry +
+{/if} +

Target user

@@ -55,15 +64,26 @@
-
-

Take action

- -
+{#if report.status === "OPEN"} +
+

Take action

+ +
+{:else if report.status === "CLOSED" && auditLogEntry} + +{:else} +
+

Closed by an unknown moderator

+

+ This should not happen! +

+
+{/if} {#if report.snapshot}

Profile at time of report