From 9f5de75d264ca433c941889c870d8f0bb65d66ea Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Fri, 28 Jul 2023 12:32:06 +0100 Subject: [PATCH] feat: show active sessions on account page --- app/panel/inspect/account/[id]/page.tsx | 54 ++++++++++- components/ui/table.tsx | 114 ++++++++++++++++++++++++ lib/db.ts | 19 ++++ 3 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 components/ui/table.tsx diff --git a/app/panel/inspect/account/[id]/page.tsx b/app/panel/inspect/account/[id]/page.tsx index 3c487c6..732b525 100644 --- a/app/panel/inspect/account/[id]/page.tsx +++ b/app/panel/inspect/account/[id]/page.tsx @@ -1,10 +1,30 @@ +import { JsonCard } from "@/components/cards/JsonCard"; import { UserCard } from "@/components/cards/UserCard"; import { EmailClassificationCard } from "@/components/cards/authifier/EmailClassificationCard"; import { NavigationToolbar } from "@/components/common/NavigationToolbar"; import { AccountActions } from "@/components/inspector/AccountActions"; -import { fetchAccountById, fetchUserById } from "@/lib/db"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { + fetchAccountById, + fetchSessionsByAccount, + fetchUserById, +} from "@/lib/db"; +import dayjs from "dayjs"; import { notFound } from "next/navigation"; import { User } from "revolt-api"; +import { decodeTime } from "ulid"; + +import relativeTime from "dayjs/plugin/relativeTime"; +dayjs.extend(relativeTime); export default async function User({ params, @@ -15,6 +35,7 @@ export default async function User({ if (!account) return notFound(); const user = await fetchUserById(params.id); + const sessions = await fetchSessionsByAccount(params.id); return (
@@ -22,6 +43,37 @@ export default async function User({ {user && } + + + + + Active Sessions + + + + + + Name + Created + + + + {sessions.map((session) => ( + + {session.name} + + {dayjs(decodeTime(session._id)).fromNow()} + + + ))} + +
+
+
+ + + + {/*TODO? update password, reset 2FA, disable / undisable (disabled if pending delete), delete / cancel delete
diff --git a/components/ui/table.tsx b/components/ui/table.tsx new file mode 100644 index 0000000..bb3a87f --- /dev/null +++ b/components/ui/table.tsx @@ -0,0 +1,114 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/lib/db.ts b/lib/db.ts index 6d502fe..ce0e80c 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -8,6 +8,7 @@ import type { Message, Report, Server, + SessionInfo, SnapshotContent, User, } from "revolt-api"; @@ -89,6 +90,24 @@ export async function fetchAccountById(id: string) { ); } +export async function fetchSessionsByAccount(accountId: string) { + return await mongo() + .db("revolt") + .collection("sessions") + .find( + { user_id: accountId }, + { + projection: { + token: 0, + }, + sort: { + _id: -1, + }, + } + ) + .toArray(); +} + export async function fetchUserById(id: string) { return await mongo() .db("revolt")