alias management for users
This commit is contained in:
parent
c9aacdaf6a
commit
21405f9d1d
|
@ -1,7 +1,7 @@
|
|||
"use server";
|
||||
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AliasEntry, approveAliasEntry, createAlias, createUserEntry, database, deleteAliasEntry, getAlias, getAllAliases, getUserAliases, setUserPassword } from "./db";
|
||||
import { AliasEntry, approveAliasEntry, createAliasEntry, createUserEntry, database, deleteAliasEntry, getAlias, getAllAliases, getUserAliases, setUserPassword } from "./db";
|
||||
import { aliasesNeedApproval, isAdmin } from "./util";
|
||||
|
||||
export async function fetchAllUsers(): Promise<string[]> {
|
||||
|
@ -68,13 +68,29 @@ export async function aliasAvailable(email: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function createAlias(user: string, alias: string): Promise<AliasEntry> {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
if (!isAdmin(session)) throw new Error("Unauthenticated");
|
||||
if (!await aliasAvailable(alias)) throw new Error("Alias unavailable");
|
||||
|
||||
const id = await createAliasEntry(user, alias.toLowerCase(), false);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
address: session.user.email,
|
||||
alias: alias,
|
||||
pending: false
|
||||
};
|
||||
}
|
||||
|
||||
export async function createAliasSelf(alias: string): Promise<AliasEntry> {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
|
||||
const pending = aliasesNeedApproval(session);
|
||||
if (!await aliasAvailable(alias)) throw new Error("Alias unavailable");
|
||||
const id = await createAlias(session.user.email, alias.toLowerCase(), pending);
|
||||
const id = await createAliasEntry(session.user.email, alias.toLowerCase(), pending);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
|
|
59
src/lib/components/ui/admin/CreateAliasButton.tsx
Normal file
59
src/lib/components/ui/admin/CreateAliasButton.tsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { createAlias } from "@/lib/actions";
|
||||
import { AliasEntry } from "@/lib/db";
|
||||
import { Button, Callout, Dialog, Flex, TextField } from "@radix-ui/themes";
|
||||
import { AtSignIcon, MailWarningIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function CreateAliasButton({ user, onCreate }: { user: string, onCreate?: (alias: AliasEntry) => any }) {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
return (
|
||||
<Dialog.Root onOpenChange={(open) => !open && setValue("")}>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="1">Add alias</Button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content>
|
||||
<Dialog.Title>Create alias</Dialog.Title>
|
||||
|
||||
<Callout.Root mb="4">
|
||||
<Callout.Icon>
|
||||
<MailWarningIcon />
|
||||
</Callout.Icon>
|
||||
<Callout.Text>Make sure the alias uses a valid domain!</Callout.Text>
|
||||
</Callout.Root>
|
||||
|
||||
<TextField.Root>
|
||||
<TextField.Slot>
|
||||
<AtSignIcon size="16" />
|
||||
</TextField.Slot>
|
||||
<TextField.Input
|
||||
placeholder={`${user.split("@")[0]}@alias.domain`}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.currentTarget.value.toLowerCase())}
|
||||
/>
|
||||
</TextField.Root>
|
||||
|
||||
<Flex gap="3" mt="4" justify="end">
|
||||
<Dialog.Close>
|
||||
<Button variant="surface">Cancel</Button>
|
||||
</Dialog.Close>
|
||||
<Dialog.Close>
|
||||
<Button
|
||||
variant="surface"
|
||||
disabled={!value.includes("@")}
|
||||
onClick={async () => {
|
||||
try {
|
||||
const alias = await createAlias(user, value);
|
||||
onCreate?.(alias);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
}}
|
||||
>Create</Button>
|
||||
</Dialog.Close>
|
||||
</Flex>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
|
@ -10,6 +10,7 @@ import { BananaIcon } from "lucide-react";
|
|||
import LoadingSpinner from "../LoadingSpinner";
|
||||
import { approveAlias, deleteAlias, fetchUserAliases } from "@/lib/actions";
|
||||
import GenericConfirmationDialog from "../GenericConfirmationDialog";
|
||||
import CreateAliasButton from "./CreateAliasButton";
|
||||
|
||||
export default function ManageUserButton({ email }: { email: string }) {
|
||||
const [aliases, setAliases] = useState<AliasEntry[] | null>(null);
|
||||
|
@ -44,7 +45,10 @@ export default function ManageUserButton({ email }: { email: string }) {
|
|||
</Card>
|
||||
|
||||
<Card className="h-fit min-w-40">
|
||||
<Heading size="3" mb="4">Aliases</Heading>
|
||||
<Flex mb="4" justify="between">
|
||||
<Heading size="3">Aliases</Heading>
|
||||
<CreateAliasButton user={email} onCreate={(alias) => setAliases([...(aliases ?? []), alias])} />
|
||||
</Flex>
|
||||
|
||||
{
|
||||
aliases
|
||||
|
|
|
@ -121,7 +121,7 @@ export function getAlias(alias: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function createAlias(user: string, alias: string, pending: boolean) {
|
||||
export function createAliasEntry(user: string, alias: string, pending: boolean) {
|
||||
return new Promise<number>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
|
|
Loading…
Reference in a new issue