diff --git a/app/panel/inspect/page.tsx b/app/panel/inspect/page.tsx index c51266b..f73b17a 100644 --- a/app/panel/inspect/page.tsx +++ b/app/panel/inspect/page.tsx @@ -3,7 +3,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { toast } from "@/components/ui/use-toast"; -import { lookupEmail } from "@/lib/actions"; +import { lookupEmail, searchUserByTag } from "@/lib/actions"; import { API_URL } from "@/lib/constants"; import { useRouter } from "next/navigation"; import { useState } from "react"; @@ -11,6 +11,8 @@ import { useState } from "react"; export default function Inspect() { const [id, setId] = useState(""); const [email, setEmail] = useState(""); + const [username, setUsername] = useState(""); + const [discriminator, setDiscriminator] = useState(""); const router = useRouter(); const searchEmail = async () => { @@ -31,6 +33,29 @@ export default function Inspect() { } }; + const searchUsername = async () => { + try { + if (!discriminator) { + // Display all users with this username + router.push(`/panel/inspect/search?username=${encodeURIComponent(username)}`); + } else { + // Show the specific user that matches username#discriminator + const result = await searchUserByTag(username, discriminator); + if (!result) toast({ + title: "Couldn't find user", + variant: "destructive", + }); + else router.push(`/panel/inspect/user/${result}`); + } + } catch(e) { + toast({ + title: "Failed to search", + description: String(e), + variant: "destructive", + }) + } + }; + const createHandler = (type: string) => () => router.push(`/panel/inspect/${type}/${id}`); @@ -41,7 +66,7 @@ export default function Inspect() { value={id} onChange={(e) => setId(e.currentTarget.value)} /> -
+

-
- setEmail(e.currentTarget.value)} - onKeyDown={(e) => e.key == "Enter" && email && searchEmail()} - /> - +
+
+ setEmail(e.currentTarget.value)} + onKeyDown={(e) => e.key == "Enter" && email && searchEmail()} + /> +
+
+
+ setUsername(e.currentTarget.value)} + onKeyDown={(e) => e.key == "Enter" && username && searchUsername()} + /> + # + setDiscriminator(e.currentTarget.value)} + onKeyDown={(e) => e.key == "Enter" && username && searchUsername()} + className="flex-shrink-[2]" + /> +
+ +
+
); } diff --git a/app/panel/inspect/search/page.tsx b/app/panel/inspect/search/page.tsx new file mode 100644 index 0000000..6b032cf --- /dev/null +++ b/app/panel/inspect/search/page.tsx @@ -0,0 +1,34 @@ +import { UserCard } from "@/components/cards/UserCard"; +import { fetchUsersByUsername } from "@/lib/actions"; +import { SearchX } from "lucide-react"; +import { redirect } from "next/navigation"; + +export default async function Search({ searchParams }: { searchParams: any }) { + const username = searchParams.username; + + if (!username) return redirect("/panel/inspect"); + const users = await fetchUsersByUsername(username); + + if (!users.length) return ( + <> +

+ +

+

+ No search results +

+ + ); + + return ( +
+ { + users.map((user) => ( + + + + )) + } +
+ ); +} diff --git a/lib/accessPermissions.ts b/lib/accessPermissions.ts index 59f4196..aa5f108 100644 --- a/lib/accessPermissions.ts +++ b/lib/accessPermissions.ts @@ -62,6 +62,8 @@ type Permission = | `/fetch${ | "" | "/by-id" + | "/by-tag" + | "/bulk-by-username" | "/memberships" | "/strikes" | "/notices" @@ -163,6 +165,8 @@ const PermissionSets = { // Moderate users "moderate-users": [ "users/fetch/by-id", + "users/fetch/by-tag", + "users/fetch/bulk-by-username", "users/fetch/strikes", "users/fetch/notices", diff --git a/lib/actions.ts b/lib/actions.ts index 210bf27..9c33b69 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -1027,3 +1027,29 @@ export async function deleteEmailClassification(domain: string) { { _id: domain }, ); } + +export async function searchUserByTag(username: string, discriminator: string): Promise { + await checkPermission("users/fetch/by-tag", { username, discriminator }); + + const result = await mongo() + .db("revolt") + .collection("users") + .findOne({ + username, + discriminator, + }); + + return result?._id || false; +} + +export async function fetchUsersByUsername(username: string) { + await checkPermission("users/fetch/bulk-by-username", { username }); + + return await mongo() + .db("revolt") + .collection("users") + .find({ + username, + }) + .toArray(); +}