1
0
Fork 0

feat: create user strikes

fix-1
Paul Makles 2023-07-28 15:42:55 +01:00
parent f005456f0d
commit 006acdb6ac
No known key found for this signature in database
GPG Key ID: 5059F398521BB0F6
4 changed files with 169 additions and 3 deletions

View File

@ -106,7 +106,11 @@ export default async function User({
)} )}
<Separator /> <Separator />
<RelevantModerationNotices strikes={strikes} notices={notices} /> <RelevantModerationNotices
userId={user._id}
strikes={strikes}
notices={notices}
/>
<Separator /> <Separator />
<RelevantObjects <RelevantObjects

View File

@ -3,19 +3,144 @@
import { AccountStrike, Message } from "revolt-api"; import { AccountStrike, Message } from "revolt-api";
import { ListCompactor } from "../common/ListCompactor"; import { ListCompactor } from "../common/ListCompactor";
import { CompactMessage } from "../cards/CompactMessage"; import { CompactMessage } from "../cards/CompactMessage";
import { useRef, useState } from "react";
import { Button } from "../ui/button";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "../ui/alert-dialog";
import { Input } from "../ui/input";
import { createStrike } from "@/lib/actions";
import { useToast } from "../ui/use-toast";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../ui/table";
import dayjs from "dayjs";
import { decodeTime } from "ulid";
/**
*
* @param param0 You have received an account strike, for one or more reasons:
- REASON_HERE
Further violations will result in suspension or a permanent ban depending on severity, please abide by the [Acceptable Usage Policy](https://revolt.chat/aup).
* @returns
*/
export function RelevantModerationNotices({ export function RelevantModerationNotices({
userId,
strikes, strikes,
notices, notices,
}: { }: {
userId: string;
strikes: AccountStrike[]; strikes: AccountStrike[];
notices: Message[]; notices: Message[];
}) { }) {
const { toast } = useToast();
const [strikesDraft, setStrikesDraft] = useState(strikes);
const givenReason = useRef("");
const additionalContext = useRef("");
return ( return (
<div className="flex gap-2"> <div className="flex gap-2">
<div className="flex-1 min-w-0 flex flex-col gap-2"> <div className="flex-1 min-w-0 flex flex-col gap-2">
<h2 className="text-md text-center pb-2">Strikes</h2> <h2 className="text-md text-center pb-2">Strikes</h2>
<ListCompactor data={strikes} Component={({ item }) => null} /> <Table>
<TableHeader>
<TableRow>
<TableHead>Reason</TableHead>
<TableHead>Created</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{strikesDraft.map((strike) => (
<TableRow key={strike._id}>
<TableCell>{strike.reason}</TableCell>
<TableCell>{dayjs(decodeTime(strike._id)).fromNow()}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button className="mx-auto" variant="outline">
Create
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Create Strike</AlertDialogTitle>
</AlertDialogHeader>
<p className="text-sm flex flex-col gap-2">
<span>
You have received an account strike, for one or more reasons:
</span>
<Input
defaultValue=""
placeholder="Short reason"
onChange={(e) => (givenReason.current = e.currentTarget.value)}
/>
<span>
Further violations will result in suspension or a permanent ban
depending on severity, please abide by the{" "}
<a href="https://revolt.chat/aup" target="_blank">
Acceptable Usage Policy
</a>
.
</span>
<Input
defaultValue=""
placeholder="Additional context (only moderators see this)"
onChange={(e) =>
(additionalContext.current = e.currentTarget.value)
}
/>
</p>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={() =>
givenReason.current &&
createStrike(
userId,
givenReason.current,
additionalContext.current
)
.then((strike) => {
setStrikesDraft((strikes) => [strike, ...strikes]);
toast({ title: "Created strike" });
})
.catch((err) =>
toast({
title: "Failed to create strike!",
description: String(err),
variant: "destructive",
})
)
.finally(() => {
givenReason.current = "";
additionalContext.current = "";
})
}
>
Create
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div> </div>
<div className="flex-1 min-w-0 flex flex-col gap-2"> <div className="flex-1 min-w-0 flex flex-col gap-2">
<h2 className="text-md text-center pb-2">Alerts</h2> <h2 className="text-md text-center pb-2">Alerts</h2>

View File

@ -16,6 +16,7 @@ import { publishMessage, sendChatMessage } from "./redis";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { import {
AccountInfo, AccountInfo,
AccountStrike,
Bot, Bot,
File, File,
Member, Member,
@ -41,6 +42,35 @@ export async function sendAlert(userId: string, content: string) {
}); });
} }
export async function createStrike(
userId: string,
givenReason: string,
additionalContext: string
) {
const strike: AccountStrike & { moderator_id: string } = {
_id: ulid(),
user_id: userId,
moderator_id: "01EX2NCWQ0CHS3QJF0FEQS1GR4", // TODO
reason: additionalContext
? givenReason + " - " + additionalContext
: givenReason,
};
await mongo()
.db("revolt")
.collection<{ _id: string }>("safety_strikes")
.insertOne(strike);
await sendAlert(
userId,
`You have received an account strike, for one or more reasons:
- ${givenReason}
Further violations will result in suspension or a permanent ban depending on severity, please abide by the [Acceptable Usage Policy](https://revolt.chat/aup).`
);
return strike;
}
export async function updateReportNotes(reportId: string, notes: string) { export async function updateReportNotes(reportId: string, notes: string) {
return await mongo() return await mongo()
.db("revolt") .db("revolt")

View File

@ -274,7 +274,14 @@ export async function fetchStrikesByUser(userId: string) {
return await mongo() return await mongo()
.db("revolt") .db("revolt")
.collection<AccountStrike>("safety_strikes") .collection<AccountStrike>("safety_strikes")
.find({ user_id: userId }) .find(
{ user_id: userId },
{
sort: {
_id: -1,
},
}
)
.toArray(); .toArray();
} }