pending aliases list

This commit is contained in:
Lea 2024-01-17 23:59:15 +01:00
parent dc0cc4b541
commit 54917bfe70
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
4 changed files with 106 additions and 12 deletions

View file

@ -0,0 +1,58 @@
"use client";
import { fetchAllAliases } from "@/lib/actions";
import GhostMessage from "@/lib/components/ui/GhostMessage";
import LoadingSpinner from "@/lib/components/ui/LoadingSpinner";
import { AliasEntry } from "@/lib/db";
import { Button, Card, Flex, Heading, Table } from "@radix-ui/themes";
import { ListChecksIcon } from "lucide-react";
import { useEffect, useState } from "react";
export default function Aliases() {
const [aliases, setAliases] = useState<AliasEntry[] | null>();
const pending = aliases?.filter((alias) => alias.pending);
useEffect(() => {
fetchAllAliases().then(setAliases);
}, []);
return (
<>
<Heading className="pb-4">Aliases</Heading>
<Card>
<Heading size="2" className="pb-2">Pending</Heading>
{pending
? pending.length
? <Table.Root>
<Table.Header>
<Table.Row>
<Table.ColumnHeaderCell justify='start'>User</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell justify='start'>Alias</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell justify='end'>Actions</Table.ColumnHeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{pending.map((alias) => (
<Table.Row key={alias.id}>
<Table.Cell justify='start'>{alias.address}</Table.Cell>
<Table.Cell justify='start'>{alias.alias}</Table.Cell>
<Table.Cell justify='end'>
<Flex gap='3' justify="end">
<Button size="1" variant="outline">Approve</Button>
<Button size="1" variant="solid">Delete</Button>
</Flex>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
: <GhostMessage icon={<ListChecksIcon />} header="All caught up" message="There are no pending alias requests" />
: <GhostMessage icon={<LoadingSpinner />} header="Loading" />
}
</Card>
</>
);
}

View file

@ -1,7 +1,7 @@
"use server";
import { getServerSession } from "next-auth";
import { AliasEntry, createAlias, database, deleteAliasEntry, getAlias, getUserAliases, setUserPassword } from "./db";
import { AliasEntry, createAlias, database, deleteAliasEntry, getAlias, getAllAliases, getUserAliases, setUserPassword } from "./db";
import { aliasesNeedApproval, isAdmin } from "./util";
export async function fetchAllUsers(): Promise<string[]> {
@ -30,6 +30,14 @@ export async function fetchOwnAliases() {
return await getUserAliases(session.user.email);
}
export async function fetchAllAliases() {
const session = await getServerSession();
if (!session?.user?.email) throw new Error("Unauthenticated");
if (!isAdmin(session)) throw new Error("Unauthorized");
return await getAllAliases();
}
export async function aliasAvailable(email: string) {
const session = await getServerSession();
if (!session?.user) throw new Error("Unauthenticated");

View file

@ -1,8 +1,8 @@
"use client";
import { isAdmin } from "@/lib/util";
import { Avatar, Box, Button, Card, Flex, IconButton, Popover, ScrollArea, Text } from "@radix-ui/themes";
import { BookUserIcon, HomeIcon } from "lucide-react";
import { Avatar, Button, Card, Flex, IconButton, Popover, ScrollArea, Text, Tooltip } from "@radix-ui/themes";
import { BookUserIcon, HomeIcon, Users2Icon } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import dayjs from "dayjs";
@ -12,6 +12,7 @@ dayjs.extend(relativeTime);
export default function NavigationPanel({ mobileUi }: { mobileUi?: boolean }) {
const session = useSession();
const tooltipSide = mobileUi ? "bottom" : "right";
return (
<Card className={mobileUi ? "w-full" : "w-fit"}>
@ -58,18 +59,31 @@ export default function NavigationPanel({ mobileUi }: { mobileUi?: boolean }) {
</Popover.Root>
)}
<Link href="/">
<IconButton variant="outline" size='4'>
<HomeIcon />
</IconButton>
</Link>
{isAdmin(session.data) && (
<Link href="/admin/users">
<Tooltip content="Home" side={tooltipSide}>
<Link href="/">
<IconButton variant="outline" size='4'>
<BookUserIcon />
<HomeIcon />
</IconButton>
</Link>
</Tooltip>
{isAdmin(session.data) && (
<>
<Tooltip content="Users" side={tooltipSide}>
<Link href="/admin/users">
<IconButton variant="outline" size='4'>
<BookUserIcon />
</IconButton>
</Link>
</Tooltip>
<Tooltip content="Aliases" side={tooltipSide}>
<Link href="/admin/aliases">
<IconButton variant="outline" size='4'>
<Users2Icon />
</IconButton>
</Link>
</Tooltip>
</>
)}
</Flex>
</ScrollArea>

View file

@ -62,6 +62,20 @@ export function setUserPassword(email: string, newPass: string) {
}
export type AliasEntry = { id: number, address: string, alias: string, pending: boolean };
export function getAllAliases() {
return new Promise<AliasEntry[]>(async (resolve, reject) => {
const db = database('aliases');
db.all("SELECT id, address, alias, pending FROM aliases", (err, res: any[]) => {
db.close();
if (err) return reject(err);
resolve(res.map((data) => ({
...data,
pending: !!data.pending,
})));
});
});
}
export function getUserAliases(email: string) {
return new Promise<AliasEntry[]>(async (resolve, reject) => {
const db = database('aliases');