Added API for TTS Username Filters
This commit is contained in:
parent
d49779e76f
commit
c3e1c1cb60
82
app/api/settings/tts/filter/users/route.ts
Normal file
82
app/api/settings/tts/filter/users/route.ts
Normal 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 });
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Calendar, Check, ChevronsUpDown, MoreHorizontal, Plus, Tags, Trash, User } from "lucide-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 { useEffect, useState } from "react";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import Link from "next/link";
|
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 { DropdownMenu, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from "@/components/ui/dropdown-menu";
|
||||||
import { DropdownMenuContent, DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
|
import { DropdownMenuContent, DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { db } from "@/lib/db";
|
||||||
|
|
||||||
const TTSFiltersPage = () => {
|
const TTSFiltersPage = () => {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
@ -30,33 +31,36 @@ const TTSFiltersPage = () => {
|
|||||||
const [moreOpen, setMoreOpen] = useState<number>(0)
|
const [moreOpen, setMoreOpen] = useState<number>(0)
|
||||||
const [tag, setTag] = useState("blacklisted")
|
const [tag, setTag] = useState("blacklisted")
|
||||||
const [open, setOpen] = useState<boolean>(false)
|
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 router = useRouter();
|
||||||
|
|
||||||
const labels = [
|
const tags = [
|
||||||
"blacklisted",
|
"blacklisted",
|
||||||
"priority"
|
"priority"
|
||||||
]
|
]
|
||||||
|
|
||||||
// Username blacklist
|
// Username blacklist
|
||||||
const usernameFilteredFormSchema = z.object({
|
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({
|
const usernameFilteredForm = useForm({
|
||||||
resolver: zodResolver(usernameFilteredFormSchema),
|
resolver: zodResolver(usernameFilteredFormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
username: ""
|
//userId: session?.user?.id ?? "",
|
||||||
|
username: "",
|
||||||
|
tag: ""
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
// const userFiltersData = (await axios.get("/api/settings/tts/filters/users")).data ?? {};
|
const userFiltersData = await axios.get("/api/settings/tts/filter/users");
|
||||||
// setApiKeys(userFiltersData)
|
setUserTag(userFiltersData.data ?? [])
|
||||||
// console.log(userFiltersData);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("ERROR", error)
|
console.log("ERROR", error)
|
||||||
}
|
}
|
||||||
@ -65,47 +69,31 @@ const TTSFiltersPage = () => {
|
|||||||
fetchData().catch(console.error);
|
fetchData().catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onApiKeyAdd = async () => {
|
const onDelete = () => {
|
||||||
///let usernames = blacklistedUsers.split("\n");
|
const username = userTags[Math.log2(moreOpen)].username
|
||||||
//console.log(usernames)
|
axios.delete("/api/settings/tts/filter/users?username=" + username)
|
||||||
// try {
|
.then(() => {
|
||||||
// await axios.post("/api/settings/tts/filters/users", {
|
setUserTag(userTags.filter((u) => u.username != username))
|
||||||
// usernames: []
|
}).catch((e) => console.error(e))
|
||||||
// });
|
|
||||||
// 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 isLoading = usernameFilteredForm.formState.isSubmitting;
|
const isLoading = usernameFilteredForm.formState.isSubmitting;
|
||||||
|
|
||||||
const addTwitchUser = (values: z.infer<typeof usernameFilteredFormSchema>) => {
|
const onAdd = (values: z.infer<typeof usernameFilteredFormSchema>) => {
|
||||||
let response = null;
|
try {
|
||||||
console.log("TEST")
|
values.tag = tag
|
||||||
console.log(values)
|
axios.post("/api/settings/tts/filter/users", values)
|
||||||
|
.then((d) => {
|
||||||
|
userTags.push({ username: values.username, tag: tag })
|
||||||
|
setUserTag(userTags)
|
||||||
|
|
||||||
// try {
|
usernameFilteredForm.reset();
|
||||||
// response = await axios.post("/api/settings/tts/filter/badges", values);
|
router.refresh();
|
||||||
// } catch (error) {
|
})
|
||||||
// console.log("[CONNECTIONS/TWITCH/POST]", error);
|
} catch (error) {
|
||||||
// return;
|
console.log("[TTS/FILTERS/USER]", error);
|
||||||
// }
|
return;
|
||||||
|
}
|
||||||
userTags.push({ username: values.username, tag: tag })
|
|
||||||
setUserTag(userTags)
|
|
||||||
usernameFilteredForm.reset();
|
|
||||||
router.refresh();
|
|
||||||
//window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 className="px-10 py-10 w-full h-full flex-grow inset-y-1/2">
|
||||||
<div>
|
<div>
|
||||||
{userTags.map((user, index) => (
|
{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">
|
<div className="flex w-full items-start justify-between rounded-md border px-2 py-3">
|
||||||
<p className="text-sm font-medium leading-none">
|
<p className="text-base font-medium">
|
||||||
<span className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
|
<span className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
|
||||||
{user.tag}
|
{user.tag}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground">{user.username}</span>
|
<span className="text-white">{user.username}</span>
|
||||||
</p>
|
</p>
|
||||||
<DropdownMenu open={(moreOpen & (1 << index)) > 0} onOpenChange={() => setMoreOpen((v) => v ^ (1 << index))}>
|
<DropdownMenu open={(moreOpen & (1 << index)) > 0} onOpenChange={() => setMoreOpen((v) => v ^ (1 << index))}>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
@ -144,17 +132,17 @@ const TTSFiltersPage = () => {
|
|||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No label found.</CommandEmpty>
|
<CommandEmpty>No label found.</CommandEmpty>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
{labels.map((label) => (
|
{tags.map((tag) => (
|
||||||
<CommandItem
|
<CommandItem
|
||||||
key={label}
|
key={tag}
|
||||||
value={label}
|
value={tag}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
userTags[index].tag = value
|
userTags[index].tag = value
|
||||||
setUserTag(userTags)
|
setUserTag(userTags)
|
||||||
setMoreOpen(0)
|
setMoreOpen(0)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{tag}
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
@ -163,10 +151,7 @@ const TTSFiltersPage = () => {
|
|||||||
</DropdownMenuSubContent>
|
</DropdownMenuSubContent>
|
||||||
</DropdownMenuSub>
|
</DropdownMenuSub>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onClick={() => {
|
<DropdownMenuItem onClick={onDelete} className="text-red-600">
|
||||||
userTags.splice(index, 1)
|
|
||||||
setUserTag(userTags)
|
|
||||||
}} className="text-red-600">
|
|
||||||
<Trash className="mr-2 h-4 w-4" />
|
<Trash className="mr-2 h-4 w-4" />
|
||||||
Delete
|
Delete
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@ -176,9 +161,9 @@ const TTSFiltersPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Form {...usernameFilteredForm}>
|
<Form {...usernameFilteredForm}>
|
||||||
<form onSubmit={usernameFilteredForm.handleSubmit(addTwitchUser)}>
|
<form onSubmit={usernameFilteredForm.handleSubmit(onAdd)}>
|
||||||
<div className="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
|
<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">
|
<Label className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
|
||||||
{tag}
|
{tag}
|
||||||
</Label>
|
</Label>
|
||||||
<FormField
|
<FormField
|
||||||
@ -219,15 +204,15 @@ const TTSFiltersPage = () => {
|
|||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No label found.</CommandEmpty>
|
<CommandEmpty>No label found.</CommandEmpty>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
{labels.map((label) => (
|
{tags.map((tag) => (
|
||||||
<CommandItem
|
<CommandItem
|
||||||
value={label}
|
value={tag}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setTag(value)
|
setTag(value)
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{tag}
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
|
@ -3,9 +3,8 @@ import { CardWrapper } from "./card-wrapper"
|
|||||||
export const LoginForm = () => {
|
export const LoginForm = () => {
|
||||||
return (
|
return (
|
||||||
<CardWrapper
|
<CardWrapper
|
||||||
headerLabel="Welcome back"
|
headerLabel="Welcome back">
|
||||||
>
|
<div></div>
|
||||||
Login Form
|
|
||||||
</CardWrapper>
|
</CardWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ const SettingsNavigation = async () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full z-20 inset-y-1/3 w-full">
|
<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">
|
<li className="text-xs text-gray-400">
|
||||||
Settings
|
Settings
|
||||||
</li>
|
</li>
|
||||||
|
@ -18,8 +18,8 @@ model User {
|
|||||||
apiKeys ApiKey[]
|
apiKeys ApiKey[]
|
||||||
accounts Account[]
|
accounts Account[]
|
||||||
twitchConnections TwitchConnection[]
|
twitchConnections TwitchConnection[]
|
||||||
createdProfiles TtsProfile[]
|
ttsUsernameFilter TtsUsernameFilter[]
|
||||||
profileStatus TtsProfileStatus[]
|
ttsWordFilter TtsWordFilter[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
@ -65,69 +65,24 @@ model TwitchConnection {
|
|||||||
@@index([userId])
|
@@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 {
|
model TtsUsernameFilter {
|
||||||
username String
|
username String
|
||||||
tag String
|
tag String
|
||||||
|
|
||||||
profileId String
|
userId String
|
||||||
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
@@index([profileId])
|
@@index([userId])
|
||||||
@@id([profileId, username])
|
@@id([userId, username])
|
||||||
}
|
}
|
||||||
|
|
||||||
model TtsWordReplacementFilter {
|
model TtsWordFilter {
|
||||||
word String
|
search String
|
||||||
replace String
|
replace String
|
||||||
|
|
||||||
profileId String
|
userId String
|
||||||
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
profile User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
@@index([profileId])
|
@@index([userId])
|
||||||
@@id([profileId, word])
|
@@id([userId, search])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user