From 24f4357775d67d05e9e4b55727837ea1aea3a945 Mon Sep 17 00:00:00 2001 From: Lea Date: Thu, 10 Aug 2023 22:44:05 +0200 Subject: [PATCH] feat: allow invite editing and deleting --- components/cards/InviteCard.tsx | 99 ++++++++++++++++++++++- components/pages/inspector/InviteList.tsx | 3 +- lib/accessPermissions.ts | 5 +- lib/actions.ts | 28 +++++++ 4 files changed, 129 insertions(+), 6 deletions(-) diff --git a/components/cards/InviteCard.tsx b/components/cards/InviteCard.tsx index d4b38ac..ee2a7f4 100644 --- a/components/cards/InviteCard.tsx +++ b/components/cards/InviteCard.tsx @@ -1,9 +1,15 @@ "use client" -import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { ChannelInvite } from "@/lib/db"; import Link from "next/link"; import { Channel, User } from "revolt-api"; +import { Button } from "../ui/button"; +import { AlertDialogFooter, AlertDialogHeader, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger } from "../ui/alert-dialog"; +import { toast } from "../ui/use-toast"; +import { Input } from "../ui/input"; +import { useState } from "react"; +import { deleteInvite, editInvite } from "@/lib/actions"; export function InviteCard({ invite, @@ -14,11 +20,17 @@ export function InviteCard({ channel?: Channel; user?: User; }) { + const [editDraft, setEditDraft] = useState(""); + const [deleted, setDeleted] = useState(false); + const [code, setCode] = useState(invite._id); + + if (deleted) return <>; + return ( - - + + - rvlt.gg/{invite._id} + rvlt.gg/{code} {" "} {/* looks better like this when for some reason the css doesnt load */} {invite.vanity ? + + {invite.vanity + ? ( + + + + + + + + Edit vanity invite + + + +

Invites are case sensitive.

+ setEditDraft(e.currentTarget.value)} + placeholder={code} + /> +
+ + { + try { + await editInvite(code, editDraft); + setCode(editDraft); + setEditDraft(""); + toast({ title: "Invite edited" }); + } catch(e) { + toast({ + title: "Failed to edit invite", + description: String(e), + variant: "destructive", + }); + } + }} + >Edit + Cancel + +
+
+ ) + : <>} + + + + + + + + Delete invite + + + + Are you sure you want to irreversibly delete this invite? + + + { + try { + await deleteInvite(code); + setDeleted(true); + toast({ title: "Invite deleted" }); + } catch(e) { + toast({ + title: "Failed to delete invite", + description: String(e), + variant: "destructive", + }); + } + }} + >Delete + Cancel + + + +
); } diff --git a/components/pages/inspector/InviteList.tsx b/components/pages/inspector/InviteList.tsx index 80d57de..3dd9087 100644 --- a/components/pages/inspector/InviteList.tsx +++ b/components/pages/inspector/InviteList.tsx @@ -27,7 +27,8 @@ export default function ServerInviteList({ server, invites, channels, users }: { return invites ?.filter(invite => vanityOnly ? invite.vanity : true) ?.filter(invite => channelFilter ? invite.channel == channelFilter : true) - ?.filter(invite => userFilter ? invite.creator == userFilter : true); + ?.filter(invite => userFilter ? invite.creator == userFilter : true) + ?.reverse(); }, [vanityOnly, channelFilter, userFilter, invites]); return ( diff --git a/lib/accessPermissions.ts b/lib/accessPermissions.ts index be8e432..5703b43 100644 --- a/lib/accessPermissions.ts +++ b/lib/accessPermissions.ts @@ -16,7 +16,7 @@ type Permission = | "" | `/fetch${"" | "/by-id" | "/by-user"}` | `/update${"" | "/discoverability"}`}` - | `channels${"" | `/fetch${"" | "/by-id" | "/by-server" | "/dm" | "/invites"}` | `/create${"" | "/dm"}`}` + | `channels${"" | `/fetch${"" | "/by-id" | "/by-server" | "/dm" | "/invites"}` | `/create${"" | "/dm" | "/invites"}` | `/update${"" | "/invites"}`}` | `messages${"" | `/fetch${"" | "/by-id" | "/by-user"}`}` | `reports${ | "" @@ -109,6 +109,9 @@ const PermissionSets = { "accounts/deletion/cancel", "accounts/update/email", "accounts/update/mfa", + + "channels/update/invites", + "channels/fetch/invites", ] as Permission[], // Moderate users diff --git a/lib/actions.ts b/lib/actions.ts index f55318e..d2c41fd 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -4,6 +4,7 @@ import { writeFile } from "fs/promises"; import { PLATFORM_MOD_ID, RESTRICT_ACCESS_LIST } from "./constants"; import mongo, { Account, + ChannelInvite, createDM, fetchAccountById, fetchChannels, @@ -587,6 +588,33 @@ export async function updateServerDiscoverability( ); } +export async function deleteInvite(invite: string) { + await checkPermission("channels/update/invites", invite); + + await mongo() + .db("revolt") + .collection("channel_invites") + .deleteOne({ _id: invite }); +} + +export async function editInvite(invite: string, newInvite: string) { + await checkPermission("channels/update/invites", { invite, newInvite }); + + if (!newInvite) throw new Error("invite is empty"); + + const { value } = await mongo() + .db("revolt") + .collection("channel_invites") + .findOneAndDelete({ _id: invite }); + + if (!value) throw new Error("invite doesn't exist"); + + await mongo() + .db("revolt") + .collection("channel_invites") + .insertOne({ ...value, _id: newInvite }); +} + export async function updateBotDiscoverability(botId: string, state: boolean) { await checkPermission("bots/update/discoverability", botId, { state }); await mongo()