allow deleting aliases

This commit is contained in:
Lea 2024-01-17 23:27:37 +01:00
parent e10dbc9a62
commit f7eb59e89e
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
3 changed files with 81 additions and 4 deletions

View file

@ -1,12 +1,12 @@
"use client"; "use client";
import { aliasAvailable, changeOwnPassword, createAliasSelf, fetchOwnAliases } from "@/lib/actions"; import { aliasAvailable, changeOwnPassword, createAliasSelf, deleteAlias, fetchOwnAliases } from "@/lib/actions";
import GhostMessage from "@/lib/components/ui/GhostMessage"; import GhostMessage from "@/lib/components/ui/GhostMessage";
import LoadingSpinner from "@/lib/components/ui/LoadingSpinner"; import LoadingSpinner from "@/lib/components/ui/LoadingSpinner";
import { AliasEntry } from "@/lib/db"; import { AliasEntry } from "@/lib/db";
import useWindowDimensions from "@/lib/hooks/useWindowDimensions"; import useWindowDimensions from "@/lib/hooks/useWindowDimensions";
import { aliasesNeedApproval } from "@/lib/util"; import { aliasesNeedApproval } from "@/lib/util";
import { Card, Text, Heading, Flex, TextField, Button, IconButton, Popover, Link, Tabs, Box, Grid, Dialog, Callout, Tooltip, Table, ScrollArea, DropdownMenu } from "@radix-ui/themes"; import { Card, Text, Heading, Flex, TextField, Button, IconButton, Popover, Link, Tabs, Box, Grid, Dialog, Callout, Tooltip, Table, ScrollArea, DropdownMenu, Code } from "@radix-ui/themes";
import { AlertCircleIcon, CheckIcon, ChevronDownIcon, CopyIcon, ExternalLinkIcon, InfoIcon, LockIcon, UserIcon, UsersRound } from "lucide-react"; import { AlertCircleIcon, CheckIcon, ChevronDownIcon, CopyIcon, ExternalLinkIcon, InfoIcon, LockIcon, UserIcon, UsersRound } from "lucide-react";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@ -303,6 +303,7 @@ export default function SelfService() {
const alias = await createAliasSelf(`${newAliasUsername}@${newAliasDomain}`); const alias = await createAliasSelf(`${newAliasUsername}@${newAliasDomain}`);
setAliases([...(aliases ?? []), alias]); setAliases([...(aliases ?? []), alias]);
} catch(e) { } catch(e) {
console.error(e);
alert(e); alert(e);
} }
}}>Change</Button> }}>Change</Button>
@ -332,7 +333,41 @@ export default function SelfService() {
<Table.Cell justify='start'>{alias.alias}</Table.Cell> <Table.Cell justify='start'>{alias.alias}</Table.Cell>
<Table.Cell justify='end'>{alias.pending ? "Pending" : "Active"}</Table.Cell> <Table.Cell justify='end'>{alias.pending ? "Pending" : "Active"}</Table.Cell>
<Table.Cell justify='end'> <Table.Cell justify='end'>
<Button variant="solid" size="1" mr="2">Delete</Button> <Dialog.Root>
<Dialog.Trigger>
<Button variant="solid" size="1" mr="2">Delete</Button>
</Dialog.Trigger>
<Dialog.Content>
<Dialog.Title>Delete alias</Dialog.Title>
<Dialog.Description>
Are you sure you want to delete the alias <Code>{alias.alias}</Code>?
It will become available for other users to claim immediately.
</Dialog.Description>
<Flex gap="3" mt="4" justify="end">
<Dialog.Close>
<Button variant="outline">Cancel</Button>
</Dialog.Close>
<Dialog.Close>
<Button
variant="solid"
onClick={async () => {
try {
await deleteAlias(alias.alias);
setAliases(aliases.filter((a) => a.id != alias.id));
} catch(e) {
console.error(e);
alert(e);
}
}}
>
Delete
</Button>
</Dialog.Close>
</Flex>
</Dialog.Content>
</Dialog.Root>
</Table.Cell> </Table.Cell>
</Table.Row>)) </Table.Row>))
} }

View file

@ -1,7 +1,7 @@
"use server"; "use server";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { AliasEntry, createAlias, database, getUserAliases, setUserPassword } from "./db"; import { AliasEntry, createAlias, database, deleteAliasEntry, getAlias, getUserAliases, setUserPassword } from "./db";
import { aliasesNeedApproval, isAdmin } from "./util"; import { aliasesNeedApproval, isAdmin } from "./util";
export async function fetchAllUsers(): Promise<string[]> { export async function fetchAllUsers(): Promise<string[]> {
@ -66,3 +66,14 @@ export async function createAliasSelf(alias: string): Promise<AliasEntry> {
pending: pending pending: pending
}; };
} }
export async function deleteAlias(alias: string) {
const session = await getServerSession();
if (!session?.user?.email) throw new Error("Unauthenticated");
if (!isAdmin(session) && (await getAlias(alias))?.address != session.user.email) {
throw new Error("Unauthorized");
}
await deleteAliasEntry(alias);
}

View file

@ -77,6 +77,22 @@ export function getUserAliases(email: string) {
}); });
} }
export function getAlias(alias: string) {
return new Promise<AliasEntry | undefined>(async (resolve, reject) => {
const db = database('aliases');
db.get("SELECT id, address, alias, pending FROM aliases WHERE address = ?", alias, (err, res: AliasEntry) => {
db.close();
if (err) return reject(err);
if (!res) return resolve(undefined);
resolve({
...res,
pending: !!res.pending,
});
});
});
}
export function createAlias(user: string, alias: string, pending: boolean) { export function createAlias(user: string, alias: string, pending: boolean) {
return new Promise<number>(async (resolve, reject) => { return new Promise<number>(async (resolve, reject) => {
const db = database('aliases'); const db = database('aliases');
@ -95,3 +111,18 @@ export function createAlias(user: string, alias: string, pending: boolean) {
}); });
}); });
} }
export function deleteAliasEntry(alias: string) {
return new Promise<void>(async (resolve, reject) => {
const db = database('aliases');
db.run(
"DELETE FROM aliases WHERE alias = ?",
alias,
function(err: any) {
db.close();
if (err) return reject(err);
resolve();
});
});
}