Added API for TTS Username Filters

This commit is contained in:
Tom 2024-01-02 18:00:11 +00:00
parent d49779e76f
commit c3e1c1cb60
5 changed files with 144 additions and 123 deletions

View File

@ -0,0 +1,82 @@
import { db } from "@/lib/db"
import { NextResponse } from "next/server";
import fetchUserUsingAPI from "@/lib/validate-api";
export async function GET(req: Request) {
try {
const user = await fetchUserUsingAPI(req)
if (!user) {
return new NextResponse("Unauthorized", { status: 401 });
}
const filters = await db.ttsUsernameFilter.findMany({
where: {
userId: user.id
}
});
return NextResponse.json(filters);
} catch (error) {
console.log("[TTS/FILTER/USER]", error);
return new NextResponse("Internal Error", { status: 500 });
}
}
export async function POST(req: Request) {
try {
const user = await fetchUserUsingAPI(req)
if (!user) {
return new NextResponse("Unauthorized", { status: 401 });
}
const { username, tag } = await req.json();
const filter = await db.ttsUsernameFilter.upsert({
where: {
userId_username: {
userId: user.id as string,
username
}
},
update: {
tag
},
create: {
userId: user.id as string,
username,
tag
}
});
return NextResponse.json(filter);
} catch (error) {
console.log("[TTS/FILTER/USER]", error);
return new NextResponse("Internal Error", { status: 500 });
}
}
export async function DELETE(req: Request) {
try {
const user = await fetchUserUsingAPI(req)
if (!user) {
return new NextResponse("Unauthorized", { status: 401 });
}
const { searchParams } = new URL(req.url)
const username = searchParams.get('username') as string
const filter = await db.ttsUsernameFilter.delete({
where: {
userId_username: {
userId: user.id as string,
username
}
}
});
return NextResponse.json(filter)
} catch (error) {
console.log("[TTS/FILTER/USER]", error);
return new NextResponse("Internal Error", { status: 500 });
}
}

View File

@ -3,7 +3,7 @@
import axios from "axios";
import * as React from 'react';
import { Calendar, Check, ChevronsUpDown, MoreHorizontal, Plus, Tags, Trash, User } from "lucide-react"
import { ApiKey, TwitchConnection } from "@prisma/client";
import { ApiKey, TtsUsernameFilter, TwitchConnection } from "@prisma/client";
import { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import Link from "next/link";
@ -23,6 +23,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { DropdownMenu, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from "@/components/ui/dropdown-menu";
import { DropdownMenuContent, DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
import { Label } from "@/components/ui/label";
import { db } from "@/lib/db";
const TTSFiltersPage = () => {
const { data: session, status } = useSession();
@ -30,33 +31,36 @@ const TTSFiltersPage = () => {
const [moreOpen, setMoreOpen] = useState<number>(0)
const [tag, setTag] = useState("blacklisted")
const [open, setOpen] = useState<boolean>(false)
const [userTags, setUserTag] = useState<{ username: string, tag: string }[]>([{ username: "test", tag:"blacklisted" }, { username: "hello world", tag:"moderator" }])
const [userTags, setUserTag] = useState<{ username: string, tag: string }[]>([])
const router = useRouter();
const labels = [
const tags = [
"blacklisted",
"priority"
]
// Username blacklist
const usernameFilteredFormSchema = z.object({
username: z.string().trim().min(4).max(25).regex(new RegExp("[a-zA-Z0-9][a-zA-Z0-9_]{3, 24}"), "Must be a valid twitch username.")
//userId: z.string().trim().min(1),
username: z.string().trim().min(4).max(25), //.regex(new RegExp("[a-zA-Z0-9][a-zA-Z0-9_]{3, 24}"), "Must be a valid twitch username.")
tag: z.string().trim()
});
const usernameFilteredForm = useForm({
resolver: zodResolver(usernameFilteredFormSchema),
defaultValues: {
username: ""
//userId: session?.user?.id ?? "",
username: "",
tag: ""
}
});
useEffect(() => {
const fetchData = async () => {
try {
// const userFiltersData = (await axios.get("/api/settings/tts/filters/users")).data ?? {};
// setApiKeys(userFiltersData)
// console.log(userFiltersData);
const userFiltersData = await axios.get("/api/settings/tts/filter/users");
setUserTag(userFiltersData.data ?? [])
} catch (error) {
console.log("ERROR", error)
}
@ -65,47 +69,31 @@ const TTSFiltersPage = () => {
fetchData().catch(console.error);
}, []);
const onApiKeyAdd = async () => {
///let usernames = blacklistedUsers.split("\n");
//console.log(usernames)
// try {
// await axios.post("/api/settings/tts/filters/users", {
// usernames: []
// });
// setUserFilters(userFilters.concat(usernames))
// } catch (error) {
// console.log("ERROR", error)
// }
}
const onApiKeyDelete = async (username: string) => {
try {
await axios.delete("/api/settings/tts/filters/users/" + username);
//setUserFilters(userFilters.filter((u) => u != username))
} catch (error) {
console.log("ERROR", error)
}
const onDelete = () => {
const username = userTags[Math.log2(moreOpen)].username
axios.delete("/api/settings/tts/filter/users?username=" + username)
.then(() => {
setUserTag(userTags.filter((u) => u.username != username))
}).catch((e) => console.error(e))
}
const isLoading = usernameFilteredForm.formState.isSubmitting;
const addTwitchUser = (values: z.infer<typeof usernameFilteredFormSchema>) => {
let response = null;
console.log("TEST")
console.log(values)
const onAdd = (values: z.infer<typeof usernameFilteredFormSchema>) => {
try {
values.tag = tag
axios.post("/api/settings/tts/filter/users", values)
.then((d) => {
userTags.push({ username: values.username, tag: tag })
setUserTag(userTags)
// try {
// response = await axios.post("/api/settings/tts/filter/badges", values);
// } catch (error) {
// console.log("[CONNECTIONS/TWITCH/POST]", error);
// return;
// }
userTags.push({ username: values.username, tag: tag })
setUserTag(userTags)
usernameFilteredForm.reset();
router.refresh();
//window.location.reload();
usernameFilteredForm.reset();
router.refresh();
})
} catch (error) {
console.log("[TTS/FILTERS/USER]", error);
return;
}
}
return (
@ -114,12 +102,12 @@ const TTSFiltersPage = () => {
<div className="px-10 py-10 w-full h-full flex-grow inset-y-1/2">
<div>
{userTags.map((user, index) => (
<div className="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
<p className="text-sm font-medium leading-none">
<div className="flex w-full items-start justify-between rounded-md border px-2 py-3">
<p className="text-base font-medium">
<span className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
{user.tag}
</span>
<span className="text-muted-foreground">{user.username}</span>
<span className="text-white">{user.username}</span>
</p>
<DropdownMenu open={(moreOpen & (1 << index)) > 0} onOpenChange={() => setMoreOpen((v) => v ^ (1 << index))}>
<DropdownMenuTrigger asChild>
@ -144,17 +132,17 @@ const TTSFiltersPage = () => {
<CommandList>
<CommandEmpty>No label found.</CommandEmpty>
<CommandGroup>
{labels.map((label) => (
{tags.map((tag) => (
<CommandItem
key={label}
value={label}
key={tag}
value={tag}
onSelect={(value) => {
userTags[index].tag = value
setUserTag(userTags)
setMoreOpen(0)
}}
>
{label}
{tag}
</CommandItem>
))}
</CommandGroup>
@ -163,10 +151,7 @@ const TTSFiltersPage = () => {
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => {
userTags.splice(index, 1)
setUserTag(userTags)
}} className="text-red-600">
<DropdownMenuItem onClick={onDelete} className="text-red-600">
<Trash className="mr-2 h-4 w-4" />
Delete
</DropdownMenuItem>
@ -176,9 +161,9 @@ const TTSFiltersPage = () => {
</div>
))}
<Form {...usernameFilteredForm}>
<form onSubmit={usernameFilteredForm.handleSubmit(addTwitchUser)}>
<div className="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
<Label className=" mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
<form onSubmit={usernameFilteredForm.handleSubmit(onAdd)}>
<div className="flex w-full items-start justify-between rounded-md border px-4 py-3">
<Label className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
{tag}
</Label>
<FormField
@ -219,15 +204,15 @@ const TTSFiltersPage = () => {
<CommandList>
<CommandEmpty>No label found.</CommandEmpty>
<CommandGroup>
{labels.map((label) => (
{tags.map((tag) => (
<CommandItem
value={label}
value={tag}
onSelect={(value) => {
setTag(value)
setOpen(false)
}}
>
{label}
{tag}
</CommandItem>
))}
</CommandGroup>

View File

@ -3,9 +3,8 @@ import { CardWrapper } from "./card-wrapper"
export const LoginForm = () => {
return (
<CardWrapper
headerLabel="Welcome back"
>
Login Form
headerLabel="Welcome back">
<div></div>
</CardWrapper>
)
}

View File

@ -12,7 +12,7 @@ const SettingsNavigation = async () => {
</div>
<div className="flex h-full z-20 inset-y-1/3 w-full">
<ul className="rounded-lg shadow-md pl-[25px] flex flex-col w-full justify-between rounded-md text-center align-center">
<ul className="rounded-lg shadow-md pl-[25px] flex flex-col w-full justify-between text-center align-center">
<li className="text-xs text-gray-400">
Settings
</li>

View File

@ -18,8 +18,8 @@ model User {
apiKeys ApiKey[]
accounts Account[]
twitchConnections TwitchConnection[]
createdProfiles TtsProfile[]
profileStatus TtsProfileStatus[]
ttsUsernameFilter TtsUsernameFilter[]
ttsWordFilter TtsWordFilter[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@ -65,69 +65,24 @@ model TwitchConnection {
@@index([userId])
}
model TtsProfile {
id String @id @default(uuid())
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
statuses TtsProfileStatus[]
badgeFilters TtsBadgeFilter[]
usernameFilters TtsUsernameFilter[]
wordFilters TtsWordReplacementFilter[]
creatorId String
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
@@index([creatorId])
@@unique([creatorId, name])
}
model TtsProfileStatus {
id String @id @default(uuid())
name String
enabled Boolean
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
profileId String
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([profileId])
}
model TtsBadgeFilter {
badgeId String
profileId String
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
@@index([profileId])
@@id([profileId, badgeId])
}
model TtsUsernameFilter {
username String
tag String
profileId String
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([profileId])
@@id([profileId, username])
@@index([userId])
@@id([userId, username])
}
model TtsWordReplacementFilter {
word String
model TtsWordFilter {
search String
replace String
profileId String
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
@@index([profileId])
@@id([profileId, word])
}
userId String
profile User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@id([userId, search])
}